]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Update to iD v2.2.0
[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 function commonjsRequire () {
11         throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
12 }
13
14
15
16 function createCommonjsModule(fn, module) {
17         return module = { exports: {} }, fn(module, module.exports), module.exports;
18 }
19
20 var lodash = createCommonjsModule(function (module, exports) {
21 /**
22  * @license
23  * Lodash <https://lodash.com/>
24  * Copyright JS Foundation and other contributors <https://js.foundation/>
25  * Released under MIT license <https://lodash.com/license>
26  * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
27  * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
28  */
29 (function() {
30
31   /** Used as a safe reference for `undefined` in pre-ES5 environments. */
32   var undefined;
33
34   /** Used as the semantic version number. */
35   var VERSION = '4.17.4';
36
37   /** Used as the size to enable large array optimizations. */
38   var LARGE_ARRAY_SIZE = 200;
39
40   /** Error message constants. */
41   var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
42       FUNC_ERROR_TEXT = 'Expected a function';
43
44   /** Used to stand-in for `undefined` hash values. */
45   var HASH_UNDEFINED = '__lodash_hash_undefined__';
46
47   /** Used as the maximum memoize cache size. */
48   var MAX_MEMOIZE_SIZE = 500;
49
50   /** Used as the internal argument placeholder. */
51   var PLACEHOLDER = '__lodash_placeholder__';
52
53   /** Used to compose bitmasks for cloning. */
54   var CLONE_DEEP_FLAG = 1,
55       CLONE_FLAT_FLAG = 2,
56       CLONE_SYMBOLS_FLAG = 4;
57
58   /** Used to compose bitmasks for value comparisons. */
59   var COMPARE_PARTIAL_FLAG = 1,
60       COMPARE_UNORDERED_FLAG = 2;
61
62   /** Used to compose bitmasks for function metadata. */
63   var WRAP_BIND_FLAG = 1,
64       WRAP_BIND_KEY_FLAG = 2,
65       WRAP_CURRY_BOUND_FLAG = 4,
66       WRAP_CURRY_FLAG = 8,
67       WRAP_CURRY_RIGHT_FLAG = 16,
68       WRAP_PARTIAL_FLAG = 32,
69       WRAP_PARTIAL_RIGHT_FLAG = 64,
70       WRAP_ARY_FLAG = 128,
71       WRAP_REARG_FLAG = 256,
72       WRAP_FLIP_FLAG = 512;
73
74   /** Used as default options for `_.truncate`. */
75   var DEFAULT_TRUNC_LENGTH = 30,
76       DEFAULT_TRUNC_OMISSION = '...';
77
78   /** Used to detect hot functions by number of calls within a span of milliseconds. */
79   var HOT_COUNT = 800,
80       HOT_SPAN = 16;
81
82   /** Used to indicate the type of lazy iteratees. */
83   var LAZY_FILTER_FLAG = 1,
84       LAZY_MAP_FLAG = 2,
85       LAZY_WHILE_FLAG = 3;
86
87   /** Used as references for various `Number` constants. */
88   var INFINITY = 1 / 0,
89       MAX_SAFE_INTEGER = 9007199254740991,
90       MAX_INTEGER = 1.7976931348623157e+308,
91       NAN = 0 / 0;
92
93   /** Used as references for the maximum length and index of an array. */
94   var MAX_ARRAY_LENGTH = 4294967295,
95       MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
96       HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
97
98   /** Used to associate wrap methods with their bit flags. */
99   var wrapFlags = [
100     ['ary', WRAP_ARY_FLAG],
101     ['bind', WRAP_BIND_FLAG],
102     ['bindKey', WRAP_BIND_KEY_FLAG],
103     ['curry', WRAP_CURRY_FLAG],
104     ['curryRight', WRAP_CURRY_RIGHT_FLAG],
105     ['flip', WRAP_FLIP_FLAG],
106     ['partial', WRAP_PARTIAL_FLAG],
107     ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
108     ['rearg', WRAP_REARG_FLAG]
109   ];
110
111   /** `Object#toString` result references. */
112   var argsTag = '[object Arguments]',
113       arrayTag = '[object Array]',
114       asyncTag = '[object AsyncFunction]',
115       boolTag = '[object Boolean]',
116       dateTag = '[object Date]',
117       domExcTag = '[object DOMException]',
118       errorTag = '[object Error]',
119       funcTag = '[object Function]',
120       genTag = '[object GeneratorFunction]',
121       mapTag = '[object Map]',
122       numberTag = '[object Number]',
123       nullTag = '[object Null]',
124       objectTag = '[object Object]',
125       promiseTag = '[object Promise]',
126       proxyTag = '[object Proxy]',
127       regexpTag = '[object RegExp]',
128       setTag = '[object Set]',
129       stringTag = '[object String]',
130       symbolTag = '[object Symbol]',
131       undefinedTag = '[object Undefined]',
132       weakMapTag = '[object WeakMap]',
133       weakSetTag = '[object WeakSet]';
134
135   var arrayBufferTag = '[object ArrayBuffer]',
136       dataViewTag = '[object DataView]',
137       float32Tag = '[object Float32Array]',
138       float64Tag = '[object Float64Array]',
139       int8Tag = '[object Int8Array]',
140       int16Tag = '[object Int16Array]',
141       int32Tag = '[object Int32Array]',
142       uint8Tag = '[object Uint8Array]',
143       uint8ClampedTag = '[object Uint8ClampedArray]',
144       uint16Tag = '[object Uint16Array]',
145       uint32Tag = '[object Uint32Array]';
146
147   /** Used to match empty string literals in compiled template source. */
148   var reEmptyStringLeading = /\b__p \+= '';/g,
149       reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
150       reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
151
152   /** Used to match HTML entities and HTML characters. */
153   var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
154       reUnescapedHtml = /[&<>"']/g,
155       reHasEscapedHtml = RegExp(reEscapedHtml.source),
156       reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
157
158   /** Used to match template delimiters. */
159   var reEscape = /<%-([\s\S]+?)%>/g,
160       reEvaluate = /<%([\s\S]+?)%>/g,
161       reInterpolate = /<%=([\s\S]+?)%>/g;
162
163   /** Used to match property names within property paths. */
164   var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
165       reIsPlainProp = /^\w*$/,
166       reLeadingDot = /^\./,
167       rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
168
169   /**
170    * Used to match `RegExp`
171    * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
172    */
173   var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
174       reHasRegExpChar = RegExp(reRegExpChar.source);
175
176   /** Used to match leading and trailing whitespace. */
177   var reTrim = /^\s+|\s+$/g,
178       reTrimStart = /^\s+/,
179       reTrimEnd = /\s+$/;
180
181   /** Used to match wrap detail comments. */
182   var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
183       reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
184       reSplitDetails = /,? & /;
185
186   /** Used to match words composed of alphanumeric characters. */
187   var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
188
189   /** Used to match backslashes in property paths. */
190   var reEscapeChar = /\\(\\)?/g;
191
192   /**
193    * Used to match
194    * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
195    */
196   var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
197
198   /** Used to match `RegExp` flags from their coerced string values. */
199   var reFlags = /\w*$/;
200
201   /** Used to detect bad signed hexadecimal string values. */
202   var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
203
204   /** Used to detect binary string values. */
205   var reIsBinary = /^0b[01]+$/i;
206
207   /** Used to detect host constructors (Safari). */
208   var reIsHostCtor = /^\[object .+?Constructor\]$/;
209
210   /** Used to detect octal string values. */
211   var reIsOctal = /^0o[0-7]+$/i;
212
213   /** Used to detect unsigned integer values. */
214   var reIsUint = /^(?:0|[1-9]\d*)$/;
215
216   /** Used to match Latin Unicode letters (excluding mathematical operators). */
217   var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
218
219   /** Used to ensure capturing order of template delimiters. */
220   var reNoMatch = /($^)/;
221
222   /** Used to match unescaped characters in compiled string literals. */
223   var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
224
225   /** Used to compose unicode character classes. */
226   var rsAstralRange = '\\ud800-\\udfff',
227       rsComboMarksRange = '\\u0300-\\u036f',
228       reComboHalfMarksRange = '\\ufe20-\\ufe2f',
229       rsComboSymbolsRange = '\\u20d0-\\u20ff',
230       rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
231       rsDingbatRange = '\\u2700-\\u27bf',
232       rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
233       rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
234       rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
235       rsPunctuationRange = '\\u2000-\\u206f',
236       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',
237       rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
238       rsVarRange = '\\ufe0e\\ufe0f',
239       rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
240
241   /** Used to compose unicode capture groups. */
242   var rsApos = "['\u2019]",
243       rsAstral = '[' + rsAstralRange + ']',
244       rsBreak = '[' + rsBreakRange + ']',
245       rsCombo = '[' + rsComboRange + ']',
246       rsDigits = '\\d+',
247       rsDingbat = '[' + rsDingbatRange + ']',
248       rsLower = '[' + rsLowerRange + ']',
249       rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
250       rsFitz = '\\ud83c[\\udffb-\\udfff]',
251       rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
252       rsNonAstral = '[^' + rsAstralRange + ']',
253       rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
254       rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
255       rsUpper = '[' + rsUpperRange + ']',
256       rsZWJ = '\\u200d';
257
258   /** Used to compose unicode regexes. */
259   var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
260       rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
261       rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
262       rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
263       reOptMod = rsModifier + '?',
264       rsOptVar = '[' + rsVarRange + ']?',
265       rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
266       rsOrdLower = '\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)',
267       rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)',
268       rsSeq = rsOptVar + reOptMod + rsOptJoin,
269       rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
270       rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
271
272   /** Used to match apostrophes. */
273   var reApos = RegExp(rsApos, 'g');
274
275   /**
276    * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
277    * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
278    */
279   var reComboMark = RegExp(rsCombo, 'g');
280
281   /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
282   var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
283
284   /** Used to match complex or compound words. */
285   var reUnicodeWord = RegExp([
286     rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
287     rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
288     rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
289     rsUpper + '+' + rsOptContrUpper,
290     rsOrdUpper,
291     rsOrdLower,
292     rsDigits,
293     rsEmoji
294   ].join('|'), 'g');
295
296   /** 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/). */
297   var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange  + rsComboRange + rsVarRange + ']');
298
299   /** Used to detect strings that need a more robust regexp to match words. */
300   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 ]/;
301
302   /** Used to assign default `context` object properties. */
303   var contextProps = [
304     'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
305     'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
306     'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
307     'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
308     '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
309   ];
310
311   /** Used to make template sourceURLs easier to identify. */
312   var templateCounter = -1;
313
314   /** Used to identify `toStringTag` values of typed arrays. */
315   var typedArrayTags = {};
316   typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
317   typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
318   typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
319   typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
320   typedArrayTags[uint32Tag] = true;
321   typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
322   typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
323   typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
324   typedArrayTags[errorTag] = typedArrayTags[funcTag] =
325   typedArrayTags[mapTag] = typedArrayTags[numberTag] =
326   typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
327   typedArrayTags[setTag] = typedArrayTags[stringTag] =
328   typedArrayTags[weakMapTag] = false;
329
330   /** Used to identify `toStringTag` values supported by `_.clone`. */
331   var cloneableTags = {};
332   cloneableTags[argsTag] = cloneableTags[arrayTag] =
333   cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
334   cloneableTags[boolTag] = cloneableTags[dateTag] =
335   cloneableTags[float32Tag] = cloneableTags[float64Tag] =
336   cloneableTags[int8Tag] = cloneableTags[int16Tag] =
337   cloneableTags[int32Tag] = cloneableTags[mapTag] =
338   cloneableTags[numberTag] = cloneableTags[objectTag] =
339   cloneableTags[regexpTag] = cloneableTags[setTag] =
340   cloneableTags[stringTag] = cloneableTags[symbolTag] =
341   cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
342   cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
343   cloneableTags[errorTag] = cloneableTags[funcTag] =
344   cloneableTags[weakMapTag] = false;
345
346   /** Used to map Latin Unicode letters to basic Latin letters. */
347   var deburredLetters = {
348     // Latin-1 Supplement block.
349     '\xc0': 'A',  '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
350     '\xe0': 'a',  '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
351     '\xc7': 'C',  '\xe7': 'c',
352     '\xd0': 'D',  '\xf0': 'd',
353     '\xc8': 'E',  '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
354     '\xe8': 'e',  '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
355     '\xcc': 'I',  '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
356     '\xec': 'i',  '\xed': 'i', '\xee': 'i', '\xef': 'i',
357     '\xd1': 'N',  '\xf1': 'n',
358     '\xd2': 'O',  '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
359     '\xf2': 'o',  '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
360     '\xd9': 'U',  '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
361     '\xf9': 'u',  '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
362     '\xdd': 'Y',  '\xfd': 'y', '\xff': 'y',
363     '\xc6': 'Ae', '\xe6': 'ae',
364     '\xde': 'Th', '\xfe': 'th',
365     '\xdf': 'ss',
366     // Latin Extended-A block.
367     '\u0100': 'A',  '\u0102': 'A', '\u0104': 'A',
368     '\u0101': 'a',  '\u0103': 'a', '\u0105': 'a',
369     '\u0106': 'C',  '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
370     '\u0107': 'c',  '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
371     '\u010e': 'D',  '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
372     '\u0112': 'E',  '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
373     '\u0113': 'e',  '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
374     '\u011c': 'G',  '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
375     '\u011d': 'g',  '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
376     '\u0124': 'H',  '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
377     '\u0128': 'I',  '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
378     '\u0129': 'i',  '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
379     '\u0134': 'J',  '\u0135': 'j',
380     '\u0136': 'K',  '\u0137': 'k', '\u0138': 'k',
381     '\u0139': 'L',  '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
382     '\u013a': 'l',  '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
383     '\u0143': 'N',  '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
384     '\u0144': 'n',  '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
385     '\u014c': 'O',  '\u014e': 'O', '\u0150': 'O',
386     '\u014d': 'o',  '\u014f': 'o', '\u0151': 'o',
387     '\u0154': 'R',  '\u0156': 'R', '\u0158': 'R',
388     '\u0155': 'r',  '\u0157': 'r', '\u0159': 'r',
389     '\u015a': 'S',  '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
390     '\u015b': 's',  '\u015d': 's', '\u015f': 's', '\u0161': 's',
391     '\u0162': 'T',  '\u0164': 'T', '\u0166': 'T',
392     '\u0163': 't',  '\u0165': 't', '\u0167': 't',
393     '\u0168': 'U',  '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
394     '\u0169': 'u',  '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
395     '\u0174': 'W',  '\u0175': 'w',
396     '\u0176': 'Y',  '\u0177': 'y', '\u0178': 'Y',
397     '\u0179': 'Z',  '\u017b': 'Z', '\u017d': 'Z',
398     '\u017a': 'z',  '\u017c': 'z', '\u017e': 'z',
399     '\u0132': 'IJ', '\u0133': 'ij',
400     '\u0152': 'Oe', '\u0153': 'oe',
401     '\u0149': "'n", '\u017f': 's'
402   };
403
404   /** Used to map characters to HTML entities. */
405   var htmlEscapes = {
406     '&': '&amp;',
407     '<': '&lt;',
408     '>': '&gt;',
409     '"': '&quot;',
410     "'": '&#39;'
411   };
412
413   /** Used to map HTML entities to characters. */
414   var htmlUnescapes = {
415     '&amp;': '&',
416     '&lt;': '<',
417     '&gt;': '>',
418     '&quot;': '"',
419     '&#39;': "'"
420   };
421
422   /** Used to escape characters for inclusion in compiled string literals. */
423   var stringEscapes = {
424     '\\': '\\',
425     "'": "'",
426     '\n': 'n',
427     '\r': 'r',
428     '\u2028': 'u2028',
429     '\u2029': 'u2029'
430   };
431
432   /** Built-in method references without a dependency on `root`. */
433   var freeParseFloat = parseFloat,
434       freeParseInt = parseInt;
435
436   /** Detect free variable `global` from Node.js. */
437   var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
438
439   /** Detect free variable `self`. */
440   var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
441
442   /** Used as a reference to the global object. */
443   var root = freeGlobal || freeSelf || Function('return this')();
444
445   /** Detect free variable `exports`. */
446   var freeExports = 'object' == 'object' && exports && !exports.nodeType && exports;
447
448   /** Detect free variable `module`. */
449   var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module;
450
451   /** Detect the popular CommonJS extension `module.exports`. */
452   var moduleExports = freeModule && freeModule.exports === freeExports;
453
454   /** Detect free variable `process` from Node.js. */
455   var freeProcess = moduleExports && freeGlobal.process;
456
457   /** Used to access faster Node.js helpers. */
458   var nodeUtil = (function() {
459     try {
460       return freeProcess && freeProcess.binding && freeProcess.binding('util');
461     } catch (e) {}
462   }());
463
464   /* Node.js helper references. */
465   var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
466       nodeIsDate = nodeUtil && nodeUtil.isDate,
467       nodeIsMap = nodeUtil && nodeUtil.isMap,
468       nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
469       nodeIsSet = nodeUtil && nodeUtil.isSet,
470       nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
471
472   /*--------------------------------------------------------------------------*/
473
474   /**
475    * Adds the key-value `pair` to `map`.
476    *
477    * @private
478    * @param {Object} map The map to modify.
479    * @param {Array} pair The key-value pair to add.
480    * @returns {Object} Returns `map`.
481    */
482   function addMapEntry(map, pair) {
483     // Don't return `map.set` because it's not chainable in IE 11.
484     map.set(pair[0], pair[1]);
485     return map;
486   }
487
488   /**
489    * Adds `value` to `set`.
490    *
491    * @private
492    * @param {Object} set The set to modify.
493    * @param {*} value The value to add.
494    * @returns {Object} Returns `set`.
495    */
496   function addSetEntry(set, value) {
497     // Don't return `set.add` because it's not chainable in IE 11.
498     set.add(value);
499     return set;
500   }
501
502   /**
503    * A faster alternative to `Function#apply`, this function invokes `func`
504    * with the `this` binding of `thisArg` and the arguments of `args`.
505    *
506    * @private
507    * @param {Function} func The function to invoke.
508    * @param {*} thisArg The `this` binding of `func`.
509    * @param {Array} args The arguments to invoke `func` with.
510    * @returns {*} Returns the result of `func`.
511    */
512   function apply(func, thisArg, args) {
513     switch (args.length) {
514       case 0: return func.call(thisArg);
515       case 1: return func.call(thisArg, args[0]);
516       case 2: return func.call(thisArg, args[0], args[1]);
517       case 3: return func.call(thisArg, args[0], args[1], args[2]);
518     }
519     return func.apply(thisArg, args);
520   }
521
522   /**
523    * A specialized version of `baseAggregator` for arrays.
524    *
525    * @private
526    * @param {Array} [array] The array to iterate over.
527    * @param {Function} setter The function to set `accumulator` values.
528    * @param {Function} iteratee The iteratee to transform keys.
529    * @param {Object} accumulator The initial aggregated object.
530    * @returns {Function} Returns `accumulator`.
531    */
532   function arrayAggregator(array, setter, iteratee, accumulator) {
533     var index = -1,
534         length = array == null ? 0 : array.length;
535
536     while (++index < length) {
537       var value = array[index];
538       setter(accumulator, value, iteratee(value), array);
539     }
540     return accumulator;
541   }
542
543   /**
544    * A specialized version of `_.forEach` for arrays without support for
545    * iteratee shorthands.
546    *
547    * @private
548    * @param {Array} [array] The array to iterate over.
549    * @param {Function} iteratee The function invoked per iteration.
550    * @returns {Array} Returns `array`.
551    */
552   function arrayEach(array, iteratee) {
553     var index = -1,
554         length = array == null ? 0 : array.length;
555
556     while (++index < length) {
557       if (iteratee(array[index], index, array) === false) {
558         break;
559       }
560     }
561     return array;
562   }
563
564   /**
565    * A specialized version of `_.forEachRight` for arrays without support for
566    * iteratee shorthands.
567    *
568    * @private
569    * @param {Array} [array] The array to iterate over.
570    * @param {Function} iteratee The function invoked per iteration.
571    * @returns {Array} Returns `array`.
572    */
573   function arrayEachRight(array, iteratee) {
574     var length = array == null ? 0 : array.length;
575
576     while (length--) {
577       if (iteratee(array[length], length, array) === false) {
578         break;
579       }
580     }
581     return array;
582   }
583
584   /**
585    * A specialized version of `_.every` for arrays without support for
586    * iteratee shorthands.
587    *
588    * @private
589    * @param {Array} [array] The array to iterate over.
590    * @param {Function} predicate The function invoked per iteration.
591    * @returns {boolean} Returns `true` if all elements pass the predicate check,
592    *  else `false`.
593    */
594   function arrayEvery(array, predicate) {
595     var index = -1,
596         length = array == null ? 0 : array.length;
597
598     while (++index < length) {
599       if (!predicate(array[index], index, array)) {
600         return false;
601       }
602     }
603     return true;
604   }
605
606   /**
607    * A specialized version of `_.filter` for arrays without support for
608    * iteratee shorthands.
609    *
610    * @private
611    * @param {Array} [array] The array to iterate over.
612    * @param {Function} predicate The function invoked per iteration.
613    * @returns {Array} Returns the new filtered array.
614    */
615   function arrayFilter(array, predicate) {
616     var index = -1,
617         length = array == null ? 0 : array.length,
618         resIndex = 0,
619         result = [];
620
621     while (++index < length) {
622       var value = array[index];
623       if (predicate(value, index, array)) {
624         result[resIndex++] = value;
625       }
626     }
627     return result;
628   }
629
630   /**
631    * A specialized version of `_.includes` for arrays without support for
632    * specifying an index to search from.
633    *
634    * @private
635    * @param {Array} [array] The array to inspect.
636    * @param {*} target The value to search for.
637    * @returns {boolean} Returns `true` if `target` is found, else `false`.
638    */
639   function arrayIncludes(array, value) {
640     var length = array == null ? 0 : array.length;
641     return !!length && baseIndexOf(array, value, 0) > -1;
642   }
643
644   /**
645    * This function is like `arrayIncludes` except that it accepts a comparator.
646    *
647    * @private
648    * @param {Array} [array] The array to inspect.
649    * @param {*} target The value to search for.
650    * @param {Function} comparator The comparator invoked per element.
651    * @returns {boolean} Returns `true` if `target` is found, else `false`.
652    */
653   function arrayIncludesWith(array, value, comparator) {
654     var index = -1,
655         length = array == null ? 0 : array.length;
656
657     while (++index < length) {
658       if (comparator(value, array[index])) {
659         return true;
660       }
661     }
662     return false;
663   }
664
665   /**
666    * A specialized version of `_.map` for arrays without support for iteratee
667    * shorthands.
668    *
669    * @private
670    * @param {Array} [array] The array to iterate over.
671    * @param {Function} iteratee The function invoked per iteration.
672    * @returns {Array} Returns the new mapped array.
673    */
674   function arrayMap(array, iteratee) {
675     var index = -1,
676         length = array == null ? 0 : array.length,
677         result = Array(length);
678
679     while (++index < length) {
680       result[index] = iteratee(array[index], index, array);
681     }
682     return result;
683   }
684
685   /**
686    * Appends the elements of `values` to `array`.
687    *
688    * @private
689    * @param {Array} array The array to modify.
690    * @param {Array} values The values to append.
691    * @returns {Array} Returns `array`.
692    */
693   function arrayPush(array, values) {
694     var index = -1,
695         length = values.length,
696         offset = array.length;
697
698     while (++index < length) {
699       array[offset + index] = values[index];
700     }
701     return array;
702   }
703
704   /**
705    * A specialized version of `_.reduce` for arrays without support for
706    * iteratee shorthands.
707    *
708    * @private
709    * @param {Array} [array] The array to iterate over.
710    * @param {Function} iteratee The function invoked per iteration.
711    * @param {*} [accumulator] The initial value.
712    * @param {boolean} [initAccum] Specify using the first element of `array` as
713    *  the initial value.
714    * @returns {*} Returns the accumulated value.
715    */
716   function arrayReduce(array, iteratee, accumulator, initAccum) {
717     var index = -1,
718         length = array == null ? 0 : array.length;
719
720     if (initAccum && length) {
721       accumulator = array[++index];
722     }
723     while (++index < length) {
724       accumulator = iteratee(accumulator, array[index], index, array);
725     }
726     return accumulator;
727   }
728
729   /**
730    * A specialized version of `_.reduceRight` for arrays without support for
731    * iteratee shorthands.
732    *
733    * @private
734    * @param {Array} [array] The array to iterate over.
735    * @param {Function} iteratee The function invoked per iteration.
736    * @param {*} [accumulator] The initial value.
737    * @param {boolean} [initAccum] Specify using the last element of `array` as
738    *  the initial value.
739    * @returns {*} Returns the accumulated value.
740    */
741   function arrayReduceRight(array, iteratee, accumulator, initAccum) {
742     var length = array == null ? 0 : array.length;
743     if (initAccum && length) {
744       accumulator = array[--length];
745     }
746     while (length--) {
747       accumulator = iteratee(accumulator, array[length], length, array);
748     }
749     return accumulator;
750   }
751
752   /**
753    * A specialized version of `_.some` for arrays without support for iteratee
754    * shorthands.
755    *
756    * @private
757    * @param {Array} [array] The array to iterate over.
758    * @param {Function} predicate The function invoked per iteration.
759    * @returns {boolean} Returns `true` if any element passes the predicate check,
760    *  else `false`.
761    */
762   function arraySome(array, predicate) {
763     var index = -1,
764         length = array == null ? 0 : array.length;
765
766     while (++index < length) {
767       if (predicate(array[index], index, array)) {
768         return true;
769       }
770     }
771     return false;
772   }
773
774   /**
775    * Gets the size of an ASCII `string`.
776    *
777    * @private
778    * @param {string} string The string inspect.
779    * @returns {number} Returns the string size.
780    */
781   var asciiSize = baseProperty('length');
782
783   /**
784    * Converts an ASCII `string` to an array.
785    *
786    * @private
787    * @param {string} string The string to convert.
788    * @returns {Array} Returns the converted array.
789    */
790   function asciiToArray(string) {
791     return string.split('');
792   }
793
794   /**
795    * Splits an ASCII `string` into an array of its words.
796    *
797    * @private
798    * @param {string} The string to inspect.
799    * @returns {Array} Returns the words of `string`.
800    */
801   function asciiWords(string) {
802     return string.match(reAsciiWord) || [];
803   }
804
805   /**
806    * The base implementation of methods like `_.findKey` and `_.findLastKey`,
807    * without support for iteratee shorthands, which iterates over `collection`
808    * using `eachFunc`.
809    *
810    * @private
811    * @param {Array|Object} collection The collection to inspect.
812    * @param {Function} predicate The function invoked per iteration.
813    * @param {Function} eachFunc The function to iterate over `collection`.
814    * @returns {*} Returns the found element or its key, else `undefined`.
815    */
816   function baseFindKey(collection, predicate, eachFunc) {
817     var result;
818     eachFunc(collection, function(value, key, collection) {
819       if (predicate(value, key, collection)) {
820         result = key;
821         return false;
822       }
823     });
824     return result;
825   }
826
827   /**
828    * The base implementation of `_.findIndex` and `_.findLastIndex` without
829    * support for iteratee shorthands.
830    *
831    * @private
832    * @param {Array} array The array to inspect.
833    * @param {Function} predicate The function invoked per iteration.
834    * @param {number} fromIndex The index to search from.
835    * @param {boolean} [fromRight] Specify iterating from right to left.
836    * @returns {number} Returns the index of the matched value, else `-1`.
837    */
838   function baseFindIndex(array, predicate, fromIndex, fromRight) {
839     var length = array.length,
840         index = fromIndex + (fromRight ? 1 : -1);
841
842     while ((fromRight ? index-- : ++index < length)) {
843       if (predicate(array[index], index, array)) {
844         return index;
845       }
846     }
847     return -1;
848   }
849
850   /**
851    * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
852    *
853    * @private
854    * @param {Array} array The array to inspect.
855    * @param {*} value The value to search for.
856    * @param {number} fromIndex The index to search from.
857    * @returns {number} Returns the index of the matched value, else `-1`.
858    */
859   function baseIndexOf(array, value, fromIndex) {
860     return value === value
861       ? strictIndexOf(array, value, fromIndex)
862       : baseFindIndex(array, baseIsNaN, fromIndex);
863   }
864
865   /**
866    * This function is like `baseIndexOf` except that it accepts a comparator.
867    *
868    * @private
869    * @param {Array} array The array to inspect.
870    * @param {*} value The value to search for.
871    * @param {number} fromIndex The index to search from.
872    * @param {Function} comparator The comparator invoked per element.
873    * @returns {number} Returns the index of the matched value, else `-1`.
874    */
875   function baseIndexOfWith(array, value, fromIndex, comparator) {
876     var index = fromIndex - 1,
877         length = array.length;
878
879     while (++index < length) {
880       if (comparator(array[index], value)) {
881         return index;
882       }
883     }
884     return -1;
885   }
886
887   /**
888    * The base implementation of `_.isNaN` without support for number objects.
889    *
890    * @private
891    * @param {*} value The value to check.
892    * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
893    */
894   function baseIsNaN(value) {
895     return value !== value;
896   }
897
898   /**
899    * The base implementation of `_.mean` and `_.meanBy` without support for
900    * iteratee shorthands.
901    *
902    * @private
903    * @param {Array} array The array to iterate over.
904    * @param {Function} iteratee The function invoked per iteration.
905    * @returns {number} Returns the mean.
906    */
907   function baseMean(array, iteratee) {
908     var length = array == null ? 0 : array.length;
909     return length ? (baseSum(array, iteratee) / length) : NAN;
910   }
911
912   /**
913    * The base implementation of `_.property` without support for deep paths.
914    *
915    * @private
916    * @param {string} key The key of the property to get.
917    * @returns {Function} Returns the new accessor function.
918    */
919   function baseProperty(key) {
920     return function(object) {
921       return object == null ? undefined : object[key];
922     };
923   }
924
925   /**
926    * The base implementation of `_.propertyOf` without support for deep paths.
927    *
928    * @private
929    * @param {Object} object The object to query.
930    * @returns {Function} Returns the new accessor function.
931    */
932   function basePropertyOf(object) {
933     return function(key) {
934       return object == null ? undefined : object[key];
935     };
936   }
937
938   /**
939    * The base implementation of `_.reduce` and `_.reduceRight`, without support
940    * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
941    *
942    * @private
943    * @param {Array|Object} collection The collection to iterate over.
944    * @param {Function} iteratee The function invoked per iteration.
945    * @param {*} accumulator The initial value.
946    * @param {boolean} initAccum Specify using the first or last element of
947    *  `collection` as the initial value.
948    * @param {Function} eachFunc The function to iterate over `collection`.
949    * @returns {*} Returns the accumulated value.
950    */
951   function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
952     eachFunc(collection, function(value, index, collection) {
953       accumulator = initAccum
954         ? (initAccum = false, value)
955         : iteratee(accumulator, value, index, collection);
956     });
957     return accumulator;
958   }
959
960   /**
961    * The base implementation of `_.sortBy` which uses `comparer` to define the
962    * sort order of `array` and replaces criteria objects with their corresponding
963    * values.
964    *
965    * @private
966    * @param {Array} array The array to sort.
967    * @param {Function} comparer The function to define sort order.
968    * @returns {Array} Returns `array`.
969    */
970   function baseSortBy(array, comparer) {
971     var length = array.length;
972
973     array.sort(comparer);
974     while (length--) {
975       array[length] = array[length].value;
976     }
977     return array;
978   }
979
980   /**
981    * The base implementation of `_.sum` and `_.sumBy` without support for
982    * iteratee shorthands.
983    *
984    * @private
985    * @param {Array} array The array to iterate over.
986    * @param {Function} iteratee The function invoked per iteration.
987    * @returns {number} Returns the sum.
988    */
989   function baseSum(array, iteratee) {
990     var result,
991         index = -1,
992         length = array.length;
993
994     while (++index < length) {
995       var current = iteratee(array[index]);
996       if (current !== undefined) {
997         result = result === undefined ? current : (result + current);
998       }
999     }
1000     return result;
1001   }
1002
1003   /**
1004    * The base implementation of `_.times` without support for iteratee shorthands
1005    * or max array length checks.
1006    *
1007    * @private
1008    * @param {number} n The number of times to invoke `iteratee`.
1009    * @param {Function} iteratee The function invoked per iteration.
1010    * @returns {Array} Returns the array of results.
1011    */
1012   function baseTimes(n, iteratee) {
1013     var index = -1,
1014         result = Array(n);
1015
1016     while (++index < n) {
1017       result[index] = iteratee(index);
1018     }
1019     return result;
1020   }
1021
1022   /**
1023    * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
1024    * of key-value pairs for `object` corresponding to the property names of `props`.
1025    *
1026    * @private
1027    * @param {Object} object The object to query.
1028    * @param {Array} props The property names to get values for.
1029    * @returns {Object} Returns the key-value pairs.
1030    */
1031   function baseToPairs(object, props) {
1032     return arrayMap(props, function(key) {
1033       return [key, object[key]];
1034     });
1035   }
1036
1037   /**
1038    * The base implementation of `_.unary` without support for storing metadata.
1039    *
1040    * @private
1041    * @param {Function} func The function to cap arguments for.
1042    * @returns {Function} Returns the new capped function.
1043    */
1044   function baseUnary(func) {
1045     return function(value) {
1046       return func(value);
1047     };
1048   }
1049
1050   /**
1051    * The base implementation of `_.values` and `_.valuesIn` which creates an
1052    * array of `object` property values corresponding to the property names
1053    * of `props`.
1054    *
1055    * @private
1056    * @param {Object} object The object to query.
1057    * @param {Array} props The property names to get values for.
1058    * @returns {Object} Returns the array of property values.
1059    */
1060   function baseValues(object, props) {
1061     return arrayMap(props, function(key) {
1062       return object[key];
1063     });
1064   }
1065
1066   /**
1067    * Checks if a `cache` value for `key` exists.
1068    *
1069    * @private
1070    * @param {Object} cache The cache to query.
1071    * @param {string} key The key of the entry to check.
1072    * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
1073    */
1074   function cacheHas(cache, key) {
1075     return cache.has(key);
1076   }
1077
1078   /**
1079    * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
1080    * that is not found in the character symbols.
1081    *
1082    * @private
1083    * @param {Array} strSymbols The string symbols to inspect.
1084    * @param {Array} chrSymbols The character symbols to find.
1085    * @returns {number} Returns the index of the first unmatched string symbol.
1086    */
1087   function charsStartIndex(strSymbols, chrSymbols) {
1088     var index = -1,
1089         length = strSymbols.length;
1090
1091     while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
1092     return index;
1093   }
1094
1095   /**
1096    * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
1097    * that is not found in the character symbols.
1098    *
1099    * @private
1100    * @param {Array} strSymbols The string symbols to inspect.
1101    * @param {Array} chrSymbols The character symbols to find.
1102    * @returns {number} Returns the index of the last unmatched string symbol.
1103    */
1104   function charsEndIndex(strSymbols, chrSymbols) {
1105     var index = strSymbols.length;
1106
1107     while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
1108     return index;
1109   }
1110
1111   /**
1112    * Gets the number of `placeholder` occurrences in `array`.
1113    *
1114    * @private
1115    * @param {Array} array The array to inspect.
1116    * @param {*} placeholder The placeholder to search for.
1117    * @returns {number} Returns the placeholder count.
1118    */
1119   function countHolders(array, placeholder) {
1120     var length = array.length,
1121         result = 0;
1122
1123     while (length--) {
1124       if (array[length] === placeholder) {
1125         ++result;
1126       }
1127     }
1128     return result;
1129   }
1130
1131   /**
1132    * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
1133    * letters to basic Latin letters.
1134    *
1135    * @private
1136    * @param {string} letter The matched letter to deburr.
1137    * @returns {string} Returns the deburred letter.
1138    */
1139   var deburrLetter = basePropertyOf(deburredLetters);
1140
1141   /**
1142    * Used by `_.escape` to convert characters to HTML entities.
1143    *
1144    * @private
1145    * @param {string} chr The matched character to escape.
1146    * @returns {string} Returns the escaped character.
1147    */
1148   var escapeHtmlChar = basePropertyOf(htmlEscapes);
1149
1150   /**
1151    * Used by `_.template` to escape characters for inclusion in compiled string literals.
1152    *
1153    * @private
1154    * @param {string} chr The matched character to escape.
1155    * @returns {string} Returns the escaped character.
1156    */
1157   function escapeStringChar(chr) {
1158     return '\\' + stringEscapes[chr];
1159   }
1160
1161   /**
1162    * Gets the value at `key` of `object`.
1163    *
1164    * @private
1165    * @param {Object} [object] The object to query.
1166    * @param {string} key The key of the property to get.
1167    * @returns {*} Returns the property value.
1168    */
1169   function getValue(object, key) {
1170     return object == null ? undefined : object[key];
1171   }
1172
1173   /**
1174    * Checks if `string` contains Unicode symbols.
1175    *
1176    * @private
1177    * @param {string} string The string to inspect.
1178    * @returns {boolean} Returns `true` if a symbol is found, else `false`.
1179    */
1180   function hasUnicode(string) {
1181     return reHasUnicode.test(string);
1182   }
1183
1184   /**
1185    * Checks if `string` contains a word composed of Unicode symbols.
1186    *
1187    * @private
1188    * @param {string} string The string to inspect.
1189    * @returns {boolean} Returns `true` if a word is found, else `false`.
1190    */
1191   function hasUnicodeWord(string) {
1192     return reHasUnicodeWord.test(string);
1193   }
1194
1195   /**
1196    * Converts `iterator` to an array.
1197    *
1198    * @private
1199    * @param {Object} iterator The iterator to convert.
1200    * @returns {Array} Returns the converted array.
1201    */
1202   function iteratorToArray(iterator) {
1203     var data,
1204         result = [];
1205
1206     while (!(data = iterator.next()).done) {
1207       result.push(data.value);
1208     }
1209     return result;
1210   }
1211
1212   /**
1213    * Converts `map` to its key-value pairs.
1214    *
1215    * @private
1216    * @param {Object} map The map to convert.
1217    * @returns {Array} Returns the key-value pairs.
1218    */
1219   function mapToArray(map) {
1220     var index = -1,
1221         result = Array(map.size);
1222
1223     map.forEach(function(value, key) {
1224       result[++index] = [key, value];
1225     });
1226     return result;
1227   }
1228
1229   /**
1230    * Creates a unary function that invokes `func` with its argument transformed.
1231    *
1232    * @private
1233    * @param {Function} func The function to wrap.
1234    * @param {Function} transform The argument transform.
1235    * @returns {Function} Returns the new function.
1236    */
1237   function overArg(func, transform) {
1238     return function(arg) {
1239       return func(transform(arg));
1240     };
1241   }
1242
1243   /**
1244    * Replaces all `placeholder` elements in `array` with an internal placeholder
1245    * and returns an array of their indexes.
1246    *
1247    * @private
1248    * @param {Array} array The array to modify.
1249    * @param {*} placeholder The placeholder to replace.
1250    * @returns {Array} Returns the new array of placeholder indexes.
1251    */
1252   function replaceHolders(array, placeholder) {
1253     var index = -1,
1254         length = array.length,
1255         resIndex = 0,
1256         result = [];
1257
1258     while (++index < length) {
1259       var value = array[index];
1260       if (value === placeholder || value === PLACEHOLDER) {
1261         array[index] = PLACEHOLDER;
1262         result[resIndex++] = index;
1263       }
1264     }
1265     return result;
1266   }
1267
1268   /**
1269    * Converts `set` to an array of its values.
1270    *
1271    * @private
1272    * @param {Object} set The set to convert.
1273    * @returns {Array} Returns the values.
1274    */
1275   function setToArray(set) {
1276     var index = -1,
1277         result = Array(set.size);
1278
1279     set.forEach(function(value) {
1280       result[++index] = value;
1281     });
1282     return result;
1283   }
1284
1285   /**
1286    * Converts `set` to its value-value pairs.
1287    *
1288    * @private
1289    * @param {Object} set The set to convert.
1290    * @returns {Array} Returns the value-value pairs.
1291    */
1292   function setToPairs(set) {
1293     var index = -1,
1294         result = Array(set.size);
1295
1296     set.forEach(function(value) {
1297       result[++index] = [value, value];
1298     });
1299     return result;
1300   }
1301
1302   /**
1303    * A specialized version of `_.indexOf` which performs strict equality
1304    * comparisons of values, i.e. `===`.
1305    *
1306    * @private
1307    * @param {Array} array The array to inspect.
1308    * @param {*} value The value to search for.
1309    * @param {number} fromIndex The index to search from.
1310    * @returns {number} Returns the index of the matched value, else `-1`.
1311    */
1312   function strictIndexOf(array, value, fromIndex) {
1313     var index = fromIndex - 1,
1314         length = array.length;
1315
1316     while (++index < length) {
1317       if (array[index] === value) {
1318         return index;
1319       }
1320     }
1321     return -1;
1322   }
1323
1324   /**
1325    * A specialized version of `_.lastIndexOf` which performs strict equality
1326    * comparisons of values, i.e. `===`.
1327    *
1328    * @private
1329    * @param {Array} array The array to inspect.
1330    * @param {*} value The value to search for.
1331    * @param {number} fromIndex The index to search from.
1332    * @returns {number} Returns the index of the matched value, else `-1`.
1333    */
1334   function strictLastIndexOf(array, value, fromIndex) {
1335     var index = fromIndex + 1;
1336     while (index--) {
1337       if (array[index] === value) {
1338         return index;
1339       }
1340     }
1341     return index;
1342   }
1343
1344   /**
1345    * Gets the number of symbols in `string`.
1346    *
1347    * @private
1348    * @param {string} string The string to inspect.
1349    * @returns {number} Returns the string size.
1350    */
1351   function stringSize(string) {
1352     return hasUnicode(string)
1353       ? unicodeSize(string)
1354       : asciiSize(string);
1355   }
1356
1357   /**
1358    * Converts `string` to an array.
1359    *
1360    * @private
1361    * @param {string} string The string to convert.
1362    * @returns {Array} Returns the converted array.
1363    */
1364   function stringToArray(string) {
1365     return hasUnicode(string)
1366       ? unicodeToArray(string)
1367       : asciiToArray(string);
1368   }
1369
1370   /**
1371    * Used by `_.unescape` to convert HTML entities to characters.
1372    *
1373    * @private
1374    * @param {string} chr The matched character to unescape.
1375    * @returns {string} Returns the unescaped character.
1376    */
1377   var unescapeHtmlChar = basePropertyOf(htmlUnescapes);
1378
1379   /**
1380    * Gets the size of a Unicode `string`.
1381    *
1382    * @private
1383    * @param {string} string The string inspect.
1384    * @returns {number} Returns the string size.
1385    */
1386   function unicodeSize(string) {
1387     var result = reUnicode.lastIndex = 0;
1388     while (reUnicode.test(string)) {
1389       ++result;
1390     }
1391     return result;
1392   }
1393
1394   /**
1395    * Converts a Unicode `string` to an array.
1396    *
1397    * @private
1398    * @param {string} string The string to convert.
1399    * @returns {Array} Returns the converted array.
1400    */
1401   function unicodeToArray(string) {
1402     return string.match(reUnicode) || [];
1403   }
1404
1405   /**
1406    * Splits a Unicode `string` into an array of its words.
1407    *
1408    * @private
1409    * @param {string} The string to inspect.
1410    * @returns {Array} Returns the words of `string`.
1411    */
1412   function unicodeWords(string) {
1413     return string.match(reUnicodeWord) || [];
1414   }
1415
1416   /*--------------------------------------------------------------------------*/
1417
1418   /**
1419    * Create a new pristine `lodash` function using the `context` object.
1420    *
1421    * @static
1422    * @memberOf _
1423    * @since 1.1.0
1424    * @category Util
1425    * @param {Object} [context=root] The context object.
1426    * @returns {Function} Returns a new `lodash` function.
1427    * @example
1428    *
1429    * _.mixin({ 'foo': _.constant('foo') });
1430    *
1431    * var lodash = _.runInContext();
1432    * lodash.mixin({ 'bar': lodash.constant('bar') });
1433    *
1434    * _.isFunction(_.foo);
1435    * // => true
1436    * _.isFunction(_.bar);
1437    * // => false
1438    *
1439    * lodash.isFunction(lodash.foo);
1440    * // => false
1441    * lodash.isFunction(lodash.bar);
1442    * // => true
1443    *
1444    * // Create a suped-up `defer` in Node.js.
1445    * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
1446    */
1447   var runInContext = (function runInContext(context) {
1448     context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));
1449
1450     /** Built-in constructor references. */
1451     var Array = context.Array,
1452         Date = context.Date,
1453         Error = context.Error,
1454         Function = context.Function,
1455         Math = context.Math,
1456         Object = context.Object,
1457         RegExp = context.RegExp,
1458         String = context.String,
1459         TypeError = context.TypeError;
1460
1461     /** Used for built-in method references. */
1462     var arrayProto = Array.prototype,
1463         funcProto = Function.prototype,
1464         objectProto = Object.prototype;
1465
1466     /** Used to detect overreaching core-js shims. */
1467     var coreJsData = context['__core-js_shared__'];
1468
1469     /** Used to resolve the decompiled source of functions. */
1470     var funcToString = funcProto.toString;
1471
1472     /** Used to check objects for own properties. */
1473     var hasOwnProperty = objectProto.hasOwnProperty;
1474
1475     /** Used to generate unique IDs. */
1476     var idCounter = 0;
1477
1478     /** Used to detect methods masquerading as native. */
1479     var maskSrcKey = (function() {
1480       var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
1481       return uid ? ('Symbol(src)_1.' + uid) : '';
1482     }());
1483
1484     /**
1485      * Used to resolve the
1486      * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
1487      * of values.
1488      */
1489     var nativeObjectToString = objectProto.toString;
1490
1491     /** Used to infer the `Object` constructor. */
1492     var objectCtorString = funcToString.call(Object);
1493
1494     /** Used to restore the original `_` reference in `_.noConflict`. */
1495     var oldDash = root._;
1496
1497     /** Used to detect if a method is native. */
1498     var reIsNative = RegExp('^' +
1499       funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
1500       .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
1501     );
1502
1503     /** Built-in value references. */
1504     var Buffer = moduleExports ? context.Buffer : undefined,
1505         Symbol = context.Symbol,
1506         Uint8Array = context.Uint8Array,
1507         allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
1508         getPrototype = overArg(Object.getPrototypeOf, Object),
1509         objectCreate = Object.create,
1510         propertyIsEnumerable = objectProto.propertyIsEnumerable,
1511         splice = arrayProto.splice,
1512         spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
1513         symIterator = Symbol ? Symbol.iterator : undefined,
1514         symToStringTag = Symbol ? Symbol.toStringTag : undefined;
1515
1516     var defineProperty = (function() {
1517       try {
1518         var func = getNative(Object, 'defineProperty');
1519         func({}, '', {});
1520         return func;
1521       } catch (e) {}
1522     }());
1523
1524     /** Mocked built-ins. */
1525     var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
1526         ctxNow = Date && Date.now !== root.Date.now && Date.now,
1527         ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;
1528
1529     /* Built-in method references for those with the same name as other `lodash` methods. */
1530     var nativeCeil = Math.ceil,
1531         nativeFloor = Math.floor,
1532         nativeGetSymbols = Object.getOwnPropertySymbols,
1533         nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
1534         nativeIsFinite = context.isFinite,
1535         nativeJoin = arrayProto.join,
1536         nativeKeys = overArg(Object.keys, Object),
1537         nativeMax = Math.max,
1538         nativeMin = Math.min,
1539         nativeNow = Date.now,
1540         nativeParseInt = context.parseInt,
1541         nativeRandom = Math.random,
1542         nativeReverse = arrayProto.reverse;
1543
1544     /* Built-in method references that are verified to be native. */
1545     var DataView = getNative(context, 'DataView'),
1546         Map = getNative(context, 'Map'),
1547         Promise = getNative(context, 'Promise'),
1548         Set = getNative(context, 'Set'),
1549         WeakMap = getNative(context, 'WeakMap'),
1550         nativeCreate = getNative(Object, 'create');
1551
1552     /** Used to store function metadata. */
1553     var metaMap = WeakMap && new WeakMap;
1554
1555     /** Used to lookup unminified function names. */
1556     var realNames = {};
1557
1558     /** Used to detect maps, sets, and weakmaps. */
1559     var dataViewCtorString = toSource(DataView),
1560         mapCtorString = toSource(Map),
1561         promiseCtorString = toSource(Promise),
1562         setCtorString = toSource(Set),
1563         weakMapCtorString = toSource(WeakMap);
1564
1565     /** Used to convert symbols to primitives and strings. */
1566     var symbolProto = Symbol ? Symbol.prototype : undefined,
1567         symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
1568         symbolToString = symbolProto ? symbolProto.toString : undefined;
1569
1570     /*------------------------------------------------------------------------*/
1571
1572     /**
1573      * Creates a `lodash` object which wraps `value` to enable implicit method
1574      * chain sequences. Methods that operate on and return arrays, collections,
1575      * and functions can be chained together. Methods that retrieve a single value
1576      * or may return a primitive value will automatically end the chain sequence
1577      * and return the unwrapped value. Otherwise, the value must be unwrapped
1578      * with `_#value`.
1579      *
1580      * Explicit chain sequences, which must be unwrapped with `_#value`, may be
1581      * enabled using `_.chain`.
1582      *
1583      * The execution of chained methods is lazy, that is, it's deferred until
1584      * `_#value` is implicitly or explicitly called.
1585      *
1586      * Lazy evaluation allows several methods to support shortcut fusion.
1587      * Shortcut fusion is an optimization to merge iteratee calls; this avoids
1588      * the creation of intermediate arrays and can greatly reduce the number of
1589      * iteratee executions. Sections of a chain sequence qualify for shortcut
1590      * fusion if the section is applied to an array and iteratees accept only
1591      * one argument. The heuristic for whether a section qualifies for shortcut
1592      * fusion is subject to change.
1593      *
1594      * Chaining is supported in custom builds as long as the `_#value` method is
1595      * directly or indirectly included in the build.
1596      *
1597      * In addition to lodash methods, wrappers have `Array` and `String` methods.
1598      *
1599      * The wrapper `Array` methods are:
1600      * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
1601      *
1602      * The wrapper `String` methods are:
1603      * `replace` and `split`
1604      *
1605      * The wrapper methods that support shortcut fusion are:
1606      * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
1607      * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
1608      * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
1609      *
1610      * The chainable wrapper methods are:
1611      * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
1612      * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
1613      * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
1614      * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
1615      * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
1616      * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
1617      * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
1618      * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
1619      * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
1620      * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
1621      * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
1622      * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
1623      * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
1624      * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
1625      * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
1626      * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
1627      * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
1628      * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
1629      * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
1630      * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
1631      * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
1632      * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
1633      * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
1634      * `zipObject`, `zipObjectDeep`, and `zipWith`
1635      *
1636      * The wrapper methods that are **not** chainable by default are:
1637      * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
1638      * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
1639      * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
1640      * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
1641      * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
1642      * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
1643      * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
1644      * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
1645      * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
1646      * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
1647      * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
1648      * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
1649      * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
1650      * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
1651      * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
1652      * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
1653      * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
1654      * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
1655      * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
1656      * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
1657      * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
1658      * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
1659      * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
1660      * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
1661      * `upperFirst`, `value`, and `words`
1662      *
1663      * @name _
1664      * @constructor
1665      * @category Seq
1666      * @param {*} value The value to wrap in a `lodash` instance.
1667      * @returns {Object} Returns the new `lodash` wrapper instance.
1668      * @example
1669      *
1670      * function square(n) {
1671      *   return n * n;
1672      * }
1673      *
1674      * var wrapped = _([1, 2, 3]);
1675      *
1676      * // Returns an unwrapped value.
1677      * wrapped.reduce(_.add);
1678      * // => 6
1679      *
1680      * // Returns a wrapped value.
1681      * var squares = wrapped.map(square);
1682      *
1683      * _.isArray(squares);
1684      * // => false
1685      *
1686      * _.isArray(squares.value());
1687      * // => true
1688      */
1689     function lodash(value) {
1690       if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
1691         if (value instanceof LodashWrapper) {
1692           return value;
1693         }
1694         if (hasOwnProperty.call(value, '__wrapped__')) {
1695           return wrapperClone(value);
1696         }
1697       }
1698       return new LodashWrapper(value);
1699     }
1700
1701     /**
1702      * The base implementation of `_.create` without support for assigning
1703      * properties to the created object.
1704      *
1705      * @private
1706      * @param {Object} proto The object to inherit from.
1707      * @returns {Object} Returns the new object.
1708      */
1709     var baseCreate = (function() {
1710       function object() {}
1711       return function(proto) {
1712         if (!isObject(proto)) {
1713           return {};
1714         }
1715         if (objectCreate) {
1716           return objectCreate(proto);
1717         }
1718         object.prototype = proto;
1719         var result = new object;
1720         object.prototype = undefined;
1721         return result;
1722       };
1723     }());
1724
1725     /**
1726      * The function whose prototype chain sequence wrappers inherit from.
1727      *
1728      * @private
1729      */
1730     function baseLodash() {
1731       // No operation performed.
1732     }
1733
1734     /**
1735      * The base constructor for creating `lodash` wrapper objects.
1736      *
1737      * @private
1738      * @param {*} value The value to wrap.
1739      * @param {boolean} [chainAll] Enable explicit method chain sequences.
1740      */
1741     function LodashWrapper(value, chainAll) {
1742       this.__wrapped__ = value;
1743       this.__actions__ = [];
1744       this.__chain__ = !!chainAll;
1745       this.__index__ = 0;
1746       this.__values__ = undefined;
1747     }
1748
1749     /**
1750      * By default, the template delimiters used by lodash are like those in
1751      * embedded Ruby (ERB) as well as ES2015 template strings. Change the
1752      * following template settings to use alternative delimiters.
1753      *
1754      * @static
1755      * @memberOf _
1756      * @type {Object}
1757      */
1758     lodash.templateSettings = {
1759
1760       /**
1761        * Used to detect `data` property values to be HTML-escaped.
1762        *
1763        * @memberOf _.templateSettings
1764        * @type {RegExp}
1765        */
1766       'escape': reEscape,
1767
1768       /**
1769        * Used to detect code to be evaluated.
1770        *
1771        * @memberOf _.templateSettings
1772        * @type {RegExp}
1773        */
1774       'evaluate': reEvaluate,
1775
1776       /**
1777        * Used to detect `data` property values to inject.
1778        *
1779        * @memberOf _.templateSettings
1780        * @type {RegExp}
1781        */
1782       'interpolate': reInterpolate,
1783
1784       /**
1785        * Used to reference the data object in the template text.
1786        *
1787        * @memberOf _.templateSettings
1788        * @type {string}
1789        */
1790       'variable': '',
1791
1792       /**
1793        * Used to import variables into the compiled template.
1794        *
1795        * @memberOf _.templateSettings
1796        * @type {Object}
1797        */
1798       'imports': {
1799
1800         /**
1801          * A reference to the `lodash` function.
1802          *
1803          * @memberOf _.templateSettings.imports
1804          * @type {Function}
1805          */
1806         '_': lodash
1807       }
1808     };
1809
1810     // Ensure wrappers are instances of `baseLodash`.
1811     lodash.prototype = baseLodash.prototype;
1812     lodash.prototype.constructor = lodash;
1813
1814     LodashWrapper.prototype = baseCreate(baseLodash.prototype);
1815     LodashWrapper.prototype.constructor = LodashWrapper;
1816
1817     /*------------------------------------------------------------------------*/
1818
1819     /**
1820      * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
1821      *
1822      * @private
1823      * @constructor
1824      * @param {*} value The value to wrap.
1825      */
1826     function LazyWrapper(value) {
1827       this.__wrapped__ = value;
1828       this.__actions__ = [];
1829       this.__dir__ = 1;
1830       this.__filtered__ = false;
1831       this.__iteratees__ = [];
1832       this.__takeCount__ = MAX_ARRAY_LENGTH;
1833       this.__views__ = [];
1834     }
1835
1836     /**
1837      * Creates a clone of the lazy wrapper object.
1838      *
1839      * @private
1840      * @name clone
1841      * @memberOf LazyWrapper
1842      * @returns {Object} Returns the cloned `LazyWrapper` object.
1843      */
1844     function lazyClone() {
1845       var result = new LazyWrapper(this.__wrapped__);
1846       result.__actions__ = copyArray(this.__actions__);
1847       result.__dir__ = this.__dir__;
1848       result.__filtered__ = this.__filtered__;
1849       result.__iteratees__ = copyArray(this.__iteratees__);
1850       result.__takeCount__ = this.__takeCount__;
1851       result.__views__ = copyArray(this.__views__);
1852       return result;
1853     }
1854
1855     /**
1856      * Reverses the direction of lazy iteration.
1857      *
1858      * @private
1859      * @name reverse
1860      * @memberOf LazyWrapper
1861      * @returns {Object} Returns the new reversed `LazyWrapper` object.
1862      */
1863     function lazyReverse() {
1864       if (this.__filtered__) {
1865         var result = new LazyWrapper(this);
1866         result.__dir__ = -1;
1867         result.__filtered__ = true;
1868       } else {
1869         result = this.clone();
1870         result.__dir__ *= -1;
1871       }
1872       return result;
1873     }
1874
1875     /**
1876      * Extracts the unwrapped value from its lazy wrapper.
1877      *
1878      * @private
1879      * @name value
1880      * @memberOf LazyWrapper
1881      * @returns {*} Returns the unwrapped value.
1882      */
1883     function lazyValue() {
1884       var array = this.__wrapped__.value(),
1885           dir = this.__dir__,
1886           isArr = isArray(array),
1887           isRight = dir < 0,
1888           arrLength = isArr ? array.length : 0,
1889           view = getView(0, arrLength, this.__views__),
1890           start = view.start,
1891           end = view.end,
1892           length = end - start,
1893           index = isRight ? end : (start - 1),
1894           iteratees = this.__iteratees__,
1895           iterLength = iteratees.length,
1896           resIndex = 0,
1897           takeCount = nativeMin(length, this.__takeCount__);
1898
1899       if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
1900         return baseWrapperValue(array, this.__actions__);
1901       }
1902       var result = [];
1903
1904       outer:
1905       while (length-- && resIndex < takeCount) {
1906         index += dir;
1907
1908         var iterIndex = -1,
1909             value = array[index];
1910
1911         while (++iterIndex < iterLength) {
1912           var data = iteratees[iterIndex],
1913               iteratee = data.iteratee,
1914               type = data.type,
1915               computed = iteratee(value);
1916
1917           if (type == LAZY_MAP_FLAG) {
1918             value = computed;
1919           } else if (!computed) {
1920             if (type == LAZY_FILTER_FLAG) {
1921               continue outer;
1922             } else {
1923               break outer;
1924             }
1925           }
1926         }
1927         result[resIndex++] = value;
1928       }
1929       return result;
1930     }
1931
1932     // Ensure `LazyWrapper` is an instance of `baseLodash`.
1933     LazyWrapper.prototype = baseCreate(baseLodash.prototype);
1934     LazyWrapper.prototype.constructor = LazyWrapper;
1935
1936     /*------------------------------------------------------------------------*/
1937
1938     /**
1939      * Creates a hash object.
1940      *
1941      * @private
1942      * @constructor
1943      * @param {Array} [entries] The key-value pairs to cache.
1944      */
1945     function Hash(entries) {
1946       var index = -1,
1947           length = entries == null ? 0 : entries.length;
1948
1949       this.clear();
1950       while (++index < length) {
1951         var entry = entries[index];
1952         this.set(entry[0], entry[1]);
1953       }
1954     }
1955
1956     /**
1957      * Removes all key-value entries from the hash.
1958      *
1959      * @private
1960      * @name clear
1961      * @memberOf Hash
1962      */
1963     function hashClear() {
1964       this.__data__ = nativeCreate ? nativeCreate(null) : {};
1965       this.size = 0;
1966     }
1967
1968     /**
1969      * Removes `key` and its value from the hash.
1970      *
1971      * @private
1972      * @name delete
1973      * @memberOf Hash
1974      * @param {Object} hash The hash to modify.
1975      * @param {string} key The key of the value to remove.
1976      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
1977      */
1978     function hashDelete(key) {
1979       var result = this.has(key) && delete this.__data__[key];
1980       this.size -= result ? 1 : 0;
1981       return result;
1982     }
1983
1984     /**
1985      * Gets the hash value for `key`.
1986      *
1987      * @private
1988      * @name get
1989      * @memberOf Hash
1990      * @param {string} key The key of the value to get.
1991      * @returns {*} Returns the entry value.
1992      */
1993     function hashGet(key) {
1994       var data = this.__data__;
1995       if (nativeCreate) {
1996         var result = data[key];
1997         return result === HASH_UNDEFINED ? undefined : result;
1998       }
1999       return hasOwnProperty.call(data, key) ? data[key] : undefined;
2000     }
2001
2002     /**
2003      * Checks if a hash value for `key` exists.
2004      *
2005      * @private
2006      * @name has
2007      * @memberOf Hash
2008      * @param {string} key The key of the entry to check.
2009      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2010      */
2011     function hashHas(key) {
2012       var data = this.__data__;
2013       return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
2014     }
2015
2016     /**
2017      * Sets the hash `key` to `value`.
2018      *
2019      * @private
2020      * @name set
2021      * @memberOf Hash
2022      * @param {string} key The key of the value to set.
2023      * @param {*} value The value to set.
2024      * @returns {Object} Returns the hash instance.
2025      */
2026     function hashSet(key, value) {
2027       var data = this.__data__;
2028       this.size += this.has(key) ? 0 : 1;
2029       data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
2030       return this;
2031     }
2032
2033     // Add methods to `Hash`.
2034     Hash.prototype.clear = hashClear;
2035     Hash.prototype['delete'] = hashDelete;
2036     Hash.prototype.get = hashGet;
2037     Hash.prototype.has = hashHas;
2038     Hash.prototype.set = hashSet;
2039
2040     /*------------------------------------------------------------------------*/
2041
2042     /**
2043      * Creates an list cache object.
2044      *
2045      * @private
2046      * @constructor
2047      * @param {Array} [entries] The key-value pairs to cache.
2048      */
2049     function ListCache(entries) {
2050       var index = -1,
2051           length = entries == null ? 0 : entries.length;
2052
2053       this.clear();
2054       while (++index < length) {
2055         var entry = entries[index];
2056         this.set(entry[0], entry[1]);
2057       }
2058     }
2059
2060     /**
2061      * Removes all key-value entries from the list cache.
2062      *
2063      * @private
2064      * @name clear
2065      * @memberOf ListCache
2066      */
2067     function listCacheClear() {
2068       this.__data__ = [];
2069       this.size = 0;
2070     }
2071
2072     /**
2073      * Removes `key` and its value from the list cache.
2074      *
2075      * @private
2076      * @name delete
2077      * @memberOf ListCache
2078      * @param {string} key The key of the value to remove.
2079      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2080      */
2081     function listCacheDelete(key) {
2082       var data = this.__data__,
2083           index = assocIndexOf(data, key);
2084
2085       if (index < 0) {
2086         return false;
2087       }
2088       var lastIndex = data.length - 1;
2089       if (index == lastIndex) {
2090         data.pop();
2091       } else {
2092         splice.call(data, index, 1);
2093       }
2094       --this.size;
2095       return true;
2096     }
2097
2098     /**
2099      * Gets the list cache value for `key`.
2100      *
2101      * @private
2102      * @name get
2103      * @memberOf ListCache
2104      * @param {string} key The key of the value to get.
2105      * @returns {*} Returns the entry value.
2106      */
2107     function listCacheGet(key) {
2108       var data = this.__data__,
2109           index = assocIndexOf(data, key);
2110
2111       return index < 0 ? undefined : data[index][1];
2112     }
2113
2114     /**
2115      * Checks if a list cache value for `key` exists.
2116      *
2117      * @private
2118      * @name has
2119      * @memberOf ListCache
2120      * @param {string} key The key of the entry to check.
2121      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2122      */
2123     function listCacheHas(key) {
2124       return assocIndexOf(this.__data__, key) > -1;
2125     }
2126
2127     /**
2128      * Sets the list cache `key` to `value`.
2129      *
2130      * @private
2131      * @name set
2132      * @memberOf ListCache
2133      * @param {string} key The key of the value to set.
2134      * @param {*} value The value to set.
2135      * @returns {Object} Returns the list cache instance.
2136      */
2137     function listCacheSet(key, value) {
2138       var data = this.__data__,
2139           index = assocIndexOf(data, key);
2140
2141       if (index < 0) {
2142         ++this.size;
2143         data.push([key, value]);
2144       } else {
2145         data[index][1] = value;
2146       }
2147       return this;
2148     }
2149
2150     // Add methods to `ListCache`.
2151     ListCache.prototype.clear = listCacheClear;
2152     ListCache.prototype['delete'] = listCacheDelete;
2153     ListCache.prototype.get = listCacheGet;
2154     ListCache.prototype.has = listCacheHas;
2155     ListCache.prototype.set = listCacheSet;
2156
2157     /*------------------------------------------------------------------------*/
2158
2159     /**
2160      * Creates a map cache object to store key-value pairs.
2161      *
2162      * @private
2163      * @constructor
2164      * @param {Array} [entries] The key-value pairs to cache.
2165      */
2166     function MapCache(entries) {
2167       var index = -1,
2168           length = entries == null ? 0 : entries.length;
2169
2170       this.clear();
2171       while (++index < length) {
2172         var entry = entries[index];
2173         this.set(entry[0], entry[1]);
2174       }
2175     }
2176
2177     /**
2178      * Removes all key-value entries from the map.
2179      *
2180      * @private
2181      * @name clear
2182      * @memberOf MapCache
2183      */
2184     function mapCacheClear() {
2185       this.size = 0;
2186       this.__data__ = {
2187         'hash': new Hash,
2188         'map': new (Map || ListCache),
2189         'string': new Hash
2190       };
2191     }
2192
2193     /**
2194      * Removes `key` and its value from the map.
2195      *
2196      * @private
2197      * @name delete
2198      * @memberOf MapCache
2199      * @param {string} key The key of the value to remove.
2200      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2201      */
2202     function mapCacheDelete(key) {
2203       var result = getMapData(this, key)['delete'](key);
2204       this.size -= result ? 1 : 0;
2205       return result;
2206     }
2207
2208     /**
2209      * Gets the map value for `key`.
2210      *
2211      * @private
2212      * @name get
2213      * @memberOf MapCache
2214      * @param {string} key The key of the value to get.
2215      * @returns {*} Returns the entry value.
2216      */
2217     function mapCacheGet(key) {
2218       return getMapData(this, key).get(key);
2219     }
2220
2221     /**
2222      * Checks if a map value for `key` exists.
2223      *
2224      * @private
2225      * @name has
2226      * @memberOf MapCache
2227      * @param {string} key The key of the entry to check.
2228      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2229      */
2230     function mapCacheHas(key) {
2231       return getMapData(this, key).has(key);
2232     }
2233
2234     /**
2235      * Sets the map `key` to `value`.
2236      *
2237      * @private
2238      * @name set
2239      * @memberOf MapCache
2240      * @param {string} key The key of the value to set.
2241      * @param {*} value The value to set.
2242      * @returns {Object} Returns the map cache instance.
2243      */
2244     function mapCacheSet(key, value) {
2245       var data = getMapData(this, key),
2246           size = data.size;
2247
2248       data.set(key, value);
2249       this.size += data.size == size ? 0 : 1;
2250       return this;
2251     }
2252
2253     // Add methods to `MapCache`.
2254     MapCache.prototype.clear = mapCacheClear;
2255     MapCache.prototype['delete'] = mapCacheDelete;
2256     MapCache.prototype.get = mapCacheGet;
2257     MapCache.prototype.has = mapCacheHas;
2258     MapCache.prototype.set = mapCacheSet;
2259
2260     /*------------------------------------------------------------------------*/
2261
2262     /**
2263      *
2264      * Creates an array cache object to store unique values.
2265      *
2266      * @private
2267      * @constructor
2268      * @param {Array} [values] The values to cache.
2269      */
2270     function SetCache(values) {
2271       var index = -1,
2272           length = values == null ? 0 : values.length;
2273
2274       this.__data__ = new MapCache;
2275       while (++index < length) {
2276         this.add(values[index]);
2277       }
2278     }
2279
2280     /**
2281      * Adds `value` to the array cache.
2282      *
2283      * @private
2284      * @name add
2285      * @memberOf SetCache
2286      * @alias push
2287      * @param {*} value The value to cache.
2288      * @returns {Object} Returns the cache instance.
2289      */
2290     function setCacheAdd(value) {
2291       this.__data__.set(value, HASH_UNDEFINED);
2292       return this;
2293     }
2294
2295     /**
2296      * Checks if `value` is in the array cache.
2297      *
2298      * @private
2299      * @name has
2300      * @memberOf SetCache
2301      * @param {*} value The value to search for.
2302      * @returns {number} Returns `true` if `value` is found, else `false`.
2303      */
2304     function setCacheHas(value) {
2305       return this.__data__.has(value);
2306     }
2307
2308     // Add methods to `SetCache`.
2309     SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
2310     SetCache.prototype.has = setCacheHas;
2311
2312     /*------------------------------------------------------------------------*/
2313
2314     /**
2315      * Creates a stack cache object to store key-value pairs.
2316      *
2317      * @private
2318      * @constructor
2319      * @param {Array} [entries] The key-value pairs to cache.
2320      */
2321     function Stack(entries) {
2322       var data = this.__data__ = new ListCache(entries);
2323       this.size = data.size;
2324     }
2325
2326     /**
2327      * Removes all key-value entries from the stack.
2328      *
2329      * @private
2330      * @name clear
2331      * @memberOf Stack
2332      */
2333     function stackClear() {
2334       this.__data__ = new ListCache;
2335       this.size = 0;
2336     }
2337
2338     /**
2339      * Removes `key` and its value from the stack.
2340      *
2341      * @private
2342      * @name delete
2343      * @memberOf Stack
2344      * @param {string} key The key of the value to remove.
2345      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2346      */
2347     function stackDelete(key) {
2348       var data = this.__data__,
2349           result = data['delete'](key);
2350
2351       this.size = data.size;
2352       return result;
2353     }
2354
2355     /**
2356      * Gets the stack value for `key`.
2357      *
2358      * @private
2359      * @name get
2360      * @memberOf Stack
2361      * @param {string} key The key of the value to get.
2362      * @returns {*} Returns the entry value.
2363      */
2364     function stackGet(key) {
2365       return this.__data__.get(key);
2366     }
2367
2368     /**
2369      * Checks if a stack value for `key` exists.
2370      *
2371      * @private
2372      * @name has
2373      * @memberOf Stack
2374      * @param {string} key The key of the entry to check.
2375      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2376      */
2377     function stackHas(key) {
2378       return this.__data__.has(key);
2379     }
2380
2381     /**
2382      * Sets the stack `key` to `value`.
2383      *
2384      * @private
2385      * @name set
2386      * @memberOf Stack
2387      * @param {string} key The key of the value to set.
2388      * @param {*} value The value to set.
2389      * @returns {Object} Returns the stack cache instance.
2390      */
2391     function stackSet(key, value) {
2392       var data = this.__data__;
2393       if (data instanceof ListCache) {
2394         var pairs = data.__data__;
2395         if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
2396           pairs.push([key, value]);
2397           this.size = ++data.size;
2398           return this;
2399         }
2400         data = this.__data__ = new MapCache(pairs);
2401       }
2402       data.set(key, value);
2403       this.size = data.size;
2404       return this;
2405     }
2406
2407     // Add methods to `Stack`.
2408     Stack.prototype.clear = stackClear;
2409     Stack.prototype['delete'] = stackDelete;
2410     Stack.prototype.get = stackGet;
2411     Stack.prototype.has = stackHas;
2412     Stack.prototype.set = stackSet;
2413
2414     /*------------------------------------------------------------------------*/
2415
2416     /**
2417      * Creates an array of the enumerable property names of the array-like `value`.
2418      *
2419      * @private
2420      * @param {*} value The value to query.
2421      * @param {boolean} inherited Specify returning inherited property names.
2422      * @returns {Array} Returns the array of property names.
2423      */
2424     function arrayLikeKeys(value, inherited) {
2425       var isArr = isArray(value),
2426           isArg = !isArr && isArguments(value),
2427           isBuff = !isArr && !isArg && isBuffer(value),
2428           isType = !isArr && !isArg && !isBuff && isTypedArray(value),
2429           skipIndexes = isArr || isArg || isBuff || isType,
2430           result = skipIndexes ? baseTimes(value.length, String) : [],
2431           length = result.length;
2432
2433       for (var key in value) {
2434         if ((inherited || hasOwnProperty.call(value, key)) &&
2435             !(skipIndexes && (
2436                // Safari 9 has enumerable `arguments.length` in strict mode.
2437                key == 'length' ||
2438                // Node.js 0.10 has enumerable non-index properties on buffers.
2439                (isBuff && (key == 'offset' || key == 'parent')) ||
2440                // PhantomJS 2 has enumerable non-index properties on typed arrays.
2441                (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
2442                // Skip index properties.
2443                isIndex(key, length)
2444             ))) {
2445           result.push(key);
2446         }
2447       }
2448       return result;
2449     }
2450
2451     /**
2452      * A specialized version of `_.sample` for arrays.
2453      *
2454      * @private
2455      * @param {Array} array The array to sample.
2456      * @returns {*} Returns the random element.
2457      */
2458     function arraySample(array) {
2459       var length = array.length;
2460       return length ? array[baseRandom(0, length - 1)] : undefined;
2461     }
2462
2463     /**
2464      * A specialized version of `_.sampleSize` for arrays.
2465      *
2466      * @private
2467      * @param {Array} array The array to sample.
2468      * @param {number} n The number of elements to sample.
2469      * @returns {Array} Returns the random elements.
2470      */
2471     function arraySampleSize(array, n) {
2472       return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
2473     }
2474
2475     /**
2476      * A specialized version of `_.shuffle` for arrays.
2477      *
2478      * @private
2479      * @param {Array} array The array to shuffle.
2480      * @returns {Array} Returns the new shuffled array.
2481      */
2482     function arrayShuffle(array) {
2483       return shuffleSelf(copyArray(array));
2484     }
2485
2486     /**
2487      * This function is like `assignValue` except that it doesn't assign
2488      * `undefined` values.
2489      *
2490      * @private
2491      * @param {Object} object The object to modify.
2492      * @param {string} key The key of the property to assign.
2493      * @param {*} value The value to assign.
2494      */
2495     function assignMergeValue(object, key, value) {
2496       if ((value !== undefined && !eq(object[key], value)) ||
2497           (value === undefined && !(key in object))) {
2498         baseAssignValue(object, key, value);
2499       }
2500     }
2501
2502     /**
2503      * Assigns `value` to `key` of `object` if the existing value is not equivalent
2504      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
2505      * for equality comparisons.
2506      *
2507      * @private
2508      * @param {Object} object The object to modify.
2509      * @param {string} key The key of the property to assign.
2510      * @param {*} value The value to assign.
2511      */
2512     function assignValue(object, key, value) {
2513       var objValue = object[key];
2514       if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
2515           (value === undefined && !(key in object))) {
2516         baseAssignValue(object, key, value);
2517       }
2518     }
2519
2520     /**
2521      * Gets the index at which the `key` is found in `array` of key-value pairs.
2522      *
2523      * @private
2524      * @param {Array} array The array to inspect.
2525      * @param {*} key The key to search for.
2526      * @returns {number} Returns the index of the matched value, else `-1`.
2527      */
2528     function assocIndexOf(array, key) {
2529       var length = array.length;
2530       while (length--) {
2531         if (eq(array[length][0], key)) {
2532           return length;
2533         }
2534       }
2535       return -1;
2536     }
2537
2538     /**
2539      * Aggregates elements of `collection` on `accumulator` with keys transformed
2540      * by `iteratee` and values set by `setter`.
2541      *
2542      * @private
2543      * @param {Array|Object} collection The collection to iterate over.
2544      * @param {Function} setter The function to set `accumulator` values.
2545      * @param {Function} iteratee The iteratee to transform keys.
2546      * @param {Object} accumulator The initial aggregated object.
2547      * @returns {Function} Returns `accumulator`.
2548      */
2549     function baseAggregator(collection, setter, iteratee, accumulator) {
2550       baseEach(collection, function(value, key, collection) {
2551         setter(accumulator, value, iteratee(value), collection);
2552       });
2553       return accumulator;
2554     }
2555
2556     /**
2557      * The base implementation of `_.assign` without support for multiple sources
2558      * or `customizer` functions.
2559      *
2560      * @private
2561      * @param {Object} object The destination object.
2562      * @param {Object} source The source object.
2563      * @returns {Object} Returns `object`.
2564      */
2565     function baseAssign(object, source) {
2566       return object && copyObject(source, keys(source), object);
2567     }
2568
2569     /**
2570      * The base implementation of `_.assignIn` without support for multiple sources
2571      * or `customizer` functions.
2572      *
2573      * @private
2574      * @param {Object} object The destination object.
2575      * @param {Object} source The source object.
2576      * @returns {Object} Returns `object`.
2577      */
2578     function baseAssignIn(object, source) {
2579       return object && copyObject(source, keysIn(source), object);
2580     }
2581
2582     /**
2583      * The base implementation of `assignValue` and `assignMergeValue` without
2584      * value checks.
2585      *
2586      * @private
2587      * @param {Object} object The object to modify.
2588      * @param {string} key The key of the property to assign.
2589      * @param {*} value The value to assign.
2590      */
2591     function baseAssignValue(object, key, value) {
2592       if (key == '__proto__' && defineProperty) {
2593         defineProperty(object, key, {
2594           'configurable': true,
2595           'enumerable': true,
2596           'value': value,
2597           'writable': true
2598         });
2599       } else {
2600         object[key] = value;
2601       }
2602     }
2603
2604     /**
2605      * The base implementation of `_.at` without support for individual paths.
2606      *
2607      * @private
2608      * @param {Object} object The object to iterate over.
2609      * @param {string[]} paths The property paths to pick.
2610      * @returns {Array} Returns the picked elements.
2611      */
2612     function baseAt(object, paths) {
2613       var index = -1,
2614           length = paths.length,
2615           result = Array(length),
2616           skip = object == null;
2617
2618       while (++index < length) {
2619         result[index] = skip ? undefined : get(object, paths[index]);
2620       }
2621       return result;
2622     }
2623
2624     /**
2625      * The base implementation of `_.clamp` which doesn't coerce arguments.
2626      *
2627      * @private
2628      * @param {number} number The number to clamp.
2629      * @param {number} [lower] The lower bound.
2630      * @param {number} upper The upper bound.
2631      * @returns {number} Returns the clamped number.
2632      */
2633     function baseClamp(number, lower, upper) {
2634       if (number === number) {
2635         if (upper !== undefined) {
2636           number = number <= upper ? number : upper;
2637         }
2638         if (lower !== undefined) {
2639           number = number >= lower ? number : lower;
2640         }
2641       }
2642       return number;
2643     }
2644
2645     /**
2646      * The base implementation of `_.clone` and `_.cloneDeep` which tracks
2647      * traversed objects.
2648      *
2649      * @private
2650      * @param {*} value The value to clone.
2651      * @param {boolean} bitmask The bitmask flags.
2652      *  1 - Deep clone
2653      *  2 - Flatten inherited properties
2654      *  4 - Clone symbols
2655      * @param {Function} [customizer] The function to customize cloning.
2656      * @param {string} [key] The key of `value`.
2657      * @param {Object} [object] The parent object of `value`.
2658      * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
2659      * @returns {*} Returns the cloned value.
2660      */
2661     function baseClone(value, bitmask, customizer, key, object, stack) {
2662       var result,
2663           isDeep = bitmask & CLONE_DEEP_FLAG,
2664           isFlat = bitmask & CLONE_FLAT_FLAG,
2665           isFull = bitmask & CLONE_SYMBOLS_FLAG;
2666
2667       if (customizer) {
2668         result = object ? customizer(value, key, object, stack) : customizer(value);
2669       }
2670       if (result !== undefined) {
2671         return result;
2672       }
2673       if (!isObject(value)) {
2674         return value;
2675       }
2676       var isArr = isArray(value);
2677       if (isArr) {
2678         result = initCloneArray(value);
2679         if (!isDeep) {
2680           return copyArray(value, result);
2681         }
2682       } else {
2683         var tag = getTag(value),
2684             isFunc = tag == funcTag || tag == genTag;
2685
2686         if (isBuffer(value)) {
2687           return cloneBuffer(value, isDeep);
2688         }
2689         if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
2690           result = (isFlat || isFunc) ? {} : initCloneObject(value);
2691           if (!isDeep) {
2692             return isFlat
2693               ? copySymbolsIn(value, baseAssignIn(result, value))
2694               : copySymbols(value, baseAssign(result, value));
2695           }
2696         } else {
2697           if (!cloneableTags[tag]) {
2698             return object ? value : {};
2699           }
2700           result = initCloneByTag(value, tag, baseClone, isDeep);
2701         }
2702       }
2703       // Check for circular references and return its corresponding clone.
2704       stack || (stack = new Stack);
2705       var stacked = stack.get(value);
2706       if (stacked) {
2707         return stacked;
2708       }
2709       stack.set(value, result);
2710
2711       var keysFunc = isFull
2712         ? (isFlat ? getAllKeysIn : getAllKeys)
2713         : (isFlat ? keysIn : keys);
2714
2715       var props = isArr ? undefined : keysFunc(value);
2716       arrayEach(props || value, function(subValue, key) {
2717         if (props) {
2718           key = subValue;
2719           subValue = value[key];
2720         }
2721         // Recursively populate clone (susceptible to call stack limits).
2722         assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
2723       });
2724       return result;
2725     }
2726
2727     /**
2728      * The base implementation of `_.conforms` which doesn't clone `source`.
2729      *
2730      * @private
2731      * @param {Object} source The object of property predicates to conform to.
2732      * @returns {Function} Returns the new spec function.
2733      */
2734     function baseConforms(source) {
2735       var props = keys(source);
2736       return function(object) {
2737         return baseConformsTo(object, source, props);
2738       };
2739     }
2740
2741     /**
2742      * The base implementation of `_.conformsTo` which accepts `props` to check.
2743      *
2744      * @private
2745      * @param {Object} object The object to inspect.
2746      * @param {Object} source The object of property predicates to conform to.
2747      * @returns {boolean} Returns `true` if `object` conforms, else `false`.
2748      */
2749     function baseConformsTo(object, source, props) {
2750       var length = props.length;
2751       if (object == null) {
2752         return !length;
2753       }
2754       object = Object(object);
2755       while (length--) {
2756         var key = props[length],
2757             predicate = source[key],
2758             value = object[key];
2759
2760         if ((value === undefined && !(key in object)) || !predicate(value)) {
2761           return false;
2762         }
2763       }
2764       return true;
2765     }
2766
2767     /**
2768      * The base implementation of `_.delay` and `_.defer` which accepts `args`
2769      * to provide to `func`.
2770      *
2771      * @private
2772      * @param {Function} func The function to delay.
2773      * @param {number} wait The number of milliseconds to delay invocation.
2774      * @param {Array} args The arguments to provide to `func`.
2775      * @returns {number|Object} Returns the timer id or timeout object.
2776      */
2777     function baseDelay(func, wait, args) {
2778       if (typeof func != 'function') {
2779         throw new TypeError(FUNC_ERROR_TEXT);
2780       }
2781       return setTimeout(function() { func.apply(undefined, args); }, wait);
2782     }
2783
2784     /**
2785      * The base implementation of methods like `_.difference` without support
2786      * for excluding multiple arrays or iteratee shorthands.
2787      *
2788      * @private
2789      * @param {Array} array The array to inspect.
2790      * @param {Array} values The values to exclude.
2791      * @param {Function} [iteratee] The iteratee invoked per element.
2792      * @param {Function} [comparator] The comparator invoked per element.
2793      * @returns {Array} Returns the new array of filtered values.
2794      */
2795     function baseDifference(array, values, iteratee, comparator) {
2796       var index = -1,
2797           includes = arrayIncludes,
2798           isCommon = true,
2799           length = array.length,
2800           result = [],
2801           valuesLength = values.length;
2802
2803       if (!length) {
2804         return result;
2805       }
2806       if (iteratee) {
2807         values = arrayMap(values, baseUnary(iteratee));
2808       }
2809       if (comparator) {
2810         includes = arrayIncludesWith;
2811         isCommon = false;
2812       }
2813       else if (values.length >= LARGE_ARRAY_SIZE) {
2814         includes = cacheHas;
2815         isCommon = false;
2816         values = new SetCache(values);
2817       }
2818       outer:
2819       while (++index < length) {
2820         var value = array[index],
2821             computed = iteratee == null ? value : iteratee(value);
2822
2823         value = (comparator || value !== 0) ? value : 0;
2824         if (isCommon && computed === computed) {
2825           var valuesIndex = valuesLength;
2826           while (valuesIndex--) {
2827             if (values[valuesIndex] === computed) {
2828               continue outer;
2829             }
2830           }
2831           result.push(value);
2832         }
2833         else if (!includes(values, computed, comparator)) {
2834           result.push(value);
2835         }
2836       }
2837       return result;
2838     }
2839
2840     /**
2841      * The base implementation of `_.forEach` without support for iteratee shorthands.
2842      *
2843      * @private
2844      * @param {Array|Object} collection The collection to iterate over.
2845      * @param {Function} iteratee The function invoked per iteration.
2846      * @returns {Array|Object} Returns `collection`.
2847      */
2848     var baseEach = createBaseEach(baseForOwn);
2849
2850     /**
2851      * The base implementation of `_.forEachRight` without support for iteratee shorthands.
2852      *
2853      * @private
2854      * @param {Array|Object} collection The collection to iterate over.
2855      * @param {Function} iteratee The function invoked per iteration.
2856      * @returns {Array|Object} Returns `collection`.
2857      */
2858     var baseEachRight = createBaseEach(baseForOwnRight, true);
2859
2860     /**
2861      * The base implementation of `_.every` without support for iteratee shorthands.
2862      *
2863      * @private
2864      * @param {Array|Object} collection The collection to iterate over.
2865      * @param {Function} predicate The function invoked per iteration.
2866      * @returns {boolean} Returns `true` if all elements pass the predicate check,
2867      *  else `false`
2868      */
2869     function baseEvery(collection, predicate) {
2870       var result = true;
2871       baseEach(collection, function(value, index, collection) {
2872         result = !!predicate(value, index, collection);
2873         return result;
2874       });
2875       return result;
2876     }
2877
2878     /**
2879      * The base implementation of methods like `_.max` and `_.min` which accepts a
2880      * `comparator` to determine the extremum value.
2881      *
2882      * @private
2883      * @param {Array} array The array to iterate over.
2884      * @param {Function} iteratee The iteratee invoked per iteration.
2885      * @param {Function} comparator The comparator used to compare values.
2886      * @returns {*} Returns the extremum value.
2887      */
2888     function baseExtremum(array, iteratee, comparator) {
2889       var index = -1,
2890           length = array.length;
2891
2892       while (++index < length) {
2893         var value = array[index],
2894             current = iteratee(value);
2895
2896         if (current != null && (computed === undefined
2897               ? (current === current && !isSymbol(current))
2898               : comparator(current, computed)
2899             )) {
2900           var computed = current,
2901               result = value;
2902         }
2903       }
2904       return result;
2905     }
2906
2907     /**
2908      * The base implementation of `_.fill` without an iteratee call guard.
2909      *
2910      * @private
2911      * @param {Array} array The array to fill.
2912      * @param {*} value The value to fill `array` with.
2913      * @param {number} [start=0] The start position.
2914      * @param {number} [end=array.length] The end position.
2915      * @returns {Array} Returns `array`.
2916      */
2917     function baseFill(array, value, start, end) {
2918       var length = array.length;
2919
2920       start = toInteger(start);
2921       if (start < 0) {
2922         start = -start > length ? 0 : (length + start);
2923       }
2924       end = (end === undefined || end > length) ? length : toInteger(end);
2925       if (end < 0) {
2926         end += length;
2927       }
2928       end = start > end ? 0 : toLength(end);
2929       while (start < end) {
2930         array[start++] = value;
2931       }
2932       return array;
2933     }
2934
2935     /**
2936      * The base implementation of `_.filter` without support for iteratee shorthands.
2937      *
2938      * @private
2939      * @param {Array|Object} collection The collection to iterate over.
2940      * @param {Function} predicate The function invoked per iteration.
2941      * @returns {Array} Returns the new filtered array.
2942      */
2943     function baseFilter(collection, predicate) {
2944       var result = [];
2945       baseEach(collection, function(value, index, collection) {
2946         if (predicate(value, index, collection)) {
2947           result.push(value);
2948         }
2949       });
2950       return result;
2951     }
2952
2953     /**
2954      * The base implementation of `_.flatten` with support for restricting flattening.
2955      *
2956      * @private
2957      * @param {Array} array The array to flatten.
2958      * @param {number} depth The maximum recursion depth.
2959      * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
2960      * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
2961      * @param {Array} [result=[]] The initial result value.
2962      * @returns {Array} Returns the new flattened array.
2963      */
2964     function baseFlatten(array, depth, predicate, isStrict, result) {
2965       var index = -1,
2966           length = array.length;
2967
2968       predicate || (predicate = isFlattenable);
2969       result || (result = []);
2970
2971       while (++index < length) {
2972         var value = array[index];
2973         if (depth > 0 && predicate(value)) {
2974           if (depth > 1) {
2975             // Recursively flatten arrays (susceptible to call stack limits).
2976             baseFlatten(value, depth - 1, predicate, isStrict, result);
2977           } else {
2978             arrayPush(result, value);
2979           }
2980         } else if (!isStrict) {
2981           result[result.length] = value;
2982         }
2983       }
2984       return result;
2985     }
2986
2987     /**
2988      * The base implementation of `baseForOwn` which iterates over `object`
2989      * properties returned by `keysFunc` and invokes `iteratee` for each property.
2990      * Iteratee functions may exit iteration early by explicitly returning `false`.
2991      *
2992      * @private
2993      * @param {Object} object The object to iterate over.
2994      * @param {Function} iteratee The function invoked per iteration.
2995      * @param {Function} keysFunc The function to get the keys of `object`.
2996      * @returns {Object} Returns `object`.
2997      */
2998     var baseFor = createBaseFor();
2999
3000     /**
3001      * This function is like `baseFor` except that it iterates over properties
3002      * in the opposite order.
3003      *
3004      * @private
3005      * @param {Object} object The object to iterate over.
3006      * @param {Function} iteratee The function invoked per iteration.
3007      * @param {Function} keysFunc The function to get the keys of `object`.
3008      * @returns {Object} Returns `object`.
3009      */
3010     var baseForRight = createBaseFor(true);
3011
3012     /**
3013      * The base implementation of `_.forOwn` without support for iteratee shorthands.
3014      *
3015      * @private
3016      * @param {Object} object The object to iterate over.
3017      * @param {Function} iteratee The function invoked per iteration.
3018      * @returns {Object} Returns `object`.
3019      */
3020     function baseForOwn(object, iteratee) {
3021       return object && baseFor(object, iteratee, keys);
3022     }
3023
3024     /**
3025      * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
3026      *
3027      * @private
3028      * @param {Object} object The object to iterate over.
3029      * @param {Function} iteratee The function invoked per iteration.
3030      * @returns {Object} Returns `object`.
3031      */
3032     function baseForOwnRight(object, iteratee) {
3033       return object && baseForRight(object, iteratee, keys);
3034     }
3035
3036     /**
3037      * The base implementation of `_.functions` which creates an array of
3038      * `object` function property names filtered from `props`.
3039      *
3040      * @private
3041      * @param {Object} object The object to inspect.
3042      * @param {Array} props The property names to filter.
3043      * @returns {Array} Returns the function names.
3044      */
3045     function baseFunctions(object, props) {
3046       return arrayFilter(props, function(key) {
3047         return isFunction(object[key]);
3048       });
3049     }
3050
3051     /**
3052      * The base implementation of `_.get` without support for default values.
3053      *
3054      * @private
3055      * @param {Object} object The object to query.
3056      * @param {Array|string} path The path of the property to get.
3057      * @returns {*} Returns the resolved value.
3058      */
3059     function baseGet(object, path) {
3060       path = castPath(path, object);
3061
3062       var index = 0,
3063           length = path.length;
3064
3065       while (object != null && index < length) {
3066         object = object[toKey(path[index++])];
3067       }
3068       return (index && index == length) ? object : undefined;
3069     }
3070
3071     /**
3072      * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
3073      * `keysFunc` and `symbolsFunc` to get the enumerable property names and
3074      * symbols of `object`.
3075      *
3076      * @private
3077      * @param {Object} object The object to query.
3078      * @param {Function} keysFunc The function to get the keys of `object`.
3079      * @param {Function} symbolsFunc The function to get the symbols of `object`.
3080      * @returns {Array} Returns the array of property names and symbols.
3081      */
3082     function baseGetAllKeys(object, keysFunc, symbolsFunc) {
3083       var result = keysFunc(object);
3084       return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
3085     }
3086
3087     /**
3088      * The base implementation of `getTag` without fallbacks for buggy environments.
3089      *
3090      * @private
3091      * @param {*} value The value to query.
3092      * @returns {string} Returns the `toStringTag`.
3093      */
3094     function baseGetTag(value) {
3095       if (value == null) {
3096         return value === undefined ? undefinedTag : nullTag;
3097       }
3098       return (symToStringTag && symToStringTag in Object(value))
3099         ? getRawTag(value)
3100         : objectToString(value);
3101     }
3102
3103     /**
3104      * The base implementation of `_.gt` which doesn't coerce arguments.
3105      *
3106      * @private
3107      * @param {*} value The value to compare.
3108      * @param {*} other The other value to compare.
3109      * @returns {boolean} Returns `true` if `value` is greater than `other`,
3110      *  else `false`.
3111      */
3112     function baseGt(value, other) {
3113       return value > other;
3114     }
3115
3116     /**
3117      * The base implementation of `_.has` without support for deep paths.
3118      *
3119      * @private
3120      * @param {Object} [object] The object to query.
3121      * @param {Array|string} key The key to check.
3122      * @returns {boolean} Returns `true` if `key` exists, else `false`.
3123      */
3124     function baseHas(object, key) {
3125       return object != null && hasOwnProperty.call(object, key);
3126     }
3127
3128     /**
3129      * The base implementation of `_.hasIn` without support for deep paths.
3130      *
3131      * @private
3132      * @param {Object} [object] The object to query.
3133      * @param {Array|string} key The key to check.
3134      * @returns {boolean} Returns `true` if `key` exists, else `false`.
3135      */
3136     function baseHasIn(object, key) {
3137       return object != null && key in Object(object);
3138     }
3139
3140     /**
3141      * The base implementation of `_.inRange` which doesn't coerce arguments.
3142      *
3143      * @private
3144      * @param {number} number The number to check.
3145      * @param {number} start The start of the range.
3146      * @param {number} end The end of the range.
3147      * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
3148      */
3149     function baseInRange(number, start, end) {
3150       return number >= nativeMin(start, end) && number < nativeMax(start, end);
3151     }
3152
3153     /**
3154      * The base implementation of methods like `_.intersection`, without support
3155      * for iteratee shorthands, that accepts an array of arrays to inspect.
3156      *
3157      * @private
3158      * @param {Array} arrays The arrays to inspect.
3159      * @param {Function} [iteratee] The iteratee invoked per element.
3160      * @param {Function} [comparator] The comparator invoked per element.
3161      * @returns {Array} Returns the new array of shared values.
3162      */
3163     function baseIntersection(arrays, iteratee, comparator) {
3164       var includes = comparator ? arrayIncludesWith : arrayIncludes,
3165           length = arrays[0].length,
3166           othLength = arrays.length,
3167           othIndex = othLength,
3168           caches = Array(othLength),
3169           maxLength = Infinity,
3170           result = [];
3171
3172       while (othIndex--) {
3173         var array = arrays[othIndex];
3174         if (othIndex && iteratee) {
3175           array = arrayMap(array, baseUnary(iteratee));
3176         }
3177         maxLength = nativeMin(array.length, maxLength);
3178         caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
3179           ? new SetCache(othIndex && array)
3180           : undefined;
3181       }
3182       array = arrays[0];
3183
3184       var index = -1,
3185           seen = caches[0];
3186
3187       outer:
3188       while (++index < length && result.length < maxLength) {
3189         var value = array[index],
3190             computed = iteratee ? iteratee(value) : value;
3191
3192         value = (comparator || value !== 0) ? value : 0;
3193         if (!(seen
3194               ? cacheHas(seen, computed)
3195               : includes(result, computed, comparator)
3196             )) {
3197           othIndex = othLength;
3198           while (--othIndex) {
3199             var cache = caches[othIndex];
3200             if (!(cache
3201                   ? cacheHas(cache, computed)
3202                   : includes(arrays[othIndex], computed, comparator))
3203                 ) {
3204               continue outer;
3205             }
3206           }
3207           if (seen) {
3208             seen.push(computed);
3209           }
3210           result.push(value);
3211         }
3212       }
3213       return result;
3214     }
3215
3216     /**
3217      * The base implementation of `_.invert` and `_.invertBy` which inverts
3218      * `object` with values transformed by `iteratee` and set by `setter`.
3219      *
3220      * @private
3221      * @param {Object} object The object to iterate over.
3222      * @param {Function} setter The function to set `accumulator` values.
3223      * @param {Function} iteratee The iteratee to transform values.
3224      * @param {Object} accumulator The initial inverted object.
3225      * @returns {Function} Returns `accumulator`.
3226      */
3227     function baseInverter(object, setter, iteratee, accumulator) {
3228       baseForOwn(object, function(value, key, object) {
3229         setter(accumulator, iteratee(value), key, object);
3230       });
3231       return accumulator;
3232     }
3233
3234     /**
3235      * The base implementation of `_.invoke` without support for individual
3236      * method arguments.
3237      *
3238      * @private
3239      * @param {Object} object The object to query.
3240      * @param {Array|string} path The path of the method to invoke.
3241      * @param {Array} args The arguments to invoke the method with.
3242      * @returns {*} Returns the result of the invoked method.
3243      */
3244     function baseInvoke(object, path, args) {
3245       path = castPath(path, object);
3246       object = parent(object, path);
3247       var func = object == null ? object : object[toKey(last(path))];
3248       return func == null ? undefined : apply(func, object, args);
3249     }
3250
3251     /**
3252      * The base implementation of `_.isArguments`.
3253      *
3254      * @private
3255      * @param {*} value The value to check.
3256      * @returns {boolean} Returns `true` if `value` is an `arguments` object,
3257      */
3258     function baseIsArguments(value) {
3259       return isObjectLike(value) && baseGetTag(value) == argsTag;
3260     }
3261
3262     /**
3263      * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
3264      *
3265      * @private
3266      * @param {*} value The value to check.
3267      * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
3268      */
3269     function baseIsArrayBuffer(value) {
3270       return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
3271     }
3272
3273     /**
3274      * The base implementation of `_.isDate` without Node.js optimizations.
3275      *
3276      * @private
3277      * @param {*} value The value to check.
3278      * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
3279      */
3280     function baseIsDate(value) {
3281       return isObjectLike(value) && baseGetTag(value) == dateTag;
3282     }
3283
3284     /**
3285      * The base implementation of `_.isEqual` which supports partial comparisons
3286      * and tracks traversed objects.
3287      *
3288      * @private
3289      * @param {*} value The value to compare.
3290      * @param {*} other The other value to compare.
3291      * @param {boolean} bitmask The bitmask flags.
3292      *  1 - Unordered comparison
3293      *  2 - Partial comparison
3294      * @param {Function} [customizer] The function to customize comparisons.
3295      * @param {Object} [stack] Tracks traversed `value` and `other` objects.
3296      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
3297      */
3298     function baseIsEqual(value, other, bitmask, customizer, stack) {
3299       if (value === other) {
3300         return true;
3301       }
3302       if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
3303         return value !== value && other !== other;
3304       }
3305       return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
3306     }
3307
3308     /**
3309      * A specialized version of `baseIsEqual` for arrays and objects which performs
3310      * deep comparisons and tracks traversed objects enabling objects with circular
3311      * references to be compared.
3312      *
3313      * @private
3314      * @param {Object} object The object to compare.
3315      * @param {Object} other The other object to compare.
3316      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
3317      * @param {Function} customizer The function to customize comparisons.
3318      * @param {Function} equalFunc The function to determine equivalents of values.
3319      * @param {Object} [stack] Tracks traversed `object` and `other` objects.
3320      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
3321      */
3322     function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
3323       var objIsArr = isArray(object),
3324           othIsArr = isArray(other),
3325           objTag = objIsArr ? arrayTag : getTag(object),
3326           othTag = othIsArr ? arrayTag : getTag(other);
3327
3328       objTag = objTag == argsTag ? objectTag : objTag;
3329       othTag = othTag == argsTag ? objectTag : othTag;
3330
3331       var objIsObj = objTag == objectTag,
3332           othIsObj = othTag == objectTag,
3333           isSameTag = objTag == othTag;
3334
3335       if (isSameTag && isBuffer(object)) {
3336         if (!isBuffer(other)) {
3337           return false;
3338         }
3339         objIsArr = true;
3340         objIsObj = false;
3341       }
3342       if (isSameTag && !objIsObj) {
3343         stack || (stack = new Stack);
3344         return (objIsArr || isTypedArray(object))
3345           ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
3346           : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
3347       }
3348       if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
3349         var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
3350             othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
3351
3352         if (objIsWrapped || othIsWrapped) {
3353           var objUnwrapped = objIsWrapped ? object.value() : object,
3354               othUnwrapped = othIsWrapped ? other.value() : other;
3355
3356           stack || (stack = new Stack);
3357           return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
3358         }
3359       }
3360       if (!isSameTag) {
3361         return false;
3362       }
3363       stack || (stack = new Stack);
3364       return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
3365     }
3366
3367     /**
3368      * The base implementation of `_.isMap` without Node.js optimizations.
3369      *
3370      * @private
3371      * @param {*} value The value to check.
3372      * @returns {boolean} Returns `true` if `value` is a map, else `false`.
3373      */
3374     function baseIsMap(value) {
3375       return isObjectLike(value) && getTag(value) == mapTag;
3376     }
3377
3378     /**
3379      * The base implementation of `_.isMatch` without support for iteratee shorthands.
3380      *
3381      * @private
3382      * @param {Object} object The object to inspect.
3383      * @param {Object} source The object of property values to match.
3384      * @param {Array} matchData The property names, values, and compare flags to match.
3385      * @param {Function} [customizer] The function to customize comparisons.
3386      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
3387      */
3388     function baseIsMatch(object, source, matchData, customizer) {
3389       var index = matchData.length,
3390           length = index,
3391           noCustomizer = !customizer;
3392
3393       if (object == null) {
3394         return !length;
3395       }
3396       object = Object(object);
3397       while (index--) {
3398         var data = matchData[index];
3399         if ((noCustomizer && data[2])
3400               ? data[1] !== object[data[0]]
3401               : !(data[0] in object)
3402             ) {
3403           return false;
3404         }
3405       }
3406       while (++index < length) {
3407         data = matchData[index];
3408         var key = data[0],
3409             objValue = object[key],
3410             srcValue = data[1];
3411
3412         if (noCustomizer && data[2]) {
3413           if (objValue === undefined && !(key in object)) {
3414             return false;
3415           }
3416         } else {
3417           var stack = new Stack;
3418           if (customizer) {
3419             var result = customizer(objValue, srcValue, key, object, source, stack);
3420           }
3421           if (!(result === undefined
3422                 ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
3423                 : result
3424               )) {
3425             return false;
3426           }
3427         }
3428       }
3429       return true;
3430     }
3431
3432     /**
3433      * The base implementation of `_.isNative` without bad shim checks.
3434      *
3435      * @private
3436      * @param {*} value The value to check.
3437      * @returns {boolean} Returns `true` if `value` is a native function,
3438      *  else `false`.
3439      */
3440     function baseIsNative(value) {
3441       if (!isObject(value) || isMasked(value)) {
3442         return false;
3443       }
3444       var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
3445       return pattern.test(toSource(value));
3446     }
3447
3448     /**
3449      * The base implementation of `_.isRegExp` without Node.js optimizations.
3450      *
3451      * @private
3452      * @param {*} value The value to check.
3453      * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
3454      */
3455     function baseIsRegExp(value) {
3456       return isObjectLike(value) && baseGetTag(value) == regexpTag;
3457     }
3458
3459     /**
3460      * The base implementation of `_.isSet` without Node.js optimizations.
3461      *
3462      * @private
3463      * @param {*} value The value to check.
3464      * @returns {boolean} Returns `true` if `value` is a set, else `false`.
3465      */
3466     function baseIsSet(value) {
3467       return isObjectLike(value) && getTag(value) == setTag;
3468     }
3469
3470     /**
3471      * The base implementation of `_.isTypedArray` without Node.js optimizations.
3472      *
3473      * @private
3474      * @param {*} value The value to check.
3475      * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
3476      */
3477     function baseIsTypedArray(value) {
3478       return isObjectLike(value) &&
3479         isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
3480     }
3481
3482     /**
3483      * The base implementation of `_.iteratee`.
3484      *
3485      * @private
3486      * @param {*} [value=_.identity] The value to convert to an iteratee.
3487      * @returns {Function} Returns the iteratee.
3488      */
3489     function baseIteratee(value) {
3490       // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
3491       // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
3492       if (typeof value == 'function') {
3493         return value;
3494       }
3495       if (value == null) {
3496         return identity;
3497       }
3498       if (typeof value == 'object') {
3499         return isArray(value)
3500           ? baseMatchesProperty(value[0], value[1])
3501           : baseMatches(value);
3502       }
3503       return property(value);
3504     }
3505
3506     /**
3507      * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
3508      *
3509      * @private
3510      * @param {Object} object The object to query.
3511      * @returns {Array} Returns the array of property names.
3512      */
3513     function baseKeys(object) {
3514       if (!isPrototype(object)) {
3515         return nativeKeys(object);
3516       }
3517       var result = [];
3518       for (var key in Object(object)) {
3519         if (hasOwnProperty.call(object, key) && key != 'constructor') {
3520           result.push(key);
3521         }
3522       }
3523       return result;
3524     }
3525
3526     /**
3527      * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
3528      *
3529      * @private
3530      * @param {Object} object The object to query.
3531      * @returns {Array} Returns the array of property names.
3532      */
3533     function baseKeysIn(object) {
3534       if (!isObject(object)) {
3535         return nativeKeysIn(object);
3536       }
3537       var isProto = isPrototype(object),
3538           result = [];
3539
3540       for (var key in object) {
3541         if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
3542           result.push(key);
3543         }
3544       }
3545       return result;
3546     }
3547
3548     /**
3549      * The base implementation of `_.lt` which doesn't coerce arguments.
3550      *
3551      * @private
3552      * @param {*} value The value to compare.
3553      * @param {*} other The other value to compare.
3554      * @returns {boolean} Returns `true` if `value` is less than `other`,
3555      *  else `false`.
3556      */
3557     function baseLt(value, other) {
3558       return value < other;
3559     }
3560
3561     /**
3562      * The base implementation of `_.map` without support for iteratee shorthands.
3563      *
3564      * @private
3565      * @param {Array|Object} collection The collection to iterate over.
3566      * @param {Function} iteratee The function invoked per iteration.
3567      * @returns {Array} Returns the new mapped array.
3568      */
3569     function baseMap(collection, iteratee) {
3570       var index = -1,
3571           result = isArrayLike(collection) ? Array(collection.length) : [];
3572
3573       baseEach(collection, function(value, key, collection) {
3574         result[++index] = iteratee(value, key, collection);
3575       });
3576       return result;
3577     }
3578
3579     /**
3580      * The base implementation of `_.matches` which doesn't clone `source`.
3581      *
3582      * @private
3583      * @param {Object} source The object of property values to match.
3584      * @returns {Function} Returns the new spec function.
3585      */
3586     function baseMatches(source) {
3587       var matchData = getMatchData(source);
3588       if (matchData.length == 1 && matchData[0][2]) {
3589         return matchesStrictComparable(matchData[0][0], matchData[0][1]);
3590       }
3591       return function(object) {
3592         return object === source || baseIsMatch(object, source, matchData);
3593       };
3594     }
3595
3596     /**
3597      * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
3598      *
3599      * @private
3600      * @param {string} path The path of the property to get.
3601      * @param {*} srcValue The value to match.
3602      * @returns {Function} Returns the new spec function.
3603      */
3604     function baseMatchesProperty(path, srcValue) {
3605       if (isKey(path) && isStrictComparable(srcValue)) {
3606         return matchesStrictComparable(toKey(path), srcValue);
3607       }
3608       return function(object) {
3609         var objValue = get(object, path);
3610         return (objValue === undefined && objValue === srcValue)
3611           ? hasIn(object, path)
3612           : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
3613       };
3614     }
3615
3616     /**
3617      * The base implementation of `_.merge` without support for multiple sources.
3618      *
3619      * @private
3620      * @param {Object} object The destination object.
3621      * @param {Object} source The source object.
3622      * @param {number} srcIndex The index of `source`.
3623      * @param {Function} [customizer] The function to customize merged values.
3624      * @param {Object} [stack] Tracks traversed source values and their merged
3625      *  counterparts.
3626      */
3627     function baseMerge(object, source, srcIndex, customizer, stack) {
3628       if (object === source) {
3629         return;
3630       }
3631       baseFor(source, function(srcValue, key) {
3632         if (isObject(srcValue)) {
3633           stack || (stack = new Stack);
3634           baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
3635         }
3636         else {
3637           var newValue = customizer
3638             ? customizer(object[key], srcValue, (key + ''), object, source, stack)
3639             : undefined;
3640
3641           if (newValue === undefined) {
3642             newValue = srcValue;
3643           }
3644           assignMergeValue(object, key, newValue);
3645         }
3646       }, keysIn);
3647     }
3648
3649     /**
3650      * A specialized version of `baseMerge` for arrays and objects which performs
3651      * deep merges and tracks traversed objects enabling objects with circular
3652      * references to be merged.
3653      *
3654      * @private
3655      * @param {Object} object The destination object.
3656      * @param {Object} source The source object.
3657      * @param {string} key The key of the value to merge.
3658      * @param {number} srcIndex The index of `source`.
3659      * @param {Function} mergeFunc The function to merge values.
3660      * @param {Function} [customizer] The function to customize assigned values.
3661      * @param {Object} [stack] Tracks traversed source values and their merged
3662      *  counterparts.
3663      */
3664     function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
3665       var objValue = object[key],
3666           srcValue = source[key],
3667           stacked = stack.get(srcValue);
3668
3669       if (stacked) {
3670         assignMergeValue(object, key, stacked);
3671         return;
3672       }
3673       var newValue = customizer
3674         ? customizer(objValue, srcValue, (key + ''), object, source, stack)
3675         : undefined;
3676
3677       var isCommon = newValue === undefined;
3678
3679       if (isCommon) {
3680         var isArr = isArray(srcValue),
3681             isBuff = !isArr && isBuffer(srcValue),
3682             isTyped = !isArr && !isBuff && isTypedArray(srcValue);
3683
3684         newValue = srcValue;
3685         if (isArr || isBuff || isTyped) {
3686           if (isArray(objValue)) {
3687             newValue = objValue;
3688           }
3689           else if (isArrayLikeObject(objValue)) {
3690             newValue = copyArray(objValue);
3691           }
3692           else if (isBuff) {
3693             isCommon = false;
3694             newValue = cloneBuffer(srcValue, true);
3695           }
3696           else if (isTyped) {
3697             isCommon = false;
3698             newValue = cloneTypedArray(srcValue, true);
3699           }
3700           else {
3701             newValue = [];
3702           }
3703         }
3704         else if (isPlainObject(srcValue) || isArguments(srcValue)) {
3705           newValue = objValue;
3706           if (isArguments(objValue)) {
3707             newValue = toPlainObject(objValue);
3708           }
3709           else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
3710             newValue = initCloneObject(srcValue);
3711           }
3712         }
3713         else {
3714           isCommon = false;
3715         }
3716       }
3717       if (isCommon) {
3718         // Recursively merge objects and arrays (susceptible to call stack limits).
3719         stack.set(srcValue, newValue);
3720         mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
3721         stack['delete'](srcValue);
3722       }
3723       assignMergeValue(object, key, newValue);
3724     }
3725
3726     /**
3727      * The base implementation of `_.nth` which doesn't coerce arguments.
3728      *
3729      * @private
3730      * @param {Array} array The array to query.
3731      * @param {number} n The index of the element to return.
3732      * @returns {*} Returns the nth element of `array`.
3733      */
3734     function baseNth(array, n) {
3735       var length = array.length;
3736       if (!length) {
3737         return;
3738       }
3739       n += n < 0 ? length : 0;
3740       return isIndex(n, length) ? array[n] : undefined;
3741     }
3742
3743     /**
3744      * The base implementation of `_.orderBy` without param guards.
3745      *
3746      * @private
3747      * @param {Array|Object} collection The collection to iterate over.
3748      * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
3749      * @param {string[]} orders The sort orders of `iteratees`.
3750      * @returns {Array} Returns the new sorted array.
3751      */
3752     function baseOrderBy(collection, iteratees, orders) {
3753       var index = -1;
3754       iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee()));
3755
3756       var result = baseMap(collection, function(value, key, collection) {
3757         var criteria = arrayMap(iteratees, function(iteratee) {
3758           return iteratee(value);
3759         });
3760         return { 'criteria': criteria, 'index': ++index, 'value': value };
3761       });
3762
3763       return baseSortBy(result, function(object, other) {
3764         return compareMultiple(object, other, orders);
3765       });
3766     }
3767
3768     /**
3769      * The base implementation of `_.pick` without support for individual
3770      * property identifiers.
3771      *
3772      * @private
3773      * @param {Object} object The source object.
3774      * @param {string[]} paths The property paths to pick.
3775      * @returns {Object} Returns the new object.
3776      */
3777     function basePick(object, paths) {
3778       return basePickBy(object, paths, function(value, path) {
3779         return hasIn(object, path);
3780       });
3781     }
3782
3783     /**
3784      * The base implementation of  `_.pickBy` without support for iteratee shorthands.
3785      *
3786      * @private
3787      * @param {Object} object The source object.
3788      * @param {string[]} paths The property paths to pick.
3789      * @param {Function} predicate The function invoked per property.
3790      * @returns {Object} Returns the new object.
3791      */
3792     function basePickBy(object, paths, predicate) {
3793       var index = -1,
3794           length = paths.length,
3795           result = {};
3796
3797       while (++index < length) {
3798         var path = paths[index],
3799             value = baseGet(object, path);
3800
3801         if (predicate(value, path)) {
3802           baseSet(result, castPath(path, object), value);
3803         }
3804       }
3805       return result;
3806     }
3807
3808     /**
3809      * A specialized version of `baseProperty` which supports deep paths.
3810      *
3811      * @private
3812      * @param {Array|string} path The path of the property to get.
3813      * @returns {Function} Returns the new accessor function.
3814      */
3815     function basePropertyDeep(path) {
3816       return function(object) {
3817         return baseGet(object, path);
3818       };
3819     }
3820
3821     /**
3822      * The base implementation of `_.pullAllBy` without support for iteratee
3823      * shorthands.
3824      *
3825      * @private
3826      * @param {Array} array The array to modify.
3827      * @param {Array} values The values to remove.
3828      * @param {Function} [iteratee] The iteratee invoked per element.
3829      * @param {Function} [comparator] The comparator invoked per element.
3830      * @returns {Array} Returns `array`.
3831      */
3832     function basePullAll(array, values, iteratee, comparator) {
3833       var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
3834           index = -1,
3835           length = values.length,
3836           seen = array;
3837
3838       if (array === values) {
3839         values = copyArray(values);
3840       }
3841       if (iteratee) {
3842         seen = arrayMap(array, baseUnary(iteratee));
3843       }
3844       while (++index < length) {
3845         var fromIndex = 0,
3846             value = values[index],
3847             computed = iteratee ? iteratee(value) : value;
3848
3849         while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
3850           if (seen !== array) {
3851             splice.call(seen, fromIndex, 1);
3852           }
3853           splice.call(array, fromIndex, 1);
3854         }
3855       }
3856       return array;
3857     }
3858
3859     /**
3860      * The base implementation of `_.pullAt` without support for individual
3861      * indexes or capturing the removed elements.
3862      *
3863      * @private
3864      * @param {Array} array The array to modify.
3865      * @param {number[]} indexes The indexes of elements to remove.
3866      * @returns {Array} Returns `array`.
3867      */
3868     function basePullAt(array, indexes) {
3869       var length = array ? indexes.length : 0,
3870           lastIndex = length - 1;
3871
3872       while (length--) {
3873         var index = indexes[length];
3874         if (length == lastIndex || index !== previous) {
3875           var previous = index;
3876           if (isIndex(index)) {
3877             splice.call(array, index, 1);
3878           } else {
3879             baseUnset(array, index);
3880           }
3881         }
3882       }
3883       return array;
3884     }
3885
3886     /**
3887      * The base implementation of `_.random` without support for returning
3888      * floating-point numbers.
3889      *
3890      * @private
3891      * @param {number} lower The lower bound.
3892      * @param {number} upper The upper bound.
3893      * @returns {number} Returns the random number.
3894      */
3895     function baseRandom(lower, upper) {
3896       return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
3897     }
3898
3899     /**
3900      * The base implementation of `_.range` and `_.rangeRight` which doesn't
3901      * coerce arguments.
3902      *
3903      * @private
3904      * @param {number} start The start of the range.
3905      * @param {number} end The end of the range.
3906      * @param {number} step The value to increment or decrement by.
3907      * @param {boolean} [fromRight] Specify iterating from right to left.
3908      * @returns {Array} Returns the range of numbers.
3909      */
3910     function baseRange(start, end, step, fromRight) {
3911       var index = -1,
3912           length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
3913           result = Array(length);
3914
3915       while (length--) {
3916         result[fromRight ? length : ++index] = start;
3917         start += step;
3918       }
3919       return result;
3920     }
3921
3922     /**
3923      * The base implementation of `_.repeat` which doesn't coerce arguments.
3924      *
3925      * @private
3926      * @param {string} string The string to repeat.
3927      * @param {number} n The number of times to repeat the string.
3928      * @returns {string} Returns the repeated string.
3929      */
3930     function baseRepeat(string, n) {
3931       var result = '';
3932       if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
3933         return result;
3934       }
3935       // Leverage the exponentiation by squaring algorithm for a faster repeat.
3936       // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
3937       do {
3938         if (n % 2) {
3939           result += string;
3940         }
3941         n = nativeFloor(n / 2);
3942         if (n) {
3943           string += string;
3944         }
3945       } while (n);
3946
3947       return result;
3948     }
3949
3950     /**
3951      * The base implementation of `_.rest` which doesn't validate or coerce arguments.
3952      *
3953      * @private
3954      * @param {Function} func The function to apply a rest parameter to.
3955      * @param {number} [start=func.length-1] The start position of the rest parameter.
3956      * @returns {Function} Returns the new function.
3957      */
3958     function baseRest(func, start) {
3959       return setToString(overRest(func, start, identity), func + '');
3960     }
3961
3962     /**
3963      * The base implementation of `_.sample`.
3964      *
3965      * @private
3966      * @param {Array|Object} collection The collection to sample.
3967      * @returns {*} Returns the random element.
3968      */
3969     function baseSample(collection) {
3970       return arraySample(values(collection));
3971     }
3972
3973     /**
3974      * The base implementation of `_.sampleSize` without param guards.
3975      *
3976      * @private
3977      * @param {Array|Object} collection The collection to sample.
3978      * @param {number} n The number of elements to sample.
3979      * @returns {Array} Returns the random elements.
3980      */
3981     function baseSampleSize(collection, n) {
3982       var array = values(collection);
3983       return shuffleSelf(array, baseClamp(n, 0, array.length));
3984     }
3985
3986     /**
3987      * The base implementation of `_.set`.
3988      *
3989      * @private
3990      * @param {Object} object The object to modify.
3991      * @param {Array|string} path The path of the property to set.
3992      * @param {*} value The value to set.
3993      * @param {Function} [customizer] The function to customize path creation.
3994      * @returns {Object} Returns `object`.
3995      */
3996     function baseSet(object, path, value, customizer) {
3997       if (!isObject(object)) {
3998         return object;
3999       }
4000       path = castPath(path, object);
4001
4002       var index = -1,
4003           length = path.length,
4004           lastIndex = length - 1,
4005           nested = object;
4006
4007       while (nested != null && ++index < length) {
4008         var key = toKey(path[index]),
4009             newValue = value;
4010
4011         if (index != lastIndex) {
4012           var objValue = nested[key];
4013           newValue = customizer ? customizer(objValue, key, nested) : undefined;
4014           if (newValue === undefined) {
4015             newValue = isObject(objValue)
4016               ? objValue
4017               : (isIndex(path[index + 1]) ? [] : {});
4018           }
4019         }
4020         assignValue(nested, key, newValue);
4021         nested = nested[key];
4022       }
4023       return object;
4024     }
4025
4026     /**
4027      * The base implementation of `setData` without support for hot loop shorting.
4028      *
4029      * @private
4030      * @param {Function} func The function to associate metadata with.
4031      * @param {*} data The metadata.
4032      * @returns {Function} Returns `func`.
4033      */
4034     var baseSetData = !metaMap ? identity : function(func, data) {
4035       metaMap.set(func, data);
4036       return func;
4037     };
4038
4039     /**
4040      * The base implementation of `setToString` without support for hot loop shorting.
4041      *
4042      * @private
4043      * @param {Function} func The function to modify.
4044      * @param {Function} string The `toString` result.
4045      * @returns {Function} Returns `func`.
4046      */
4047     var baseSetToString = !defineProperty ? identity : function(func, string) {
4048       return defineProperty(func, 'toString', {
4049         'configurable': true,
4050         'enumerable': false,
4051         'value': constant(string),
4052         'writable': true
4053       });
4054     };
4055
4056     /**
4057      * The base implementation of `_.shuffle`.
4058      *
4059      * @private
4060      * @param {Array|Object} collection The collection to shuffle.
4061      * @returns {Array} Returns the new shuffled array.
4062      */
4063     function baseShuffle(collection) {
4064       return shuffleSelf(values(collection));
4065     }
4066
4067     /**
4068      * The base implementation of `_.slice` without an iteratee call guard.
4069      *
4070      * @private
4071      * @param {Array} array The array to slice.
4072      * @param {number} [start=0] The start position.
4073      * @param {number} [end=array.length] The end position.
4074      * @returns {Array} Returns the slice of `array`.
4075      */
4076     function baseSlice(array, start, end) {
4077       var index = -1,
4078           length = array.length;
4079
4080       if (start < 0) {
4081         start = -start > length ? 0 : (length + start);
4082       }
4083       end = end > length ? length : end;
4084       if (end < 0) {
4085         end += length;
4086       }
4087       length = start > end ? 0 : ((end - start) >>> 0);
4088       start >>>= 0;
4089
4090       var result = Array(length);
4091       while (++index < length) {
4092         result[index] = array[index + start];
4093       }
4094       return result;
4095     }
4096
4097     /**
4098      * The base implementation of `_.some` without support for iteratee shorthands.
4099      *
4100      * @private
4101      * @param {Array|Object} collection The collection to iterate over.
4102      * @param {Function} predicate The function invoked per iteration.
4103      * @returns {boolean} Returns `true` if any element passes the predicate check,
4104      *  else `false`.
4105      */
4106     function baseSome(collection, predicate) {
4107       var result;
4108
4109       baseEach(collection, function(value, index, collection) {
4110         result = predicate(value, index, collection);
4111         return !result;
4112       });
4113       return !!result;
4114     }
4115
4116     /**
4117      * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
4118      * performs a binary search of `array` to determine the index at which `value`
4119      * should be inserted into `array` in order to maintain its sort order.
4120      *
4121      * @private
4122      * @param {Array} array The sorted array to inspect.
4123      * @param {*} value The value to evaluate.
4124      * @param {boolean} [retHighest] Specify returning the highest qualified index.
4125      * @returns {number} Returns the index at which `value` should be inserted
4126      *  into `array`.
4127      */
4128     function baseSortedIndex(array, value, retHighest) {
4129       var low = 0,
4130           high = array == null ? low : array.length;
4131
4132       if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
4133         while (low < high) {
4134           var mid = (low + high) >>> 1,
4135               computed = array[mid];
4136
4137           if (computed !== null && !isSymbol(computed) &&
4138               (retHighest ? (computed <= value) : (computed < value))) {
4139             low = mid + 1;
4140           } else {
4141             high = mid;
4142           }
4143         }
4144         return high;
4145       }
4146       return baseSortedIndexBy(array, value, identity, retHighest);
4147     }
4148
4149     /**
4150      * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
4151      * which invokes `iteratee` for `value` and each element of `array` to compute
4152      * their sort ranking. The iteratee is invoked with one argument; (value).
4153      *
4154      * @private
4155      * @param {Array} array The sorted array to inspect.
4156      * @param {*} value The value to evaluate.
4157      * @param {Function} iteratee The iteratee invoked per element.
4158      * @param {boolean} [retHighest] Specify returning the highest qualified index.
4159      * @returns {number} Returns the index at which `value` should be inserted
4160      *  into `array`.
4161      */
4162     function baseSortedIndexBy(array, value, iteratee, retHighest) {
4163       value = iteratee(value);
4164
4165       var low = 0,
4166           high = array == null ? 0 : array.length,
4167           valIsNaN = value !== value,
4168           valIsNull = value === null,
4169           valIsSymbol = isSymbol(value),
4170           valIsUndefined = value === undefined;
4171
4172       while (low < high) {
4173         var mid = nativeFloor((low + high) / 2),
4174             computed = iteratee(array[mid]),
4175             othIsDefined = computed !== undefined,
4176             othIsNull = computed === null,
4177             othIsReflexive = computed === computed,
4178             othIsSymbol = isSymbol(computed);
4179
4180         if (valIsNaN) {
4181           var setLow = retHighest || othIsReflexive;
4182         } else if (valIsUndefined) {
4183           setLow = othIsReflexive && (retHighest || othIsDefined);
4184         } else if (valIsNull) {
4185           setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
4186         } else if (valIsSymbol) {
4187           setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
4188         } else if (othIsNull || othIsSymbol) {
4189           setLow = false;
4190         } else {
4191           setLow = retHighest ? (computed <= value) : (computed < value);
4192         }
4193         if (setLow) {
4194           low = mid + 1;
4195         } else {
4196           high = mid;
4197         }
4198       }
4199       return nativeMin(high, MAX_ARRAY_INDEX);
4200     }
4201
4202     /**
4203      * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
4204      * support for iteratee shorthands.
4205      *
4206      * @private
4207      * @param {Array} array The array to inspect.
4208      * @param {Function} [iteratee] The iteratee invoked per element.
4209      * @returns {Array} Returns the new duplicate free array.
4210      */
4211     function baseSortedUniq(array, iteratee) {
4212       var index = -1,
4213           length = array.length,
4214           resIndex = 0,
4215           result = [];
4216
4217       while (++index < length) {
4218         var value = array[index],
4219             computed = iteratee ? iteratee(value) : value;
4220
4221         if (!index || !eq(computed, seen)) {
4222           var seen = computed;
4223           result[resIndex++] = value === 0 ? 0 : value;
4224         }
4225       }
4226       return result;
4227     }
4228
4229     /**
4230      * The base implementation of `_.toNumber` which doesn't ensure correct
4231      * conversions of binary, hexadecimal, or octal string values.
4232      *
4233      * @private
4234      * @param {*} value The value to process.
4235      * @returns {number} Returns the number.
4236      */
4237     function baseToNumber(value) {
4238       if (typeof value == 'number') {
4239         return value;
4240       }
4241       if (isSymbol(value)) {
4242         return NAN;
4243       }
4244       return +value;
4245     }
4246
4247     /**
4248      * The base implementation of `_.toString` which doesn't convert nullish
4249      * values to empty strings.
4250      *
4251      * @private
4252      * @param {*} value The value to process.
4253      * @returns {string} Returns the string.
4254      */
4255     function baseToString(value) {
4256       // Exit early for strings to avoid a performance hit in some environments.
4257       if (typeof value == 'string') {
4258         return value;
4259       }
4260       if (isArray(value)) {
4261         // Recursively convert values (susceptible to call stack limits).
4262         return arrayMap(value, baseToString) + '';
4263       }
4264       if (isSymbol(value)) {
4265         return symbolToString ? symbolToString.call(value) : '';
4266       }
4267       var result = (value + '');
4268       return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
4269     }
4270
4271     /**
4272      * The base implementation of `_.uniqBy` without support for iteratee shorthands.
4273      *
4274      * @private
4275      * @param {Array} array The array to inspect.
4276      * @param {Function} [iteratee] The iteratee invoked per element.
4277      * @param {Function} [comparator] The comparator invoked per element.
4278      * @returns {Array} Returns the new duplicate free array.
4279      */
4280     function baseUniq(array, iteratee, comparator) {
4281       var index = -1,
4282           includes = arrayIncludes,
4283           length = array.length,
4284           isCommon = true,
4285           result = [],
4286           seen = result;
4287
4288       if (comparator) {
4289         isCommon = false;
4290         includes = arrayIncludesWith;
4291       }
4292       else if (length >= LARGE_ARRAY_SIZE) {
4293         var set = iteratee ? null : createSet(array);
4294         if (set) {
4295           return setToArray(set);
4296         }
4297         isCommon = false;
4298         includes = cacheHas;
4299         seen = new SetCache;
4300       }
4301       else {
4302         seen = iteratee ? [] : result;
4303       }
4304       outer:
4305       while (++index < length) {
4306         var value = array[index],
4307             computed = iteratee ? iteratee(value) : value;
4308
4309         value = (comparator || value !== 0) ? value : 0;
4310         if (isCommon && computed === computed) {
4311           var seenIndex = seen.length;
4312           while (seenIndex--) {
4313             if (seen[seenIndex] === computed) {
4314               continue outer;
4315             }
4316           }
4317           if (iteratee) {
4318             seen.push(computed);
4319           }
4320           result.push(value);
4321         }
4322         else if (!includes(seen, computed, comparator)) {
4323           if (seen !== result) {
4324             seen.push(computed);
4325           }
4326           result.push(value);
4327         }
4328       }
4329       return result;
4330     }
4331
4332     /**
4333      * The base implementation of `_.unset`.
4334      *
4335      * @private
4336      * @param {Object} object The object to modify.
4337      * @param {Array|string} path The property path to unset.
4338      * @returns {boolean} Returns `true` if the property is deleted, else `false`.
4339      */
4340     function baseUnset(object, path) {
4341       path = castPath(path, object);
4342       object = parent(object, path);
4343       return object == null || delete object[toKey(last(path))];
4344     }
4345
4346     /**
4347      * The base implementation of `_.update`.
4348      *
4349      * @private
4350      * @param {Object} object The object to modify.
4351      * @param {Array|string} path The path of the property to update.
4352      * @param {Function} updater The function to produce the updated value.
4353      * @param {Function} [customizer] The function to customize path creation.
4354      * @returns {Object} Returns `object`.
4355      */
4356     function baseUpdate(object, path, updater, customizer) {
4357       return baseSet(object, path, updater(baseGet(object, path)), customizer);
4358     }
4359
4360     /**
4361      * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
4362      * without support for iteratee shorthands.
4363      *
4364      * @private
4365      * @param {Array} array The array to query.
4366      * @param {Function} predicate The function invoked per iteration.
4367      * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
4368      * @param {boolean} [fromRight] Specify iterating from right to left.
4369      * @returns {Array} Returns the slice of `array`.
4370      */
4371     function baseWhile(array, predicate, isDrop, fromRight) {
4372       var length = array.length,
4373           index = fromRight ? length : -1;
4374
4375       while ((fromRight ? index-- : ++index < length) &&
4376         predicate(array[index], index, array)) {}
4377
4378       return isDrop
4379         ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
4380         : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
4381     }
4382
4383     /**
4384      * The base implementation of `wrapperValue` which returns the result of
4385      * performing a sequence of actions on the unwrapped `value`, where each
4386      * successive action is supplied the return value of the previous.
4387      *
4388      * @private
4389      * @param {*} value The unwrapped value.
4390      * @param {Array} actions Actions to perform to resolve the unwrapped value.
4391      * @returns {*} Returns the resolved value.
4392      */
4393     function baseWrapperValue(value, actions) {
4394       var result = value;
4395       if (result instanceof LazyWrapper) {
4396         result = result.value();
4397       }
4398       return arrayReduce(actions, function(result, action) {
4399         return action.func.apply(action.thisArg, arrayPush([result], action.args));
4400       }, result);
4401     }
4402
4403     /**
4404      * The base implementation of methods like `_.xor`, without support for
4405      * iteratee shorthands, that accepts an array of arrays to inspect.
4406      *
4407      * @private
4408      * @param {Array} arrays The arrays to inspect.
4409      * @param {Function} [iteratee] The iteratee invoked per element.
4410      * @param {Function} [comparator] The comparator invoked per element.
4411      * @returns {Array} Returns the new array of values.
4412      */
4413     function baseXor(arrays, iteratee, comparator) {
4414       var length = arrays.length;
4415       if (length < 2) {
4416         return length ? baseUniq(arrays[0]) : [];
4417       }
4418       var index = -1,
4419           result = Array(length);
4420
4421       while (++index < length) {
4422         var array = arrays[index],
4423             othIndex = -1;
4424
4425         while (++othIndex < length) {
4426           if (othIndex != index) {
4427             result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
4428           }
4429         }
4430       }
4431       return baseUniq(baseFlatten(result, 1), iteratee, comparator);
4432     }
4433
4434     /**
4435      * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
4436      *
4437      * @private
4438      * @param {Array} props The property identifiers.
4439      * @param {Array} values The property values.
4440      * @param {Function} assignFunc The function to assign values.
4441      * @returns {Object} Returns the new object.
4442      */
4443     function baseZipObject(props, values, assignFunc) {
4444       var index = -1,
4445           length = props.length,
4446           valsLength = values.length,
4447           result = {};
4448
4449       while (++index < length) {
4450         var value = index < valsLength ? values[index] : undefined;
4451         assignFunc(result, props[index], value);
4452       }
4453       return result;
4454     }
4455
4456     /**
4457      * Casts `value` to an empty array if it's not an array like object.
4458      *
4459      * @private
4460      * @param {*} value The value to inspect.
4461      * @returns {Array|Object} Returns the cast array-like object.
4462      */
4463     function castArrayLikeObject(value) {
4464       return isArrayLikeObject(value) ? value : [];
4465     }
4466
4467     /**
4468      * Casts `value` to `identity` if it's not a function.
4469      *
4470      * @private
4471      * @param {*} value The value to inspect.
4472      * @returns {Function} Returns cast function.
4473      */
4474     function castFunction(value) {
4475       return typeof value == 'function' ? value : identity;
4476     }
4477
4478     /**
4479      * Casts `value` to a path array if it's not one.
4480      *
4481      * @private
4482      * @param {*} value The value to inspect.
4483      * @param {Object} [object] The object to query keys on.
4484      * @returns {Array} Returns the cast property path array.
4485      */
4486     function castPath(value, object) {
4487       if (isArray(value)) {
4488         return value;
4489       }
4490       return isKey(value, object) ? [value] : stringToPath(toString(value));
4491     }
4492
4493     /**
4494      * A `baseRest` alias which can be replaced with `identity` by module
4495      * replacement plugins.
4496      *
4497      * @private
4498      * @type {Function}
4499      * @param {Function} func The function to apply a rest parameter to.
4500      * @returns {Function} Returns the new function.
4501      */
4502     var castRest = baseRest;
4503
4504     /**
4505      * Casts `array` to a slice if it's needed.
4506      *
4507      * @private
4508      * @param {Array} array The array to inspect.
4509      * @param {number} start The start position.
4510      * @param {number} [end=array.length] The end position.
4511      * @returns {Array} Returns the cast slice.
4512      */
4513     function castSlice(array, start, end) {
4514       var length = array.length;
4515       end = end === undefined ? length : end;
4516       return (!start && end >= length) ? array : baseSlice(array, start, end);
4517     }
4518
4519     /**
4520      * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
4521      *
4522      * @private
4523      * @param {number|Object} id The timer id or timeout object of the timer to clear.
4524      */
4525     var clearTimeout = ctxClearTimeout || function(id) {
4526       return root.clearTimeout(id);
4527     };
4528
4529     /**
4530      * Creates a clone of  `buffer`.
4531      *
4532      * @private
4533      * @param {Buffer} buffer The buffer to clone.
4534      * @param {boolean} [isDeep] Specify a deep clone.
4535      * @returns {Buffer} Returns the cloned buffer.
4536      */
4537     function cloneBuffer(buffer, isDeep) {
4538       if (isDeep) {
4539         return buffer.slice();
4540       }
4541       var length = buffer.length,
4542           result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
4543
4544       buffer.copy(result);
4545       return result;
4546     }
4547
4548     /**
4549      * Creates a clone of `arrayBuffer`.
4550      *
4551      * @private
4552      * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
4553      * @returns {ArrayBuffer} Returns the cloned array buffer.
4554      */
4555     function cloneArrayBuffer(arrayBuffer) {
4556       var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
4557       new Uint8Array(result).set(new Uint8Array(arrayBuffer));
4558       return result;
4559     }
4560
4561     /**
4562      * Creates a clone of `dataView`.
4563      *
4564      * @private
4565      * @param {Object} dataView The data view to clone.
4566      * @param {boolean} [isDeep] Specify a deep clone.
4567      * @returns {Object} Returns the cloned data view.
4568      */
4569     function cloneDataView(dataView, isDeep) {
4570       var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
4571       return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
4572     }
4573
4574     /**
4575      * Creates a clone of `map`.
4576      *
4577      * @private
4578      * @param {Object} map The map to clone.
4579      * @param {Function} cloneFunc The function to clone values.
4580      * @param {boolean} [isDeep] Specify a deep clone.
4581      * @returns {Object} Returns the cloned map.
4582      */
4583     function cloneMap(map, isDeep, cloneFunc) {
4584       var array = isDeep ? cloneFunc(mapToArray(map), CLONE_DEEP_FLAG) : mapToArray(map);
4585       return arrayReduce(array, addMapEntry, new map.constructor);
4586     }
4587
4588     /**
4589      * Creates a clone of `regexp`.
4590      *
4591      * @private
4592      * @param {Object} regexp The regexp to clone.
4593      * @returns {Object} Returns the cloned regexp.
4594      */
4595     function cloneRegExp(regexp) {
4596       var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
4597       result.lastIndex = regexp.lastIndex;
4598       return result;
4599     }
4600
4601     /**
4602      * Creates a clone of `set`.
4603      *
4604      * @private
4605      * @param {Object} set The set to clone.
4606      * @param {Function} cloneFunc The function to clone values.
4607      * @param {boolean} [isDeep] Specify a deep clone.
4608      * @returns {Object} Returns the cloned set.
4609      */
4610     function cloneSet(set, isDeep, cloneFunc) {
4611       var array = isDeep ? cloneFunc(setToArray(set), CLONE_DEEP_FLAG) : setToArray(set);
4612       return arrayReduce(array, addSetEntry, new set.constructor);
4613     }
4614
4615     /**
4616      * Creates a clone of the `symbol` object.
4617      *
4618      * @private
4619      * @param {Object} symbol The symbol object to clone.
4620      * @returns {Object} Returns the cloned symbol object.
4621      */
4622     function cloneSymbol(symbol) {
4623       return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
4624     }
4625
4626     /**
4627      * Creates a clone of `typedArray`.
4628      *
4629      * @private
4630      * @param {Object} typedArray The typed array to clone.
4631      * @param {boolean} [isDeep] Specify a deep clone.
4632      * @returns {Object} Returns the cloned typed array.
4633      */
4634     function cloneTypedArray(typedArray, isDeep) {
4635       var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
4636       return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
4637     }
4638
4639     /**
4640      * Compares values to sort them in ascending order.
4641      *
4642      * @private
4643      * @param {*} value The value to compare.
4644      * @param {*} other The other value to compare.
4645      * @returns {number} Returns the sort order indicator for `value`.
4646      */
4647     function compareAscending(value, other) {
4648       if (value !== other) {
4649         var valIsDefined = value !== undefined,
4650             valIsNull = value === null,
4651             valIsReflexive = value === value,
4652             valIsSymbol = isSymbol(value);
4653
4654         var othIsDefined = other !== undefined,
4655             othIsNull = other === null,
4656             othIsReflexive = other === other,
4657             othIsSymbol = isSymbol(other);
4658
4659         if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
4660             (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
4661             (valIsNull && othIsDefined && othIsReflexive) ||
4662             (!valIsDefined && othIsReflexive) ||
4663             !valIsReflexive) {
4664           return 1;
4665         }
4666         if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
4667             (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
4668             (othIsNull && valIsDefined && valIsReflexive) ||
4669             (!othIsDefined && valIsReflexive) ||
4670             !othIsReflexive) {
4671           return -1;
4672         }
4673       }
4674       return 0;
4675     }
4676
4677     /**
4678      * Used by `_.orderBy` to compare multiple properties of a value to another
4679      * and stable sort them.
4680      *
4681      * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
4682      * specify an order of "desc" for descending or "asc" for ascending sort order
4683      * of corresponding values.
4684      *
4685      * @private
4686      * @param {Object} object The object to compare.
4687      * @param {Object} other The other object to compare.
4688      * @param {boolean[]|string[]} orders The order to sort by for each property.
4689      * @returns {number} Returns the sort order indicator for `object`.
4690      */
4691     function compareMultiple(object, other, orders) {
4692       var index = -1,
4693           objCriteria = object.criteria,
4694           othCriteria = other.criteria,
4695           length = objCriteria.length,
4696           ordersLength = orders.length;
4697
4698       while (++index < length) {
4699         var result = compareAscending(objCriteria[index], othCriteria[index]);
4700         if (result) {
4701           if (index >= ordersLength) {
4702             return result;
4703           }
4704           var order = orders[index];
4705           return result * (order == 'desc' ? -1 : 1);
4706         }
4707       }
4708       // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
4709       // that causes it, under certain circumstances, to provide the same value for
4710       // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
4711       // for more details.
4712       //
4713       // This also ensures a stable sort in V8 and other engines.
4714       // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
4715       return object.index - other.index;
4716     }
4717
4718     /**
4719      * Creates an array that is the composition of partially applied arguments,
4720      * placeholders, and provided arguments into a single array of arguments.
4721      *
4722      * @private
4723      * @param {Array} args The provided arguments.
4724      * @param {Array} partials The arguments to prepend to those provided.
4725      * @param {Array} holders The `partials` placeholder indexes.
4726      * @params {boolean} [isCurried] Specify composing for a curried function.
4727      * @returns {Array} Returns the new array of composed arguments.
4728      */
4729     function composeArgs(args, partials, holders, isCurried) {
4730       var argsIndex = -1,
4731           argsLength = args.length,
4732           holdersLength = holders.length,
4733           leftIndex = -1,
4734           leftLength = partials.length,
4735           rangeLength = nativeMax(argsLength - holdersLength, 0),
4736           result = Array(leftLength + rangeLength),
4737           isUncurried = !isCurried;
4738
4739       while (++leftIndex < leftLength) {
4740         result[leftIndex] = partials[leftIndex];
4741       }
4742       while (++argsIndex < holdersLength) {
4743         if (isUncurried || argsIndex < argsLength) {
4744           result[holders[argsIndex]] = args[argsIndex];
4745         }
4746       }
4747       while (rangeLength--) {
4748         result[leftIndex++] = args[argsIndex++];
4749       }
4750       return result;
4751     }
4752
4753     /**
4754      * This function is like `composeArgs` except that the arguments composition
4755      * is tailored for `_.partialRight`.
4756      *
4757      * @private
4758      * @param {Array} args The provided arguments.
4759      * @param {Array} partials The arguments to append to those provided.
4760      * @param {Array} holders The `partials` placeholder indexes.
4761      * @params {boolean} [isCurried] Specify composing for a curried function.
4762      * @returns {Array} Returns the new array of composed arguments.
4763      */
4764     function composeArgsRight(args, partials, holders, isCurried) {
4765       var argsIndex = -1,
4766           argsLength = args.length,
4767           holdersIndex = -1,
4768           holdersLength = holders.length,
4769           rightIndex = -1,
4770           rightLength = partials.length,
4771           rangeLength = nativeMax(argsLength - holdersLength, 0),
4772           result = Array(rangeLength + rightLength),
4773           isUncurried = !isCurried;
4774
4775       while (++argsIndex < rangeLength) {
4776         result[argsIndex] = args[argsIndex];
4777       }
4778       var offset = argsIndex;
4779       while (++rightIndex < rightLength) {
4780         result[offset + rightIndex] = partials[rightIndex];
4781       }
4782       while (++holdersIndex < holdersLength) {
4783         if (isUncurried || argsIndex < argsLength) {
4784           result[offset + holders[holdersIndex]] = args[argsIndex++];
4785         }
4786       }
4787       return result;
4788     }
4789
4790     /**
4791      * Copies the values of `source` to `array`.
4792      *
4793      * @private
4794      * @param {Array} source The array to copy values from.
4795      * @param {Array} [array=[]] The array to copy values to.
4796      * @returns {Array} Returns `array`.
4797      */
4798     function copyArray(source, array) {
4799       var index = -1,
4800           length = source.length;
4801
4802       array || (array = Array(length));
4803       while (++index < length) {
4804         array[index] = source[index];
4805       }
4806       return array;
4807     }
4808
4809     /**
4810      * Copies properties of `source` to `object`.
4811      *
4812      * @private
4813      * @param {Object} source The object to copy properties from.
4814      * @param {Array} props The property identifiers to copy.
4815      * @param {Object} [object={}] The object to copy properties to.
4816      * @param {Function} [customizer] The function to customize copied values.
4817      * @returns {Object} Returns `object`.
4818      */
4819     function copyObject(source, props, object, customizer) {
4820       var isNew = !object;
4821       object || (object = {});
4822
4823       var index = -1,
4824           length = props.length;
4825
4826       while (++index < length) {
4827         var key = props[index];
4828
4829         var newValue = customizer
4830           ? customizer(object[key], source[key], key, object, source)
4831           : undefined;
4832
4833         if (newValue === undefined) {
4834           newValue = source[key];
4835         }
4836         if (isNew) {
4837           baseAssignValue(object, key, newValue);
4838         } else {
4839           assignValue(object, key, newValue);
4840         }
4841       }
4842       return object;
4843     }
4844
4845     /**
4846      * Copies own symbols of `source` to `object`.
4847      *
4848      * @private
4849      * @param {Object} source The object to copy symbols from.
4850      * @param {Object} [object={}] The object to copy symbols to.
4851      * @returns {Object} Returns `object`.
4852      */
4853     function copySymbols(source, object) {
4854       return copyObject(source, getSymbols(source), object);
4855     }
4856
4857     /**
4858      * Copies own and inherited symbols of `source` to `object`.
4859      *
4860      * @private
4861      * @param {Object} source The object to copy symbols from.
4862      * @param {Object} [object={}] The object to copy symbols to.
4863      * @returns {Object} Returns `object`.
4864      */
4865     function copySymbolsIn(source, object) {
4866       return copyObject(source, getSymbolsIn(source), object);
4867     }
4868
4869     /**
4870      * Creates a function like `_.groupBy`.
4871      *
4872      * @private
4873      * @param {Function} setter The function to set accumulator values.
4874      * @param {Function} [initializer] The accumulator object initializer.
4875      * @returns {Function} Returns the new aggregator function.
4876      */
4877     function createAggregator(setter, initializer) {
4878       return function(collection, iteratee) {
4879         var func = isArray(collection) ? arrayAggregator : baseAggregator,
4880             accumulator = initializer ? initializer() : {};
4881
4882         return func(collection, setter, getIteratee(iteratee, 2), accumulator);
4883       };
4884     }
4885
4886     /**
4887      * Creates a function like `_.assign`.
4888      *
4889      * @private
4890      * @param {Function} assigner The function to assign values.
4891      * @returns {Function} Returns the new assigner function.
4892      */
4893     function createAssigner(assigner) {
4894       return baseRest(function(object, sources) {
4895         var index = -1,
4896             length = sources.length,
4897             customizer = length > 1 ? sources[length - 1] : undefined,
4898             guard = length > 2 ? sources[2] : undefined;
4899
4900         customizer = (assigner.length > 3 && typeof customizer == 'function')
4901           ? (length--, customizer)
4902           : undefined;
4903
4904         if (guard && isIterateeCall(sources[0], sources[1], guard)) {
4905           customizer = length < 3 ? undefined : customizer;
4906           length = 1;
4907         }
4908         object = Object(object);
4909         while (++index < length) {
4910           var source = sources[index];
4911           if (source) {
4912             assigner(object, source, index, customizer);
4913           }
4914         }
4915         return object;
4916       });
4917     }
4918
4919     /**
4920      * Creates a `baseEach` or `baseEachRight` function.
4921      *
4922      * @private
4923      * @param {Function} eachFunc The function to iterate over a collection.
4924      * @param {boolean} [fromRight] Specify iterating from right to left.
4925      * @returns {Function} Returns the new base function.
4926      */
4927     function createBaseEach(eachFunc, fromRight) {
4928       return function(collection, iteratee) {
4929         if (collection == null) {
4930           return collection;
4931         }
4932         if (!isArrayLike(collection)) {
4933           return eachFunc(collection, iteratee);
4934         }
4935         var length = collection.length,
4936             index = fromRight ? length : -1,
4937             iterable = Object(collection);
4938
4939         while ((fromRight ? index-- : ++index < length)) {
4940           if (iteratee(iterable[index], index, iterable) === false) {
4941             break;
4942           }
4943         }
4944         return collection;
4945       };
4946     }
4947
4948     /**
4949      * Creates a base function for methods like `_.forIn` and `_.forOwn`.
4950      *
4951      * @private
4952      * @param {boolean} [fromRight] Specify iterating from right to left.
4953      * @returns {Function} Returns the new base function.
4954      */
4955     function createBaseFor(fromRight) {
4956       return function(object, iteratee, keysFunc) {
4957         var index = -1,
4958             iterable = Object(object),
4959             props = keysFunc(object),
4960             length = props.length;
4961
4962         while (length--) {
4963           var key = props[fromRight ? length : ++index];
4964           if (iteratee(iterable[key], key, iterable) === false) {
4965             break;
4966           }
4967         }
4968         return object;
4969       };
4970     }
4971
4972     /**
4973      * Creates a function that wraps `func` to invoke it with the optional `this`
4974      * binding of `thisArg`.
4975      *
4976      * @private
4977      * @param {Function} func The function to wrap.
4978      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
4979      * @param {*} [thisArg] The `this` binding of `func`.
4980      * @returns {Function} Returns the new wrapped function.
4981      */
4982     function createBind(func, bitmask, thisArg) {
4983       var isBind = bitmask & WRAP_BIND_FLAG,
4984           Ctor = createCtor(func);
4985
4986       function wrapper() {
4987         var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
4988         return fn.apply(isBind ? thisArg : this, arguments);
4989       }
4990       return wrapper;
4991     }
4992
4993     /**
4994      * Creates a function like `_.lowerFirst`.
4995      *
4996      * @private
4997      * @param {string} methodName The name of the `String` case method to use.
4998      * @returns {Function} Returns the new case function.
4999      */
5000     function createCaseFirst(methodName) {
5001       return function(string) {
5002         string = toString(string);
5003
5004         var strSymbols = hasUnicode(string)
5005           ? stringToArray(string)
5006           : undefined;
5007
5008         var chr = strSymbols
5009           ? strSymbols[0]
5010           : string.charAt(0);
5011
5012         var trailing = strSymbols
5013           ? castSlice(strSymbols, 1).join('')
5014           : string.slice(1);
5015
5016         return chr[methodName]() + trailing;
5017       };
5018     }
5019
5020     /**
5021      * Creates a function like `_.camelCase`.
5022      *
5023      * @private
5024      * @param {Function} callback The function to combine each word.
5025      * @returns {Function} Returns the new compounder function.
5026      */
5027     function createCompounder(callback) {
5028       return function(string) {
5029         return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
5030       };
5031     }
5032
5033     /**
5034      * Creates a function that produces an instance of `Ctor` regardless of
5035      * whether it was invoked as part of a `new` expression or by `call` or `apply`.
5036      *
5037      * @private
5038      * @param {Function} Ctor The constructor to wrap.
5039      * @returns {Function} Returns the new wrapped function.
5040      */
5041     function createCtor(Ctor) {
5042       return function() {
5043         // Use a `switch` statement to work with class constructors. See
5044         // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
5045         // for more details.
5046         var args = arguments;
5047         switch (args.length) {
5048           case 0: return new Ctor;
5049           case 1: return new Ctor(args[0]);
5050           case 2: return new Ctor(args[0], args[1]);
5051           case 3: return new Ctor(args[0], args[1], args[2]);
5052           case 4: return new Ctor(args[0], args[1], args[2], args[3]);
5053           case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
5054           case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
5055           case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
5056         }
5057         var thisBinding = baseCreate(Ctor.prototype),
5058             result = Ctor.apply(thisBinding, args);
5059
5060         // Mimic the constructor's `return` behavior.
5061         // See https://es5.github.io/#x13.2.2 for more details.
5062         return isObject(result) ? result : thisBinding;
5063       };
5064     }
5065
5066     /**
5067      * Creates a function that wraps `func` to enable currying.
5068      *
5069      * @private
5070      * @param {Function} func The function to wrap.
5071      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5072      * @param {number} arity The arity of `func`.
5073      * @returns {Function} Returns the new wrapped function.
5074      */
5075     function createCurry(func, bitmask, arity) {
5076       var Ctor = createCtor(func);
5077
5078       function wrapper() {
5079         var length = arguments.length,
5080             args = Array(length),
5081             index = length,
5082             placeholder = getHolder(wrapper);
5083
5084         while (index--) {
5085           args[index] = arguments[index];
5086         }
5087         var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
5088           ? []
5089           : replaceHolders(args, placeholder);
5090
5091         length -= holders.length;
5092         if (length < arity) {
5093           return createRecurry(
5094             func, bitmask, createHybrid, wrapper.placeholder, undefined,
5095             args, holders, undefined, undefined, arity - length);
5096         }
5097         var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
5098         return apply(fn, this, args);
5099       }
5100       return wrapper;
5101     }
5102
5103     /**
5104      * Creates a `_.find` or `_.findLast` function.
5105      *
5106      * @private
5107      * @param {Function} findIndexFunc The function to find the collection index.
5108      * @returns {Function} Returns the new find function.
5109      */
5110     function createFind(findIndexFunc) {
5111       return function(collection, predicate, fromIndex) {
5112         var iterable = Object(collection);
5113         if (!isArrayLike(collection)) {
5114           var iteratee = getIteratee(predicate, 3);
5115           collection = keys(collection);
5116           predicate = function(key) { return iteratee(iterable[key], key, iterable); };
5117         }
5118         var index = findIndexFunc(collection, predicate, fromIndex);
5119         return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
5120       };
5121     }
5122
5123     /**
5124      * Creates a `_.flow` or `_.flowRight` function.
5125      *
5126      * @private
5127      * @param {boolean} [fromRight] Specify iterating from right to left.
5128      * @returns {Function} Returns the new flow function.
5129      */
5130     function createFlow(fromRight) {
5131       return flatRest(function(funcs) {
5132         var length = funcs.length,
5133             index = length,
5134             prereq = LodashWrapper.prototype.thru;
5135
5136         if (fromRight) {
5137           funcs.reverse();
5138         }
5139         while (index--) {
5140           var func = funcs[index];
5141           if (typeof func != 'function') {
5142             throw new TypeError(FUNC_ERROR_TEXT);
5143           }
5144           if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
5145             var wrapper = new LodashWrapper([], true);
5146           }
5147         }
5148         index = wrapper ? index : length;
5149         while (++index < length) {
5150           func = funcs[index];
5151
5152           var funcName = getFuncName(func),
5153               data = funcName == 'wrapper' ? getData(func) : undefined;
5154
5155           if (data && isLaziable(data[0]) &&
5156                 data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
5157                 !data[4].length && data[9] == 1
5158               ) {
5159             wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
5160           } else {
5161             wrapper = (func.length == 1 && isLaziable(func))
5162               ? wrapper[funcName]()
5163               : wrapper.thru(func);
5164           }
5165         }
5166         return function() {
5167           var args = arguments,
5168               value = args[0];
5169
5170           if (wrapper && args.length == 1 && isArray(value)) {
5171             return wrapper.plant(value).value();
5172           }
5173           var index = 0,
5174               result = length ? funcs[index].apply(this, args) : value;
5175
5176           while (++index < length) {
5177             result = funcs[index].call(this, result);
5178           }
5179           return result;
5180         };
5181       });
5182     }
5183
5184     /**
5185      * Creates a function that wraps `func` to invoke it with optional `this`
5186      * binding of `thisArg`, partial application, and currying.
5187      *
5188      * @private
5189      * @param {Function|string} func The function or method name to wrap.
5190      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5191      * @param {*} [thisArg] The `this` binding of `func`.
5192      * @param {Array} [partials] The arguments to prepend to those provided to
5193      *  the new function.
5194      * @param {Array} [holders] The `partials` placeholder indexes.
5195      * @param {Array} [partialsRight] The arguments to append to those provided
5196      *  to the new function.
5197      * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
5198      * @param {Array} [argPos] The argument positions of the new function.
5199      * @param {number} [ary] The arity cap of `func`.
5200      * @param {number} [arity] The arity of `func`.
5201      * @returns {Function} Returns the new wrapped function.
5202      */
5203     function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
5204       var isAry = bitmask & WRAP_ARY_FLAG,
5205           isBind = bitmask & WRAP_BIND_FLAG,
5206           isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
5207           isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
5208           isFlip = bitmask & WRAP_FLIP_FLAG,
5209           Ctor = isBindKey ? undefined : createCtor(func);
5210
5211       function wrapper() {
5212         var length = arguments.length,
5213             args = Array(length),
5214             index = length;
5215
5216         while (index--) {
5217           args[index] = arguments[index];
5218         }
5219         if (isCurried) {
5220           var placeholder = getHolder(wrapper),
5221               holdersCount = countHolders(args, placeholder);
5222         }
5223         if (partials) {
5224           args = composeArgs(args, partials, holders, isCurried);
5225         }
5226         if (partialsRight) {
5227           args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
5228         }
5229         length -= holdersCount;
5230         if (isCurried && length < arity) {
5231           var newHolders = replaceHolders(args, placeholder);
5232           return createRecurry(
5233             func, bitmask, createHybrid, wrapper.placeholder, thisArg,
5234             args, newHolders, argPos, ary, arity - length
5235           );
5236         }
5237         var thisBinding = isBind ? thisArg : this,
5238             fn = isBindKey ? thisBinding[func] : func;
5239
5240         length = args.length;
5241         if (argPos) {
5242           args = reorder(args, argPos);
5243         } else if (isFlip && length > 1) {
5244           args.reverse();
5245         }
5246         if (isAry && ary < length) {
5247           args.length = ary;
5248         }
5249         if (this && this !== root && this instanceof wrapper) {
5250           fn = Ctor || createCtor(fn);
5251         }
5252         return fn.apply(thisBinding, args);
5253       }
5254       return wrapper;
5255     }
5256
5257     /**
5258      * Creates a function like `_.invertBy`.
5259      *
5260      * @private
5261      * @param {Function} setter The function to set accumulator values.
5262      * @param {Function} toIteratee The function to resolve iteratees.
5263      * @returns {Function} Returns the new inverter function.
5264      */
5265     function createInverter(setter, toIteratee) {
5266       return function(object, iteratee) {
5267         return baseInverter(object, setter, toIteratee(iteratee), {});
5268       };
5269     }
5270
5271     /**
5272      * Creates a function that performs a mathematical operation on two values.
5273      *
5274      * @private
5275      * @param {Function} operator The function to perform the operation.
5276      * @param {number} [defaultValue] The value used for `undefined` arguments.
5277      * @returns {Function} Returns the new mathematical operation function.
5278      */
5279     function createMathOperation(operator, defaultValue) {
5280       return function(value, other) {
5281         var result;
5282         if (value === undefined && other === undefined) {
5283           return defaultValue;
5284         }
5285         if (value !== undefined) {
5286           result = value;
5287         }
5288         if (other !== undefined) {
5289           if (result === undefined) {
5290             return other;
5291           }
5292           if (typeof value == 'string' || typeof other == 'string') {
5293             value = baseToString(value);
5294             other = baseToString(other);
5295           } else {
5296             value = baseToNumber(value);
5297             other = baseToNumber(other);
5298           }
5299           result = operator(value, other);
5300         }
5301         return result;
5302       };
5303     }
5304
5305     /**
5306      * Creates a function like `_.over`.
5307      *
5308      * @private
5309      * @param {Function} arrayFunc The function to iterate over iteratees.
5310      * @returns {Function} Returns the new over function.
5311      */
5312     function createOver(arrayFunc) {
5313       return flatRest(function(iteratees) {
5314         iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
5315         return baseRest(function(args) {
5316           var thisArg = this;
5317           return arrayFunc(iteratees, function(iteratee) {
5318             return apply(iteratee, thisArg, args);
5319           });
5320         });
5321       });
5322     }
5323
5324     /**
5325      * Creates the padding for `string` based on `length`. The `chars` string
5326      * is truncated if the number of characters exceeds `length`.
5327      *
5328      * @private
5329      * @param {number} length The padding length.
5330      * @param {string} [chars=' '] The string used as padding.
5331      * @returns {string} Returns the padding for `string`.
5332      */
5333     function createPadding(length, chars) {
5334       chars = chars === undefined ? ' ' : baseToString(chars);
5335
5336       var charsLength = chars.length;
5337       if (charsLength < 2) {
5338         return charsLength ? baseRepeat(chars, length) : chars;
5339       }
5340       var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
5341       return hasUnicode(chars)
5342         ? castSlice(stringToArray(result), 0, length).join('')
5343         : result.slice(0, length);
5344     }
5345
5346     /**
5347      * Creates a function that wraps `func` to invoke it with the `this` binding
5348      * of `thisArg` and `partials` prepended to the arguments it receives.
5349      *
5350      * @private
5351      * @param {Function} func The function to wrap.
5352      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5353      * @param {*} thisArg The `this` binding of `func`.
5354      * @param {Array} partials The arguments to prepend to those provided to
5355      *  the new function.
5356      * @returns {Function} Returns the new wrapped function.
5357      */
5358     function createPartial(func, bitmask, thisArg, partials) {
5359       var isBind = bitmask & WRAP_BIND_FLAG,
5360           Ctor = createCtor(func);
5361
5362       function wrapper() {
5363         var argsIndex = -1,
5364             argsLength = arguments.length,
5365             leftIndex = -1,
5366             leftLength = partials.length,
5367             args = Array(leftLength + argsLength),
5368             fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
5369
5370         while (++leftIndex < leftLength) {
5371           args[leftIndex] = partials[leftIndex];
5372         }
5373         while (argsLength--) {
5374           args[leftIndex++] = arguments[++argsIndex];
5375         }
5376         return apply(fn, isBind ? thisArg : this, args);
5377       }
5378       return wrapper;
5379     }
5380
5381     /**
5382      * Creates a `_.range` or `_.rangeRight` function.
5383      *
5384      * @private
5385      * @param {boolean} [fromRight] Specify iterating from right to left.
5386      * @returns {Function} Returns the new range function.
5387      */
5388     function createRange(fromRight) {
5389       return function(start, end, step) {
5390         if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
5391           end = step = undefined;
5392         }
5393         // Ensure the sign of `-0` is preserved.
5394         start = toFinite(start);
5395         if (end === undefined) {
5396           end = start;
5397           start = 0;
5398         } else {
5399           end = toFinite(end);
5400         }
5401         step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
5402         return baseRange(start, end, step, fromRight);
5403       };
5404     }
5405
5406     /**
5407      * Creates a function that performs a relational operation on two values.
5408      *
5409      * @private
5410      * @param {Function} operator The function to perform the operation.
5411      * @returns {Function} Returns the new relational operation function.
5412      */
5413     function createRelationalOperation(operator) {
5414       return function(value, other) {
5415         if (!(typeof value == 'string' && typeof other == 'string')) {
5416           value = toNumber(value);
5417           other = toNumber(other);
5418         }
5419         return operator(value, other);
5420       };
5421     }
5422
5423     /**
5424      * Creates a function that wraps `func` to continue currying.
5425      *
5426      * @private
5427      * @param {Function} func The function to wrap.
5428      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5429      * @param {Function} wrapFunc The function to create the `func` wrapper.
5430      * @param {*} placeholder The placeholder value.
5431      * @param {*} [thisArg] The `this` binding of `func`.
5432      * @param {Array} [partials] The arguments to prepend to those provided to
5433      *  the new function.
5434      * @param {Array} [holders] The `partials` placeholder indexes.
5435      * @param {Array} [argPos] The argument positions of the new function.
5436      * @param {number} [ary] The arity cap of `func`.
5437      * @param {number} [arity] The arity of `func`.
5438      * @returns {Function} Returns the new wrapped function.
5439      */
5440     function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
5441       var isCurry = bitmask & WRAP_CURRY_FLAG,
5442           newHolders = isCurry ? holders : undefined,
5443           newHoldersRight = isCurry ? undefined : holders,
5444           newPartials = isCurry ? partials : undefined,
5445           newPartialsRight = isCurry ? undefined : partials;
5446
5447       bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
5448       bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);
5449
5450       if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
5451         bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
5452       }
5453       var newData = [
5454         func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
5455         newHoldersRight, argPos, ary, arity
5456       ];
5457
5458       var result = wrapFunc.apply(undefined, newData);
5459       if (isLaziable(func)) {
5460         setData(result, newData);
5461       }
5462       result.placeholder = placeholder;
5463       return setWrapToString(result, func, bitmask);
5464     }
5465
5466     /**
5467      * Creates a function like `_.round`.
5468      *
5469      * @private
5470      * @param {string} methodName The name of the `Math` method to use when rounding.
5471      * @returns {Function} Returns the new round function.
5472      */
5473     function createRound(methodName) {
5474       var func = Math[methodName];
5475       return function(number, precision) {
5476         number = toNumber(number);
5477         precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
5478         if (precision) {
5479           // Shift with exponential notation to avoid floating-point issues.
5480           // See [MDN](https://mdn.io/round#Examples) for more details.
5481           var pair = (toString(number) + 'e').split('e'),
5482               value = func(pair[0] + 'e' + (+pair[1] + precision));
5483
5484           pair = (toString(value) + 'e').split('e');
5485           return +(pair[0] + 'e' + (+pair[1] - precision));
5486         }
5487         return func(number);
5488       };
5489     }
5490
5491     /**
5492      * Creates a set object of `values`.
5493      *
5494      * @private
5495      * @param {Array} values The values to add to the set.
5496      * @returns {Object} Returns the new set.
5497      */
5498     var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
5499       return new Set(values);
5500     };
5501
5502     /**
5503      * Creates a `_.toPairs` or `_.toPairsIn` function.
5504      *
5505      * @private
5506      * @param {Function} keysFunc The function to get the keys of a given object.
5507      * @returns {Function} Returns the new pairs function.
5508      */
5509     function createToPairs(keysFunc) {
5510       return function(object) {
5511         var tag = getTag(object);
5512         if (tag == mapTag) {
5513           return mapToArray(object);
5514         }
5515         if (tag == setTag) {
5516           return setToPairs(object);
5517         }
5518         return baseToPairs(object, keysFunc(object));
5519       };
5520     }
5521
5522     /**
5523      * Creates a function that either curries or invokes `func` with optional
5524      * `this` binding and partially applied arguments.
5525      *
5526      * @private
5527      * @param {Function|string} func The function or method name to wrap.
5528      * @param {number} bitmask The bitmask flags.
5529      *    1 - `_.bind`
5530      *    2 - `_.bindKey`
5531      *    4 - `_.curry` or `_.curryRight` of a bound function
5532      *    8 - `_.curry`
5533      *   16 - `_.curryRight`
5534      *   32 - `_.partial`
5535      *   64 - `_.partialRight`
5536      *  128 - `_.rearg`
5537      *  256 - `_.ary`
5538      *  512 - `_.flip`
5539      * @param {*} [thisArg] The `this` binding of `func`.
5540      * @param {Array} [partials] The arguments to be partially applied.
5541      * @param {Array} [holders] The `partials` placeholder indexes.
5542      * @param {Array} [argPos] The argument positions of the new function.
5543      * @param {number} [ary] The arity cap of `func`.
5544      * @param {number} [arity] The arity of `func`.
5545      * @returns {Function} Returns the new wrapped function.
5546      */
5547     function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
5548       var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
5549       if (!isBindKey && typeof func != 'function') {
5550         throw new TypeError(FUNC_ERROR_TEXT);
5551       }
5552       var length = partials ? partials.length : 0;
5553       if (!length) {
5554         bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
5555         partials = holders = undefined;
5556       }
5557       ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
5558       arity = arity === undefined ? arity : toInteger(arity);
5559       length -= holders ? holders.length : 0;
5560
5561       if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
5562         var partialsRight = partials,
5563             holdersRight = holders;
5564
5565         partials = holders = undefined;
5566       }
5567       var data = isBindKey ? undefined : getData(func);
5568
5569       var newData = [
5570         func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
5571         argPos, ary, arity
5572       ];
5573
5574       if (data) {
5575         mergeData(newData, data);
5576       }
5577       func = newData[0];
5578       bitmask = newData[1];
5579       thisArg = newData[2];
5580       partials = newData[3];
5581       holders = newData[4];
5582       arity = newData[9] = newData[9] === undefined
5583         ? (isBindKey ? 0 : func.length)
5584         : nativeMax(newData[9] - length, 0);
5585
5586       if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
5587         bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
5588       }
5589       if (!bitmask || bitmask == WRAP_BIND_FLAG) {
5590         var result = createBind(func, bitmask, thisArg);
5591       } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
5592         result = createCurry(func, bitmask, arity);
5593       } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) {
5594         result = createPartial(func, bitmask, thisArg, partials);
5595       } else {
5596         result = createHybrid.apply(undefined, newData);
5597       }
5598       var setter = data ? baseSetData : setData;
5599       return setWrapToString(setter(result, newData), func, bitmask);
5600     }
5601
5602     /**
5603      * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
5604      * of source objects to the destination object for all destination properties
5605      * that resolve to `undefined`.
5606      *
5607      * @private
5608      * @param {*} objValue The destination value.
5609      * @param {*} srcValue The source value.
5610      * @param {string} key The key of the property to assign.
5611      * @param {Object} object The parent object of `objValue`.
5612      * @returns {*} Returns the value to assign.
5613      */
5614     function customDefaultsAssignIn(objValue, srcValue, key, object) {
5615       if (objValue === undefined ||
5616           (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
5617         return srcValue;
5618       }
5619       return objValue;
5620     }
5621
5622     /**
5623      * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
5624      * objects into destination objects that are passed thru.
5625      *
5626      * @private
5627      * @param {*} objValue The destination value.
5628      * @param {*} srcValue The source value.
5629      * @param {string} key The key of the property to merge.
5630      * @param {Object} object The parent object of `objValue`.
5631      * @param {Object} source The parent object of `srcValue`.
5632      * @param {Object} [stack] Tracks traversed source values and their merged
5633      *  counterparts.
5634      * @returns {*} Returns the value to assign.
5635      */
5636     function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
5637       if (isObject(objValue) && isObject(srcValue)) {
5638         // Recursively merge objects and arrays (susceptible to call stack limits).
5639         stack.set(srcValue, objValue);
5640         baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
5641         stack['delete'](srcValue);
5642       }
5643       return objValue;
5644     }
5645
5646     /**
5647      * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
5648      * objects.
5649      *
5650      * @private
5651      * @param {*} value The value to inspect.
5652      * @param {string} key The key of the property to inspect.
5653      * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
5654      */
5655     function customOmitClone(value) {
5656       return isPlainObject(value) ? undefined : value;
5657     }
5658
5659     /**
5660      * A specialized version of `baseIsEqualDeep` for arrays with support for
5661      * partial deep comparisons.
5662      *
5663      * @private
5664      * @param {Array} array The array to compare.
5665      * @param {Array} other The other array to compare.
5666      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5667      * @param {Function} customizer The function to customize comparisons.
5668      * @param {Function} equalFunc The function to determine equivalents of values.
5669      * @param {Object} stack Tracks traversed `array` and `other` objects.
5670      * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
5671      */
5672     function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
5673       var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
5674           arrLength = array.length,
5675           othLength = other.length;
5676
5677       if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
5678         return false;
5679       }
5680       // Assume cyclic values are equal.
5681       var stacked = stack.get(array);
5682       if (stacked && stack.get(other)) {
5683         return stacked == other;
5684       }
5685       var index = -1,
5686           result = true,
5687           seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;
5688
5689       stack.set(array, other);
5690       stack.set(other, array);
5691
5692       // Ignore non-index properties.
5693       while (++index < arrLength) {
5694         var arrValue = array[index],
5695             othValue = other[index];
5696
5697         if (customizer) {
5698           var compared = isPartial
5699             ? customizer(othValue, arrValue, index, other, array, stack)
5700             : customizer(arrValue, othValue, index, array, other, stack);
5701         }
5702         if (compared !== undefined) {
5703           if (compared) {
5704             continue;
5705           }
5706           result = false;
5707           break;
5708         }
5709         // Recursively compare arrays (susceptible to call stack limits).
5710         if (seen) {
5711           if (!arraySome(other, function(othValue, othIndex) {
5712                 if (!cacheHas(seen, othIndex) &&
5713                     (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
5714                   return seen.push(othIndex);
5715                 }
5716               })) {
5717             result = false;
5718             break;
5719           }
5720         } else if (!(
5721               arrValue === othValue ||
5722                 equalFunc(arrValue, othValue, bitmask, customizer, stack)
5723             )) {
5724           result = false;
5725           break;
5726         }
5727       }
5728       stack['delete'](array);
5729       stack['delete'](other);
5730       return result;
5731     }
5732
5733     /**
5734      * A specialized version of `baseIsEqualDeep` for comparing objects of
5735      * the same `toStringTag`.
5736      *
5737      * **Note:** This function only supports comparing values with tags of
5738      * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
5739      *
5740      * @private
5741      * @param {Object} object The object to compare.
5742      * @param {Object} other The other object to compare.
5743      * @param {string} tag The `toStringTag` of the objects to compare.
5744      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5745      * @param {Function} customizer The function to customize comparisons.
5746      * @param {Function} equalFunc The function to determine equivalents of values.
5747      * @param {Object} stack Tracks traversed `object` and `other` objects.
5748      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
5749      */
5750     function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
5751       switch (tag) {
5752         case dataViewTag:
5753           if ((object.byteLength != other.byteLength) ||
5754               (object.byteOffset != other.byteOffset)) {
5755             return false;
5756           }
5757           object = object.buffer;
5758           other = other.buffer;
5759
5760         case arrayBufferTag:
5761           if ((object.byteLength != other.byteLength) ||
5762               !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
5763             return false;
5764           }
5765           return true;
5766
5767         case boolTag:
5768         case dateTag:
5769         case numberTag:
5770           // Coerce booleans to `1` or `0` and dates to milliseconds.
5771           // Invalid dates are coerced to `NaN`.
5772           return eq(+object, +other);
5773
5774         case errorTag:
5775           return object.name == other.name && object.message == other.message;
5776
5777         case regexpTag:
5778         case stringTag:
5779           // Coerce regexes to strings and treat strings, primitives and objects,
5780           // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
5781           // for more details.
5782           return object == (other + '');
5783
5784         case mapTag:
5785           var convert = mapToArray;
5786
5787         case setTag:
5788           var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
5789           convert || (convert = setToArray);
5790
5791           if (object.size != other.size && !isPartial) {
5792             return false;
5793           }
5794           // Assume cyclic values are equal.
5795           var stacked = stack.get(object);
5796           if (stacked) {
5797             return stacked == other;
5798           }
5799           bitmask |= COMPARE_UNORDERED_FLAG;
5800
5801           // Recursively compare objects (susceptible to call stack limits).
5802           stack.set(object, other);
5803           var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
5804           stack['delete'](object);
5805           return result;
5806
5807         case symbolTag:
5808           if (symbolValueOf) {
5809             return symbolValueOf.call(object) == symbolValueOf.call(other);
5810           }
5811       }
5812       return false;
5813     }
5814
5815     /**
5816      * A specialized version of `baseIsEqualDeep` for objects with support for
5817      * partial deep comparisons.
5818      *
5819      * @private
5820      * @param {Object} object The object to compare.
5821      * @param {Object} other The other object to compare.
5822      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5823      * @param {Function} customizer The function to customize comparisons.
5824      * @param {Function} equalFunc The function to determine equivalents of values.
5825      * @param {Object} stack Tracks traversed `object` and `other` objects.
5826      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
5827      */
5828     function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
5829       var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
5830           objProps = getAllKeys(object),
5831           objLength = objProps.length,
5832           othProps = getAllKeys(other),
5833           othLength = othProps.length;
5834
5835       if (objLength != othLength && !isPartial) {
5836         return false;
5837       }
5838       var index = objLength;
5839       while (index--) {
5840         var key = objProps[index];
5841         if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
5842           return false;
5843         }
5844       }
5845       // Assume cyclic values are equal.
5846       var stacked = stack.get(object);
5847       if (stacked && stack.get(other)) {
5848         return stacked == other;
5849       }
5850       var result = true;
5851       stack.set(object, other);
5852       stack.set(other, object);
5853
5854       var skipCtor = isPartial;
5855       while (++index < objLength) {
5856         key = objProps[index];
5857         var objValue = object[key],
5858             othValue = other[key];
5859
5860         if (customizer) {
5861           var compared = isPartial
5862             ? customizer(othValue, objValue, key, other, object, stack)
5863             : customizer(objValue, othValue, key, object, other, stack);
5864         }
5865         // Recursively compare objects (susceptible to call stack limits).
5866         if (!(compared === undefined
5867               ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
5868               : compared
5869             )) {
5870           result = false;
5871           break;
5872         }
5873         skipCtor || (skipCtor = key == 'constructor');
5874       }
5875       if (result && !skipCtor) {
5876         var objCtor = object.constructor,
5877             othCtor = other.constructor;
5878
5879         // Non `Object` object instances with different constructors are not equal.
5880         if (objCtor != othCtor &&
5881             ('constructor' in object && 'constructor' in other) &&
5882             !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
5883               typeof othCtor == 'function' && othCtor instanceof othCtor)) {
5884           result = false;
5885         }
5886       }
5887       stack['delete'](object);
5888       stack['delete'](other);
5889       return result;
5890     }
5891
5892     /**
5893      * A specialized version of `baseRest` which flattens the rest array.
5894      *
5895      * @private
5896      * @param {Function} func The function to apply a rest parameter to.
5897      * @returns {Function} Returns the new function.
5898      */
5899     function flatRest(func) {
5900       return setToString(overRest(func, undefined, flatten), func + '');
5901     }
5902
5903     /**
5904      * Creates an array of own enumerable property names and symbols of `object`.
5905      *
5906      * @private
5907      * @param {Object} object The object to query.
5908      * @returns {Array} Returns the array of property names and symbols.
5909      */
5910     function getAllKeys(object) {
5911       return baseGetAllKeys(object, keys, getSymbols);
5912     }
5913
5914     /**
5915      * Creates an array of own and inherited enumerable property names and
5916      * symbols of `object`.
5917      *
5918      * @private
5919      * @param {Object} object The object to query.
5920      * @returns {Array} Returns the array of property names and symbols.
5921      */
5922     function getAllKeysIn(object) {
5923       return baseGetAllKeys(object, keysIn, getSymbolsIn);
5924     }
5925
5926     /**
5927      * Gets metadata for `func`.
5928      *
5929      * @private
5930      * @param {Function} func The function to query.
5931      * @returns {*} Returns the metadata for `func`.
5932      */
5933     var getData = !metaMap ? noop : function(func) {
5934       return metaMap.get(func);
5935     };
5936
5937     /**
5938      * Gets the name of `func`.
5939      *
5940      * @private
5941      * @param {Function} func The function to query.
5942      * @returns {string} Returns the function name.
5943      */
5944     function getFuncName(func) {
5945       var result = (func.name + ''),
5946           array = realNames[result],
5947           length = hasOwnProperty.call(realNames, result) ? array.length : 0;
5948
5949       while (length--) {
5950         var data = array[length],
5951             otherFunc = data.func;
5952         if (otherFunc == null || otherFunc == func) {
5953           return data.name;
5954         }
5955       }
5956       return result;
5957     }
5958
5959     /**
5960      * Gets the argument placeholder value for `func`.
5961      *
5962      * @private
5963      * @param {Function} func The function to inspect.
5964      * @returns {*} Returns the placeholder value.
5965      */
5966     function getHolder(func) {
5967       var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
5968       return object.placeholder;
5969     }
5970
5971     /**
5972      * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
5973      * this function returns the custom method, otherwise it returns `baseIteratee`.
5974      * If arguments are provided, the chosen function is invoked with them and
5975      * its result is returned.
5976      *
5977      * @private
5978      * @param {*} [value] The value to convert to an iteratee.
5979      * @param {number} [arity] The arity of the created iteratee.
5980      * @returns {Function} Returns the chosen function or its result.
5981      */
5982     function getIteratee() {
5983       var result = lodash.iteratee || iteratee;
5984       result = result === iteratee ? baseIteratee : result;
5985       return arguments.length ? result(arguments[0], arguments[1]) : result;
5986     }
5987
5988     /**
5989      * Gets the data for `map`.
5990      *
5991      * @private
5992      * @param {Object} map The map to query.
5993      * @param {string} key The reference key.
5994      * @returns {*} Returns the map data.
5995      */
5996     function getMapData(map, key) {
5997       var data = map.__data__;
5998       return isKeyable(key)
5999         ? data[typeof key == 'string' ? 'string' : 'hash']
6000         : data.map;
6001     }
6002
6003     /**
6004      * Gets the property names, values, and compare flags of `object`.
6005      *
6006      * @private
6007      * @param {Object} object The object to query.
6008      * @returns {Array} Returns the match data of `object`.
6009      */
6010     function getMatchData(object) {
6011       var result = keys(object),
6012           length = result.length;
6013
6014       while (length--) {
6015         var key = result[length],
6016             value = object[key];
6017
6018         result[length] = [key, value, isStrictComparable(value)];
6019       }
6020       return result;
6021     }
6022
6023     /**
6024      * Gets the native function at `key` of `object`.
6025      *
6026      * @private
6027      * @param {Object} object The object to query.
6028      * @param {string} key The key of the method to get.
6029      * @returns {*} Returns the function if it's native, else `undefined`.
6030      */
6031     function getNative(object, key) {
6032       var value = getValue(object, key);
6033       return baseIsNative(value) ? value : undefined;
6034     }
6035
6036     /**
6037      * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
6038      *
6039      * @private
6040      * @param {*} value The value to query.
6041      * @returns {string} Returns the raw `toStringTag`.
6042      */
6043     function getRawTag(value) {
6044       var isOwn = hasOwnProperty.call(value, symToStringTag),
6045           tag = value[symToStringTag];
6046
6047       try {
6048         value[symToStringTag] = undefined;
6049         var unmasked = true;
6050       } catch (e) {}
6051
6052       var result = nativeObjectToString.call(value);
6053       if (unmasked) {
6054         if (isOwn) {
6055           value[symToStringTag] = tag;
6056         } else {
6057           delete value[symToStringTag];
6058         }
6059       }
6060       return result;
6061     }
6062
6063     /**
6064      * Creates an array of the own enumerable symbols of `object`.
6065      *
6066      * @private
6067      * @param {Object} object The object to query.
6068      * @returns {Array} Returns the array of symbols.
6069      */
6070     var getSymbols = !nativeGetSymbols ? stubArray : function(object) {
6071       if (object == null) {
6072         return [];
6073       }
6074       object = Object(object);
6075       return arrayFilter(nativeGetSymbols(object), function(symbol) {
6076         return propertyIsEnumerable.call(object, symbol);
6077       });
6078     };
6079
6080     /**
6081      * Creates an array of the own and inherited enumerable symbols of `object`.
6082      *
6083      * @private
6084      * @param {Object} object The object to query.
6085      * @returns {Array} Returns the array of symbols.
6086      */
6087     var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {
6088       var result = [];
6089       while (object) {
6090         arrayPush(result, getSymbols(object));
6091         object = getPrototype(object);
6092       }
6093       return result;
6094     };
6095
6096     /**
6097      * Gets the `toStringTag` of `value`.
6098      *
6099      * @private
6100      * @param {*} value The value to query.
6101      * @returns {string} Returns the `toStringTag`.
6102      */
6103     var getTag = baseGetTag;
6104
6105     // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
6106     if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
6107         (Map && getTag(new Map) != mapTag) ||
6108         (Promise && getTag(Promise.resolve()) != promiseTag) ||
6109         (Set && getTag(new Set) != setTag) ||
6110         (WeakMap && getTag(new WeakMap) != weakMapTag)) {
6111       getTag = function(value) {
6112         var result = baseGetTag(value),
6113             Ctor = result == objectTag ? value.constructor : undefined,
6114             ctorString = Ctor ? toSource(Ctor) : '';
6115
6116         if (ctorString) {
6117           switch (ctorString) {
6118             case dataViewCtorString: return dataViewTag;
6119             case mapCtorString: return mapTag;
6120             case promiseCtorString: return promiseTag;
6121             case setCtorString: return setTag;
6122             case weakMapCtorString: return weakMapTag;
6123           }
6124         }
6125         return result;
6126       };
6127     }
6128
6129     /**
6130      * Gets the view, applying any `transforms` to the `start` and `end` positions.
6131      *
6132      * @private
6133      * @param {number} start The start of the view.
6134      * @param {number} end The end of the view.
6135      * @param {Array} transforms The transformations to apply to the view.
6136      * @returns {Object} Returns an object containing the `start` and `end`
6137      *  positions of the view.
6138      */
6139     function getView(start, end, transforms) {
6140       var index = -1,
6141           length = transforms.length;
6142
6143       while (++index < length) {
6144         var data = transforms[index],
6145             size = data.size;
6146
6147         switch (data.type) {
6148           case 'drop':      start += size; break;
6149           case 'dropRight': end -= size; break;
6150           case 'take':      end = nativeMin(end, start + size); break;
6151           case 'takeRight': start = nativeMax(start, end - size); break;
6152         }
6153       }
6154       return { 'start': start, 'end': end };
6155     }
6156
6157     /**
6158      * Extracts wrapper details from the `source` body comment.
6159      *
6160      * @private
6161      * @param {string} source The source to inspect.
6162      * @returns {Array} Returns the wrapper details.
6163      */
6164     function getWrapDetails(source) {
6165       var match = source.match(reWrapDetails);
6166       return match ? match[1].split(reSplitDetails) : [];
6167     }
6168
6169     /**
6170      * Checks if `path` exists on `object`.
6171      *
6172      * @private
6173      * @param {Object} object The object to query.
6174      * @param {Array|string} path The path to check.
6175      * @param {Function} hasFunc The function to check properties.
6176      * @returns {boolean} Returns `true` if `path` exists, else `false`.
6177      */
6178     function hasPath(object, path, hasFunc) {
6179       path = castPath(path, object);
6180
6181       var index = -1,
6182           length = path.length,
6183           result = false;
6184
6185       while (++index < length) {
6186         var key = toKey(path[index]);
6187         if (!(result = object != null && hasFunc(object, key))) {
6188           break;
6189         }
6190         object = object[key];
6191       }
6192       if (result || ++index != length) {
6193         return result;
6194       }
6195       length = object == null ? 0 : object.length;
6196       return !!length && isLength(length) && isIndex(key, length) &&
6197         (isArray(object) || isArguments(object));
6198     }
6199
6200     /**
6201      * Initializes an array clone.
6202      *
6203      * @private
6204      * @param {Array} array The array to clone.
6205      * @returns {Array} Returns the initialized clone.
6206      */
6207     function initCloneArray(array) {
6208       var length = array.length,
6209           result = array.constructor(length);
6210
6211       // Add properties assigned by `RegExp#exec`.
6212       if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
6213         result.index = array.index;
6214         result.input = array.input;
6215       }
6216       return result;
6217     }
6218
6219     /**
6220      * Initializes an object clone.
6221      *
6222      * @private
6223      * @param {Object} object The object to clone.
6224      * @returns {Object} Returns the initialized clone.
6225      */
6226     function initCloneObject(object) {
6227       return (typeof object.constructor == 'function' && !isPrototype(object))
6228         ? baseCreate(getPrototype(object))
6229         : {};
6230     }
6231
6232     /**
6233      * Initializes an object clone based on its `toStringTag`.
6234      *
6235      * **Note:** This function only supports cloning values with tags of
6236      * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
6237      *
6238      * @private
6239      * @param {Object} object The object to clone.
6240      * @param {string} tag The `toStringTag` of the object to clone.
6241      * @param {Function} cloneFunc The function to clone values.
6242      * @param {boolean} [isDeep] Specify a deep clone.
6243      * @returns {Object} Returns the initialized clone.
6244      */
6245     function initCloneByTag(object, tag, cloneFunc, isDeep) {
6246       var Ctor = object.constructor;
6247       switch (tag) {
6248         case arrayBufferTag:
6249           return cloneArrayBuffer(object);
6250
6251         case boolTag:
6252         case dateTag:
6253           return new Ctor(+object);
6254
6255         case dataViewTag:
6256           return cloneDataView(object, isDeep);
6257
6258         case float32Tag: case float64Tag:
6259         case int8Tag: case int16Tag: case int32Tag:
6260         case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
6261           return cloneTypedArray(object, isDeep);
6262
6263         case mapTag:
6264           return cloneMap(object, isDeep, cloneFunc);
6265
6266         case numberTag:
6267         case stringTag:
6268           return new Ctor(object);
6269
6270         case regexpTag:
6271           return cloneRegExp(object);
6272
6273         case setTag:
6274           return cloneSet(object, isDeep, cloneFunc);
6275
6276         case symbolTag:
6277           return cloneSymbol(object);
6278       }
6279     }
6280
6281     /**
6282      * Inserts wrapper `details` in a comment at the top of the `source` body.
6283      *
6284      * @private
6285      * @param {string} source The source to modify.
6286      * @returns {Array} details The details to insert.
6287      * @returns {string} Returns the modified source.
6288      */
6289     function insertWrapDetails(source, details) {
6290       var length = details.length;
6291       if (!length) {
6292         return source;
6293       }
6294       var lastIndex = length - 1;
6295       details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
6296       details = details.join(length > 2 ? ', ' : ' ');
6297       return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
6298     }
6299
6300     /**
6301      * Checks if `value` is a flattenable `arguments` object or array.
6302      *
6303      * @private
6304      * @param {*} value The value to check.
6305      * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
6306      */
6307     function isFlattenable(value) {
6308       return isArray(value) || isArguments(value) ||
6309         !!(spreadableSymbol && value && value[spreadableSymbol]);
6310     }
6311
6312     /**
6313      * Checks if `value` is a valid array-like index.
6314      *
6315      * @private
6316      * @param {*} value The value to check.
6317      * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
6318      * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
6319      */
6320     function isIndex(value, length) {
6321       length = length == null ? MAX_SAFE_INTEGER : length;
6322       return !!length &&
6323         (typeof value == 'number' || reIsUint.test(value)) &&
6324         (value > -1 && value % 1 == 0 && value < length);
6325     }
6326
6327     /**
6328      * Checks if the given arguments are from an iteratee call.
6329      *
6330      * @private
6331      * @param {*} value The potential iteratee value argument.
6332      * @param {*} index The potential iteratee index or key argument.
6333      * @param {*} object The potential iteratee object argument.
6334      * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
6335      *  else `false`.
6336      */
6337     function isIterateeCall(value, index, object) {
6338       if (!isObject(object)) {
6339         return false;
6340       }
6341       var type = typeof index;
6342       if (type == 'number'
6343             ? (isArrayLike(object) && isIndex(index, object.length))
6344             : (type == 'string' && index in object)
6345           ) {
6346         return eq(object[index], value);
6347       }
6348       return false;
6349     }
6350
6351     /**
6352      * Checks if `value` is a property name and not a property path.
6353      *
6354      * @private
6355      * @param {*} value The value to check.
6356      * @param {Object} [object] The object to query keys on.
6357      * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
6358      */
6359     function isKey(value, object) {
6360       if (isArray(value)) {
6361         return false;
6362       }
6363       var type = typeof value;
6364       if (type == 'number' || type == 'symbol' || type == 'boolean' ||
6365           value == null || isSymbol(value)) {
6366         return true;
6367       }
6368       return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
6369         (object != null && value in Object(object));
6370     }
6371
6372     /**
6373      * Checks if `value` is suitable for use as unique object key.
6374      *
6375      * @private
6376      * @param {*} value The value to check.
6377      * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
6378      */
6379     function isKeyable(value) {
6380       var type = typeof value;
6381       return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
6382         ? (value !== '__proto__')
6383         : (value === null);
6384     }
6385
6386     /**
6387      * Checks if `func` has a lazy counterpart.
6388      *
6389      * @private
6390      * @param {Function} func The function to check.
6391      * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
6392      *  else `false`.
6393      */
6394     function isLaziable(func) {
6395       var funcName = getFuncName(func),
6396           other = lodash[funcName];
6397
6398       if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
6399         return false;
6400       }
6401       if (func === other) {
6402         return true;
6403       }
6404       var data = getData(other);
6405       return !!data && func === data[0];
6406     }
6407
6408     /**
6409      * Checks if `func` has its source masked.
6410      *
6411      * @private
6412      * @param {Function} func The function to check.
6413      * @returns {boolean} Returns `true` if `func` is masked, else `false`.
6414      */
6415     function isMasked(func) {
6416       return !!maskSrcKey && (maskSrcKey in func);
6417     }
6418
6419     /**
6420      * Checks if `func` is capable of being masked.
6421      *
6422      * @private
6423      * @param {*} value The value to check.
6424      * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
6425      */
6426     var isMaskable = coreJsData ? isFunction : stubFalse;
6427
6428     /**
6429      * Checks if `value` is likely a prototype object.
6430      *
6431      * @private
6432      * @param {*} value The value to check.
6433      * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
6434      */
6435     function isPrototype(value) {
6436       var Ctor = value && value.constructor,
6437           proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
6438
6439       return value === proto;
6440     }
6441
6442     /**
6443      * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
6444      *
6445      * @private
6446      * @param {*} value The value to check.
6447      * @returns {boolean} Returns `true` if `value` if suitable for strict
6448      *  equality comparisons, else `false`.
6449      */
6450     function isStrictComparable(value) {
6451       return value === value && !isObject(value);
6452     }
6453
6454     /**
6455      * A specialized version of `matchesProperty` for source values suitable
6456      * for strict equality comparisons, i.e. `===`.
6457      *
6458      * @private
6459      * @param {string} key The key of the property to get.
6460      * @param {*} srcValue The value to match.
6461      * @returns {Function} Returns the new spec function.
6462      */
6463     function matchesStrictComparable(key, srcValue) {
6464       return function(object) {
6465         if (object == null) {
6466           return false;
6467         }
6468         return object[key] === srcValue &&
6469           (srcValue !== undefined || (key in Object(object)));
6470       };
6471     }
6472
6473     /**
6474      * A specialized version of `_.memoize` which clears the memoized function's
6475      * cache when it exceeds `MAX_MEMOIZE_SIZE`.
6476      *
6477      * @private
6478      * @param {Function} func The function to have its output memoized.
6479      * @returns {Function} Returns the new memoized function.
6480      */
6481     function memoizeCapped(func) {
6482       var result = memoize(func, function(key) {
6483         if (cache.size === MAX_MEMOIZE_SIZE) {
6484           cache.clear();
6485         }
6486         return key;
6487       });
6488
6489       var cache = result.cache;
6490       return result;
6491     }
6492
6493     /**
6494      * Merges the function metadata of `source` into `data`.
6495      *
6496      * Merging metadata reduces the number of wrappers used to invoke a function.
6497      * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
6498      * may be applied regardless of execution order. Methods like `_.ary` and
6499      * `_.rearg` modify function arguments, making the order in which they are
6500      * executed important, preventing the merging of metadata. However, we make
6501      * an exception for a safe combined case where curried functions have `_.ary`
6502      * and or `_.rearg` applied.
6503      *
6504      * @private
6505      * @param {Array} data The destination metadata.
6506      * @param {Array} source The source metadata.
6507      * @returns {Array} Returns `data`.
6508      */
6509     function mergeData(data, source) {
6510       var bitmask = data[1],
6511           srcBitmask = source[1],
6512           newBitmask = bitmask | srcBitmask,
6513           isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);
6514
6515       var isCombo =
6516         ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) ||
6517         ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) ||
6518         ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG));
6519
6520       // Exit early if metadata can't be merged.
6521       if (!(isCommon || isCombo)) {
6522         return data;
6523       }
6524       // Use source `thisArg` if available.
6525       if (srcBitmask & WRAP_BIND_FLAG) {
6526         data[2] = source[2];
6527         // Set when currying a bound function.
6528         newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
6529       }
6530       // Compose partial arguments.
6531       var value = source[3];
6532       if (value) {
6533         var partials = data[3];
6534         data[3] = partials ? composeArgs(partials, value, source[4]) : value;
6535         data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
6536       }
6537       // Compose partial right arguments.
6538       value = source[5];
6539       if (value) {
6540         partials = data[5];
6541         data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
6542         data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
6543       }
6544       // Use source `argPos` if available.
6545       value = source[7];
6546       if (value) {
6547         data[7] = value;
6548       }
6549       // Use source `ary` if it's smaller.
6550       if (srcBitmask & WRAP_ARY_FLAG) {
6551         data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
6552       }
6553       // Use source `arity` if one is not provided.
6554       if (data[9] == null) {
6555         data[9] = source[9];
6556       }
6557       // Use source `func` and merge bitmasks.
6558       data[0] = source[0];
6559       data[1] = newBitmask;
6560
6561       return data;
6562     }
6563
6564     /**
6565      * This function is like
6566      * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
6567      * except that it includes inherited enumerable properties.
6568      *
6569      * @private
6570      * @param {Object} object The object to query.
6571      * @returns {Array} Returns the array of property names.
6572      */
6573     function nativeKeysIn(object) {
6574       var result = [];
6575       if (object != null) {
6576         for (var key in Object(object)) {
6577           result.push(key);
6578         }
6579       }
6580       return result;
6581     }
6582
6583     /**
6584      * Converts `value` to a string using `Object.prototype.toString`.
6585      *
6586      * @private
6587      * @param {*} value The value to convert.
6588      * @returns {string} Returns the converted string.
6589      */
6590     function objectToString(value) {
6591       return nativeObjectToString.call(value);
6592     }
6593
6594     /**
6595      * A specialized version of `baseRest` which transforms the rest array.
6596      *
6597      * @private
6598      * @param {Function} func The function to apply a rest parameter to.
6599      * @param {number} [start=func.length-1] The start position of the rest parameter.
6600      * @param {Function} transform The rest array transform.
6601      * @returns {Function} Returns the new function.
6602      */
6603     function overRest(func, start, transform) {
6604       start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
6605       return function() {
6606         var args = arguments,
6607             index = -1,
6608             length = nativeMax(args.length - start, 0),
6609             array = Array(length);
6610
6611         while (++index < length) {
6612           array[index] = args[start + index];
6613         }
6614         index = -1;
6615         var otherArgs = Array(start + 1);
6616         while (++index < start) {
6617           otherArgs[index] = args[index];
6618         }
6619         otherArgs[start] = transform(array);
6620         return apply(func, this, otherArgs);
6621       };
6622     }
6623
6624     /**
6625      * Gets the parent value at `path` of `object`.
6626      *
6627      * @private
6628      * @param {Object} object The object to query.
6629      * @param {Array} path The path to get the parent value of.
6630      * @returns {*} Returns the parent value.
6631      */
6632     function parent(object, path) {
6633       return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
6634     }
6635
6636     /**
6637      * Reorder `array` according to the specified indexes where the element at
6638      * the first index is assigned as the first element, the element at
6639      * the second index is assigned as the second element, and so on.
6640      *
6641      * @private
6642      * @param {Array} array The array to reorder.
6643      * @param {Array} indexes The arranged array indexes.
6644      * @returns {Array} Returns `array`.
6645      */
6646     function reorder(array, indexes) {
6647       var arrLength = array.length,
6648           length = nativeMin(indexes.length, arrLength),
6649           oldArray = copyArray(array);
6650
6651       while (length--) {
6652         var index = indexes[length];
6653         array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
6654       }
6655       return array;
6656     }
6657
6658     /**
6659      * Sets metadata for `func`.
6660      *
6661      * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
6662      * period of time, it will trip its breaker and transition to an identity
6663      * function to avoid garbage collection pauses in V8. See
6664      * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
6665      * for more details.
6666      *
6667      * @private
6668      * @param {Function} func The function to associate metadata with.
6669      * @param {*} data The metadata.
6670      * @returns {Function} Returns `func`.
6671      */
6672     var setData = shortOut(baseSetData);
6673
6674     /**
6675      * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
6676      *
6677      * @private
6678      * @param {Function} func The function to delay.
6679      * @param {number} wait The number of milliseconds to delay invocation.
6680      * @returns {number|Object} Returns the timer id or timeout object.
6681      */
6682     var setTimeout = ctxSetTimeout || function(func, wait) {
6683       return root.setTimeout(func, wait);
6684     };
6685
6686     /**
6687      * Sets the `toString` method of `func` to return `string`.
6688      *
6689      * @private
6690      * @param {Function} func The function to modify.
6691      * @param {Function} string The `toString` result.
6692      * @returns {Function} Returns `func`.
6693      */
6694     var setToString = shortOut(baseSetToString);
6695
6696     /**
6697      * Sets the `toString` method of `wrapper` to mimic the source of `reference`
6698      * with wrapper details in a comment at the top of the source body.
6699      *
6700      * @private
6701      * @param {Function} wrapper The function to modify.
6702      * @param {Function} reference The reference function.
6703      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6704      * @returns {Function} Returns `wrapper`.
6705      */
6706     function setWrapToString(wrapper, reference, bitmask) {
6707       var source = (reference + '');
6708       return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)));
6709     }
6710
6711     /**
6712      * Creates a function that'll short out and invoke `identity` instead
6713      * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
6714      * milliseconds.
6715      *
6716      * @private
6717      * @param {Function} func The function to restrict.
6718      * @returns {Function} Returns the new shortable function.
6719      */
6720     function shortOut(func) {
6721       var count = 0,
6722           lastCalled = 0;
6723
6724       return function() {
6725         var stamp = nativeNow(),
6726             remaining = HOT_SPAN - (stamp - lastCalled);
6727
6728         lastCalled = stamp;
6729         if (remaining > 0) {
6730           if (++count >= HOT_COUNT) {
6731             return arguments[0];
6732           }
6733         } else {
6734           count = 0;
6735         }
6736         return func.apply(undefined, arguments);
6737       };
6738     }
6739
6740     /**
6741      * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
6742      *
6743      * @private
6744      * @param {Array} array The array to shuffle.
6745      * @param {number} [size=array.length] The size of `array`.
6746      * @returns {Array} Returns `array`.
6747      */
6748     function shuffleSelf(array, size) {
6749       var index = -1,
6750           length = array.length,
6751           lastIndex = length - 1;
6752
6753       size = size === undefined ? length : size;
6754       while (++index < size) {
6755         var rand = baseRandom(index, lastIndex),
6756             value = array[rand];
6757
6758         array[rand] = array[index];
6759         array[index] = value;
6760       }
6761       array.length = size;
6762       return array;
6763     }
6764
6765     /**
6766      * Converts `string` to a property path array.
6767      *
6768      * @private
6769      * @param {string} string The string to convert.
6770      * @returns {Array} Returns the property path array.
6771      */
6772     var stringToPath = memoizeCapped(function(string) {
6773       var result = [];
6774       if (reLeadingDot.test(string)) {
6775         result.push('');
6776       }
6777       string.replace(rePropName, function(match, number, quote, string) {
6778         result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
6779       });
6780       return result;
6781     });
6782
6783     /**
6784      * Converts `value` to a string key if it's not a string or symbol.
6785      *
6786      * @private
6787      * @param {*} value The value to inspect.
6788      * @returns {string|symbol} Returns the key.
6789      */
6790     function toKey(value) {
6791       if (typeof value == 'string' || isSymbol(value)) {
6792         return value;
6793       }
6794       var result = (value + '');
6795       return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
6796     }
6797
6798     /**
6799      * Converts `func` to its source code.
6800      *
6801      * @private
6802      * @param {Function} func The function to convert.
6803      * @returns {string} Returns the source code.
6804      */
6805     function toSource(func) {
6806       if (func != null) {
6807         try {
6808           return funcToString.call(func);
6809         } catch (e) {}
6810         try {
6811           return (func + '');
6812         } catch (e) {}
6813       }
6814       return '';
6815     }
6816
6817     /**
6818      * Updates wrapper `details` based on `bitmask` flags.
6819      *
6820      * @private
6821      * @returns {Array} details The details to modify.
6822      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6823      * @returns {Array} Returns `details`.
6824      */
6825     function updateWrapDetails(details, bitmask) {
6826       arrayEach(wrapFlags, function(pair) {
6827         var value = '_.' + pair[0];
6828         if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
6829           details.push(value);
6830         }
6831       });
6832       return details.sort();
6833     }
6834
6835     /**
6836      * Creates a clone of `wrapper`.
6837      *
6838      * @private
6839      * @param {Object} wrapper The wrapper to clone.
6840      * @returns {Object} Returns the cloned wrapper.
6841      */
6842     function wrapperClone(wrapper) {
6843       if (wrapper instanceof LazyWrapper) {
6844         return wrapper.clone();
6845       }
6846       var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
6847       result.__actions__ = copyArray(wrapper.__actions__);
6848       result.__index__  = wrapper.__index__;
6849       result.__values__ = wrapper.__values__;
6850       return result;
6851     }
6852
6853     /*------------------------------------------------------------------------*/
6854
6855     /**
6856      * Creates an array of elements split into groups the length of `size`.
6857      * If `array` can't be split evenly, the final chunk will be the remaining
6858      * elements.
6859      *
6860      * @static
6861      * @memberOf _
6862      * @since 3.0.0
6863      * @category Array
6864      * @param {Array} array The array to process.
6865      * @param {number} [size=1] The length of each chunk
6866      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
6867      * @returns {Array} Returns the new array of chunks.
6868      * @example
6869      *
6870      * _.chunk(['a', 'b', 'c', 'd'], 2);
6871      * // => [['a', 'b'], ['c', 'd']]
6872      *
6873      * _.chunk(['a', 'b', 'c', 'd'], 3);
6874      * // => [['a', 'b', 'c'], ['d']]
6875      */
6876     function chunk(array, size, guard) {
6877       if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
6878         size = 1;
6879       } else {
6880         size = nativeMax(toInteger(size), 0);
6881       }
6882       var length = array == null ? 0 : array.length;
6883       if (!length || size < 1) {
6884         return [];
6885       }
6886       var index = 0,
6887           resIndex = 0,
6888           result = Array(nativeCeil(length / size));
6889
6890       while (index < length) {
6891         result[resIndex++] = baseSlice(array, index, (index += size));
6892       }
6893       return result;
6894     }
6895
6896     /**
6897      * Creates an array with all falsey values removed. The values `false`, `null`,
6898      * `0`, `""`, `undefined`, and `NaN` are falsey.
6899      *
6900      * @static
6901      * @memberOf _
6902      * @since 0.1.0
6903      * @category Array
6904      * @param {Array} array The array to compact.
6905      * @returns {Array} Returns the new array of filtered values.
6906      * @example
6907      *
6908      * _.compact([0, 1, false, 2, '', 3]);
6909      * // => [1, 2, 3]
6910      */
6911     function compact(array) {
6912       var index = -1,
6913           length = array == null ? 0 : array.length,
6914           resIndex = 0,
6915           result = [];
6916
6917       while (++index < length) {
6918         var value = array[index];
6919         if (value) {
6920           result[resIndex++] = value;
6921         }
6922       }
6923       return result;
6924     }
6925
6926     /**
6927      * Creates a new array concatenating `array` with any additional arrays
6928      * and/or values.
6929      *
6930      * @static
6931      * @memberOf _
6932      * @since 4.0.0
6933      * @category Array
6934      * @param {Array} array The array to concatenate.
6935      * @param {...*} [values] The values to concatenate.
6936      * @returns {Array} Returns the new concatenated array.
6937      * @example
6938      *
6939      * var array = [1];
6940      * var other = _.concat(array, 2, [3], [[4]]);
6941      *
6942      * console.log(other);
6943      * // => [1, 2, 3, [4]]
6944      *
6945      * console.log(array);
6946      * // => [1]
6947      */
6948     function concat() {
6949       var length = arguments.length;
6950       if (!length) {
6951         return [];
6952       }
6953       var args = Array(length - 1),
6954           array = arguments[0],
6955           index = length;
6956
6957       while (index--) {
6958         args[index - 1] = arguments[index];
6959       }
6960       return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
6961     }
6962
6963     /**
6964      * Creates an array of `array` values not included in the other given arrays
6965      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
6966      * for equality comparisons. The order and references of result values are
6967      * determined by the first array.
6968      *
6969      * **Note:** Unlike `_.pullAll`, this method returns a new array.
6970      *
6971      * @static
6972      * @memberOf _
6973      * @since 0.1.0
6974      * @category Array
6975      * @param {Array} array The array to inspect.
6976      * @param {...Array} [values] The values to exclude.
6977      * @returns {Array} Returns the new array of filtered values.
6978      * @see _.without, _.xor
6979      * @example
6980      *
6981      * _.difference([2, 1], [2, 3]);
6982      * // => [1]
6983      */
6984     var difference = baseRest(function(array, values) {
6985       return isArrayLikeObject(array)
6986         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
6987         : [];
6988     });
6989
6990     /**
6991      * This method is like `_.difference` except that it accepts `iteratee` which
6992      * is invoked for each element of `array` and `values` to generate the criterion
6993      * by which they're compared. The order and references of result values are
6994      * determined by the first array. The iteratee is invoked with one argument:
6995      * (value).
6996      *
6997      * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
6998      *
6999      * @static
7000      * @memberOf _
7001      * @since 4.0.0
7002      * @category Array
7003      * @param {Array} array The array to inspect.
7004      * @param {...Array} [values] The values to exclude.
7005      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7006      * @returns {Array} Returns the new array of filtered values.
7007      * @example
7008      *
7009      * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
7010      * // => [1.2]
7011      *
7012      * // The `_.property` iteratee shorthand.
7013      * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
7014      * // => [{ 'x': 2 }]
7015      */
7016     var differenceBy = baseRest(function(array, values) {
7017       var iteratee = last(values);
7018       if (isArrayLikeObject(iteratee)) {
7019         iteratee = undefined;
7020       }
7021       return isArrayLikeObject(array)
7022         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2))
7023         : [];
7024     });
7025
7026     /**
7027      * This method is like `_.difference` except that it accepts `comparator`
7028      * which is invoked to compare elements of `array` to `values`. The order and
7029      * references of result values are determined by the first array. The comparator
7030      * is invoked with two arguments: (arrVal, othVal).
7031      *
7032      * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
7033      *
7034      * @static
7035      * @memberOf _
7036      * @since 4.0.0
7037      * @category Array
7038      * @param {Array} array The array to inspect.
7039      * @param {...Array} [values] The values to exclude.
7040      * @param {Function} [comparator] The comparator invoked per element.
7041      * @returns {Array} Returns the new array of filtered values.
7042      * @example
7043      *
7044      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
7045      *
7046      * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
7047      * // => [{ 'x': 2, 'y': 1 }]
7048      */
7049     var differenceWith = baseRest(function(array, values) {
7050       var comparator = last(values);
7051       if (isArrayLikeObject(comparator)) {
7052         comparator = undefined;
7053       }
7054       return isArrayLikeObject(array)
7055         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
7056         : [];
7057     });
7058
7059     /**
7060      * Creates a slice of `array` with `n` elements dropped from the beginning.
7061      *
7062      * @static
7063      * @memberOf _
7064      * @since 0.5.0
7065      * @category Array
7066      * @param {Array} array The array to query.
7067      * @param {number} [n=1] The number of elements to drop.
7068      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
7069      * @returns {Array} Returns the slice of `array`.
7070      * @example
7071      *
7072      * _.drop([1, 2, 3]);
7073      * // => [2, 3]
7074      *
7075      * _.drop([1, 2, 3], 2);
7076      * // => [3]
7077      *
7078      * _.drop([1, 2, 3], 5);
7079      * // => []
7080      *
7081      * _.drop([1, 2, 3], 0);
7082      * // => [1, 2, 3]
7083      */
7084     function drop(array, n, guard) {
7085       var length = array == null ? 0 : array.length;
7086       if (!length) {
7087         return [];
7088       }
7089       n = (guard || n === undefined) ? 1 : toInteger(n);
7090       return baseSlice(array, n < 0 ? 0 : n, length);
7091     }
7092
7093     /**
7094      * Creates a slice of `array` with `n` elements dropped from the end.
7095      *
7096      * @static
7097      * @memberOf _
7098      * @since 3.0.0
7099      * @category Array
7100      * @param {Array} array The array to query.
7101      * @param {number} [n=1] The number of elements to drop.
7102      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
7103      * @returns {Array} Returns the slice of `array`.
7104      * @example
7105      *
7106      * _.dropRight([1, 2, 3]);
7107      * // => [1, 2]
7108      *
7109      * _.dropRight([1, 2, 3], 2);
7110      * // => [1]
7111      *
7112      * _.dropRight([1, 2, 3], 5);
7113      * // => []
7114      *
7115      * _.dropRight([1, 2, 3], 0);
7116      * // => [1, 2, 3]
7117      */
7118     function dropRight(array, n, guard) {
7119       var length = array == null ? 0 : array.length;
7120       if (!length) {
7121         return [];
7122       }
7123       n = (guard || n === undefined) ? 1 : toInteger(n);
7124       n = length - n;
7125       return baseSlice(array, 0, n < 0 ? 0 : n);
7126     }
7127
7128     /**
7129      * Creates a slice of `array` excluding elements dropped from the end.
7130      * Elements are dropped until `predicate` returns falsey. The predicate is
7131      * invoked with three arguments: (value, index, array).
7132      *
7133      * @static
7134      * @memberOf _
7135      * @since 3.0.0
7136      * @category Array
7137      * @param {Array} array The array to query.
7138      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7139      * @returns {Array} Returns the slice of `array`.
7140      * @example
7141      *
7142      * var users = [
7143      *   { 'user': 'barney',  'active': true },
7144      *   { 'user': 'fred',    'active': false },
7145      *   { 'user': 'pebbles', 'active': false }
7146      * ];
7147      *
7148      * _.dropRightWhile(users, function(o) { return !o.active; });
7149      * // => objects for ['barney']
7150      *
7151      * // The `_.matches` iteratee shorthand.
7152      * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
7153      * // => objects for ['barney', 'fred']
7154      *
7155      * // The `_.matchesProperty` iteratee shorthand.
7156      * _.dropRightWhile(users, ['active', false]);
7157      * // => objects for ['barney']
7158      *
7159      * // The `_.property` iteratee shorthand.
7160      * _.dropRightWhile(users, 'active');
7161      * // => objects for ['barney', 'fred', 'pebbles']
7162      */
7163     function dropRightWhile(array, predicate) {
7164       return (array && array.length)
7165         ? baseWhile(array, getIteratee(predicate, 3), true, true)
7166         : [];
7167     }
7168
7169     /**
7170      * Creates a slice of `array` excluding elements dropped from the beginning.
7171      * Elements are dropped until `predicate` returns falsey. The predicate is
7172      * invoked with three arguments: (value, index, array).
7173      *
7174      * @static
7175      * @memberOf _
7176      * @since 3.0.0
7177      * @category Array
7178      * @param {Array} array The array to query.
7179      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7180      * @returns {Array} Returns the slice of `array`.
7181      * @example
7182      *
7183      * var users = [
7184      *   { 'user': 'barney',  'active': false },
7185      *   { 'user': 'fred',    'active': false },
7186      *   { 'user': 'pebbles', 'active': true }
7187      * ];
7188      *
7189      * _.dropWhile(users, function(o) { return !o.active; });
7190      * // => objects for ['pebbles']
7191      *
7192      * // The `_.matches` iteratee shorthand.
7193      * _.dropWhile(users, { 'user': 'barney', 'active': false });
7194      * // => objects for ['fred', 'pebbles']
7195      *
7196      * // The `_.matchesProperty` iteratee shorthand.
7197      * _.dropWhile(users, ['active', false]);
7198      * // => objects for ['pebbles']
7199      *
7200      * // The `_.property` iteratee shorthand.
7201      * _.dropWhile(users, 'active');
7202      * // => objects for ['barney', 'fred', 'pebbles']
7203      */
7204     function dropWhile(array, predicate) {
7205       return (array && array.length)
7206         ? baseWhile(array, getIteratee(predicate, 3), true)
7207         : [];
7208     }
7209
7210     /**
7211      * Fills elements of `array` with `value` from `start` up to, but not
7212      * including, `end`.
7213      *
7214      * **Note:** This method mutates `array`.
7215      *
7216      * @static
7217      * @memberOf _
7218      * @since 3.2.0
7219      * @category Array
7220      * @param {Array} array The array to fill.
7221      * @param {*} value The value to fill `array` with.
7222      * @param {number} [start=0] The start position.
7223      * @param {number} [end=array.length] The end position.
7224      * @returns {Array} Returns `array`.
7225      * @example
7226      *
7227      * var array = [1, 2, 3];
7228      *
7229      * _.fill(array, 'a');
7230      * console.log(array);
7231      * // => ['a', 'a', 'a']
7232      *
7233      * _.fill(Array(3), 2);
7234      * // => [2, 2, 2]
7235      *
7236      * _.fill([4, 6, 8, 10], '*', 1, 3);
7237      * // => [4, '*', '*', 10]
7238      */
7239     function fill(array, value, start, end) {
7240       var length = array == null ? 0 : array.length;
7241       if (!length) {
7242         return [];
7243       }
7244       if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
7245         start = 0;
7246         end = length;
7247       }
7248       return baseFill(array, value, start, end);
7249     }
7250
7251     /**
7252      * This method is like `_.find` except that it returns the index of the first
7253      * element `predicate` returns truthy for instead of the element itself.
7254      *
7255      * @static
7256      * @memberOf _
7257      * @since 1.1.0
7258      * @category Array
7259      * @param {Array} array The array to inspect.
7260      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7261      * @param {number} [fromIndex=0] The index to search from.
7262      * @returns {number} Returns the index of the found element, else `-1`.
7263      * @example
7264      *
7265      * var users = [
7266      *   { 'user': 'barney',  'active': false },
7267      *   { 'user': 'fred',    'active': false },
7268      *   { 'user': 'pebbles', 'active': true }
7269      * ];
7270      *
7271      * _.findIndex(users, function(o) { return o.user == 'barney'; });
7272      * // => 0
7273      *
7274      * // The `_.matches` iteratee shorthand.
7275      * _.findIndex(users, { 'user': 'fred', 'active': false });
7276      * // => 1
7277      *
7278      * // The `_.matchesProperty` iteratee shorthand.
7279      * _.findIndex(users, ['active', false]);
7280      * // => 0
7281      *
7282      * // The `_.property` iteratee shorthand.
7283      * _.findIndex(users, 'active');
7284      * // => 2
7285      */
7286     function findIndex(array, predicate, fromIndex) {
7287       var length = array == null ? 0 : array.length;
7288       if (!length) {
7289         return -1;
7290       }
7291       var index = fromIndex == null ? 0 : toInteger(fromIndex);
7292       if (index < 0) {
7293         index = nativeMax(length + index, 0);
7294       }
7295       return baseFindIndex(array, getIteratee(predicate, 3), index);
7296     }
7297
7298     /**
7299      * This method is like `_.findIndex` except that it iterates over elements
7300      * of `collection` from right to left.
7301      *
7302      * @static
7303      * @memberOf _
7304      * @since 2.0.0
7305      * @category Array
7306      * @param {Array} array The array to inspect.
7307      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7308      * @param {number} [fromIndex=array.length-1] The index to search from.
7309      * @returns {number} Returns the index of the found element, else `-1`.
7310      * @example
7311      *
7312      * var users = [
7313      *   { 'user': 'barney',  'active': true },
7314      *   { 'user': 'fred',    'active': false },
7315      *   { 'user': 'pebbles', 'active': false }
7316      * ];
7317      *
7318      * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
7319      * // => 2
7320      *
7321      * // The `_.matches` iteratee shorthand.
7322      * _.findLastIndex(users, { 'user': 'barney', 'active': true });
7323      * // => 0
7324      *
7325      * // The `_.matchesProperty` iteratee shorthand.
7326      * _.findLastIndex(users, ['active', false]);
7327      * // => 2
7328      *
7329      * // The `_.property` iteratee shorthand.
7330      * _.findLastIndex(users, 'active');
7331      * // => 0
7332      */
7333     function findLastIndex(array, predicate, fromIndex) {
7334       var length = array == null ? 0 : array.length;
7335       if (!length) {
7336         return -1;
7337       }
7338       var index = length - 1;
7339       if (fromIndex !== undefined) {
7340         index = toInteger(fromIndex);
7341         index = fromIndex < 0
7342           ? nativeMax(length + index, 0)
7343           : nativeMin(index, length - 1);
7344       }
7345       return baseFindIndex(array, getIteratee(predicate, 3), index, true);
7346     }
7347
7348     /**
7349      * Flattens `array` a single level deep.
7350      *
7351      * @static
7352      * @memberOf _
7353      * @since 0.1.0
7354      * @category Array
7355      * @param {Array} array The array to flatten.
7356      * @returns {Array} Returns the new flattened array.
7357      * @example
7358      *
7359      * _.flatten([1, [2, [3, [4]], 5]]);
7360      * // => [1, 2, [3, [4]], 5]
7361      */
7362     function flatten(array) {
7363       var length = array == null ? 0 : array.length;
7364       return length ? baseFlatten(array, 1) : [];
7365     }
7366
7367     /**
7368      * Recursively flattens `array`.
7369      *
7370      * @static
7371      * @memberOf _
7372      * @since 3.0.0
7373      * @category Array
7374      * @param {Array} array The array to flatten.
7375      * @returns {Array} Returns the new flattened array.
7376      * @example
7377      *
7378      * _.flattenDeep([1, [2, [3, [4]], 5]]);
7379      * // => [1, 2, 3, 4, 5]
7380      */
7381     function flattenDeep(array) {
7382       var length = array == null ? 0 : array.length;
7383       return length ? baseFlatten(array, INFINITY) : [];
7384     }
7385
7386     /**
7387      * Recursively flatten `array` up to `depth` times.
7388      *
7389      * @static
7390      * @memberOf _
7391      * @since 4.4.0
7392      * @category Array
7393      * @param {Array} array The array to flatten.
7394      * @param {number} [depth=1] The maximum recursion depth.
7395      * @returns {Array} Returns the new flattened array.
7396      * @example
7397      *
7398      * var array = [1, [2, [3, [4]], 5]];
7399      *
7400      * _.flattenDepth(array, 1);
7401      * // => [1, 2, [3, [4]], 5]
7402      *
7403      * _.flattenDepth(array, 2);
7404      * // => [1, 2, 3, [4], 5]
7405      */
7406     function flattenDepth(array, depth) {
7407       var length = array == null ? 0 : array.length;
7408       if (!length) {
7409         return [];
7410       }
7411       depth = depth === undefined ? 1 : toInteger(depth);
7412       return baseFlatten(array, depth);
7413     }
7414
7415     /**
7416      * The inverse of `_.toPairs`; this method returns an object composed
7417      * from key-value `pairs`.
7418      *
7419      * @static
7420      * @memberOf _
7421      * @since 4.0.0
7422      * @category Array
7423      * @param {Array} pairs The key-value pairs.
7424      * @returns {Object} Returns the new object.
7425      * @example
7426      *
7427      * _.fromPairs([['a', 1], ['b', 2]]);
7428      * // => { 'a': 1, 'b': 2 }
7429      */
7430     function fromPairs(pairs) {
7431       var index = -1,
7432           length = pairs == null ? 0 : pairs.length,
7433           result = {};
7434
7435       while (++index < length) {
7436         var pair = pairs[index];
7437         result[pair[0]] = pair[1];
7438       }
7439       return result;
7440     }
7441
7442     /**
7443      * Gets the first element of `array`.
7444      *
7445      * @static
7446      * @memberOf _
7447      * @since 0.1.0
7448      * @alias first
7449      * @category Array
7450      * @param {Array} array The array to query.
7451      * @returns {*} Returns the first element of `array`.
7452      * @example
7453      *
7454      * _.head([1, 2, 3]);
7455      * // => 1
7456      *
7457      * _.head([]);
7458      * // => undefined
7459      */
7460     function head(array) {
7461       return (array && array.length) ? array[0] : undefined;
7462     }
7463
7464     /**
7465      * Gets the index at which the first occurrence of `value` is found in `array`
7466      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7467      * for equality comparisons. If `fromIndex` is negative, it's used as the
7468      * offset from the end of `array`.
7469      *
7470      * @static
7471      * @memberOf _
7472      * @since 0.1.0
7473      * @category Array
7474      * @param {Array} array The array to inspect.
7475      * @param {*} value The value to search for.
7476      * @param {number} [fromIndex=0] The index to search from.
7477      * @returns {number} Returns the index of the matched value, else `-1`.
7478      * @example
7479      *
7480      * _.indexOf([1, 2, 1, 2], 2);
7481      * // => 1
7482      *
7483      * // Search from the `fromIndex`.
7484      * _.indexOf([1, 2, 1, 2], 2, 2);
7485      * // => 3
7486      */
7487     function indexOf(array, value, fromIndex) {
7488       var length = array == null ? 0 : array.length;
7489       if (!length) {
7490         return -1;
7491       }
7492       var index = fromIndex == null ? 0 : toInteger(fromIndex);
7493       if (index < 0) {
7494         index = nativeMax(length + index, 0);
7495       }
7496       return baseIndexOf(array, value, index);
7497     }
7498
7499     /**
7500      * Gets all but the last element of `array`.
7501      *
7502      * @static
7503      * @memberOf _
7504      * @since 0.1.0
7505      * @category Array
7506      * @param {Array} array The array to query.
7507      * @returns {Array} Returns the slice of `array`.
7508      * @example
7509      *
7510      * _.initial([1, 2, 3]);
7511      * // => [1, 2]
7512      */
7513     function initial(array) {
7514       var length = array == null ? 0 : array.length;
7515       return length ? baseSlice(array, 0, -1) : [];
7516     }
7517
7518     /**
7519      * Creates an array of unique values that are included in all given arrays
7520      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7521      * for equality comparisons. The order and references of result values are
7522      * determined by the first array.
7523      *
7524      * @static
7525      * @memberOf _
7526      * @since 0.1.0
7527      * @category Array
7528      * @param {...Array} [arrays] The arrays to inspect.
7529      * @returns {Array} Returns the new array of intersecting values.
7530      * @example
7531      *
7532      * _.intersection([2, 1], [2, 3]);
7533      * // => [2]
7534      */
7535     var intersection = baseRest(function(arrays) {
7536       var mapped = arrayMap(arrays, castArrayLikeObject);
7537       return (mapped.length && mapped[0] === arrays[0])
7538         ? baseIntersection(mapped)
7539         : [];
7540     });
7541
7542     /**
7543      * This method is like `_.intersection` except that it accepts `iteratee`
7544      * which is invoked for each element of each `arrays` to generate the criterion
7545      * by which they're compared. The order and references of result values are
7546      * determined by the first array. The iteratee is invoked with one argument:
7547      * (value).
7548      *
7549      * @static
7550      * @memberOf _
7551      * @since 4.0.0
7552      * @category Array
7553      * @param {...Array} [arrays] The arrays to inspect.
7554      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7555      * @returns {Array} Returns the new array of intersecting values.
7556      * @example
7557      *
7558      * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
7559      * // => [2.1]
7560      *
7561      * // The `_.property` iteratee shorthand.
7562      * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
7563      * // => [{ 'x': 1 }]
7564      */
7565     var intersectionBy = baseRest(function(arrays) {
7566       var iteratee = last(arrays),
7567           mapped = arrayMap(arrays, castArrayLikeObject);
7568
7569       if (iteratee === last(mapped)) {
7570         iteratee = undefined;
7571       } else {
7572         mapped.pop();
7573       }
7574       return (mapped.length && mapped[0] === arrays[0])
7575         ? baseIntersection(mapped, getIteratee(iteratee, 2))
7576         : [];
7577     });
7578
7579     /**
7580      * This method is like `_.intersection` except that it accepts `comparator`
7581      * which is invoked to compare elements of `arrays`. The order and references
7582      * of result values are determined by the first array. The comparator is
7583      * invoked with two arguments: (arrVal, othVal).
7584      *
7585      * @static
7586      * @memberOf _
7587      * @since 4.0.0
7588      * @category Array
7589      * @param {...Array} [arrays] The arrays to inspect.
7590      * @param {Function} [comparator] The comparator invoked per element.
7591      * @returns {Array} Returns the new array of intersecting values.
7592      * @example
7593      *
7594      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
7595      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
7596      *
7597      * _.intersectionWith(objects, others, _.isEqual);
7598      * // => [{ 'x': 1, 'y': 2 }]
7599      */
7600     var intersectionWith = baseRest(function(arrays) {
7601       var comparator = last(arrays),
7602           mapped = arrayMap(arrays, castArrayLikeObject);
7603
7604       comparator = typeof comparator == 'function' ? comparator : undefined;
7605       if (comparator) {
7606         mapped.pop();
7607       }
7608       return (mapped.length && mapped[0] === arrays[0])
7609         ? baseIntersection(mapped, undefined, comparator)
7610         : [];
7611     });
7612
7613     /**
7614      * Converts all elements in `array` into a string separated by `separator`.
7615      *
7616      * @static
7617      * @memberOf _
7618      * @since 4.0.0
7619      * @category Array
7620      * @param {Array} array The array to convert.
7621      * @param {string} [separator=','] The element separator.
7622      * @returns {string} Returns the joined string.
7623      * @example
7624      *
7625      * _.join(['a', 'b', 'c'], '~');
7626      * // => 'a~b~c'
7627      */
7628     function join(array, separator) {
7629       return array == null ? '' : nativeJoin.call(array, separator);
7630     }
7631
7632     /**
7633      * Gets the last element of `array`.
7634      *
7635      * @static
7636      * @memberOf _
7637      * @since 0.1.0
7638      * @category Array
7639      * @param {Array} array The array to query.
7640      * @returns {*} Returns the last element of `array`.
7641      * @example
7642      *
7643      * _.last([1, 2, 3]);
7644      * // => 3
7645      */
7646     function last(array) {
7647       var length = array == null ? 0 : array.length;
7648       return length ? array[length - 1] : undefined;
7649     }
7650
7651     /**
7652      * This method is like `_.indexOf` except that it iterates over elements of
7653      * `array` from right to left.
7654      *
7655      * @static
7656      * @memberOf _
7657      * @since 0.1.0
7658      * @category Array
7659      * @param {Array} array The array to inspect.
7660      * @param {*} value The value to search for.
7661      * @param {number} [fromIndex=array.length-1] The index to search from.
7662      * @returns {number} Returns the index of the matched value, else `-1`.
7663      * @example
7664      *
7665      * _.lastIndexOf([1, 2, 1, 2], 2);
7666      * // => 3
7667      *
7668      * // Search from the `fromIndex`.
7669      * _.lastIndexOf([1, 2, 1, 2], 2, 2);
7670      * // => 1
7671      */
7672     function lastIndexOf(array, value, fromIndex) {
7673       var length = array == null ? 0 : array.length;
7674       if (!length) {
7675         return -1;
7676       }
7677       var index = length;
7678       if (fromIndex !== undefined) {
7679         index = toInteger(fromIndex);
7680         index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
7681       }
7682       return value === value
7683         ? strictLastIndexOf(array, value, index)
7684         : baseFindIndex(array, baseIsNaN, index, true);
7685     }
7686
7687     /**
7688      * Gets the element at index `n` of `array`. If `n` is negative, the nth
7689      * element from the end is returned.
7690      *
7691      * @static
7692      * @memberOf _
7693      * @since 4.11.0
7694      * @category Array
7695      * @param {Array} array The array to query.
7696      * @param {number} [n=0] The index of the element to return.
7697      * @returns {*} Returns the nth element of `array`.
7698      * @example
7699      *
7700      * var array = ['a', 'b', 'c', 'd'];
7701      *
7702      * _.nth(array, 1);
7703      * // => 'b'
7704      *
7705      * _.nth(array, -2);
7706      * // => 'c';
7707      */
7708     function nth(array, n) {
7709       return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
7710     }
7711
7712     /**
7713      * Removes all given values from `array` using
7714      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7715      * for equality comparisons.
7716      *
7717      * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
7718      * to remove elements from an array by predicate.
7719      *
7720      * @static
7721      * @memberOf _
7722      * @since 2.0.0
7723      * @category Array
7724      * @param {Array} array The array to modify.
7725      * @param {...*} [values] The values to remove.
7726      * @returns {Array} Returns `array`.
7727      * @example
7728      *
7729      * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
7730      *
7731      * _.pull(array, 'a', 'c');
7732      * console.log(array);
7733      * // => ['b', 'b']
7734      */
7735     var pull = baseRest(pullAll);
7736
7737     /**
7738      * This method is like `_.pull` except that it accepts an array of values to remove.
7739      *
7740      * **Note:** Unlike `_.difference`, this method mutates `array`.
7741      *
7742      * @static
7743      * @memberOf _
7744      * @since 4.0.0
7745      * @category Array
7746      * @param {Array} array The array to modify.
7747      * @param {Array} values The values to remove.
7748      * @returns {Array} Returns `array`.
7749      * @example
7750      *
7751      * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
7752      *
7753      * _.pullAll(array, ['a', 'c']);
7754      * console.log(array);
7755      * // => ['b', 'b']
7756      */
7757     function pullAll(array, values) {
7758       return (array && array.length && values && values.length)
7759         ? basePullAll(array, values)
7760         : array;
7761     }
7762
7763     /**
7764      * This method is like `_.pullAll` except that it accepts `iteratee` which is
7765      * invoked for each element of `array` and `values` to generate the criterion
7766      * by which they're compared. The iteratee is invoked with one argument: (value).
7767      *
7768      * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
7769      *
7770      * @static
7771      * @memberOf _
7772      * @since 4.0.0
7773      * @category Array
7774      * @param {Array} array The array to modify.
7775      * @param {Array} values The values to remove.
7776      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7777      * @returns {Array} Returns `array`.
7778      * @example
7779      *
7780      * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
7781      *
7782      * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
7783      * console.log(array);
7784      * // => [{ 'x': 2 }]
7785      */
7786     function pullAllBy(array, values, iteratee) {
7787       return (array && array.length && values && values.length)
7788         ? basePullAll(array, values, getIteratee(iteratee, 2))
7789         : array;
7790     }
7791
7792     /**
7793      * This method is like `_.pullAll` except that it accepts `comparator` which
7794      * is invoked to compare elements of `array` to `values`. The comparator is
7795      * invoked with two arguments: (arrVal, othVal).
7796      *
7797      * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
7798      *
7799      * @static
7800      * @memberOf _
7801      * @since 4.6.0
7802      * @category Array
7803      * @param {Array} array The array to modify.
7804      * @param {Array} values The values to remove.
7805      * @param {Function} [comparator] The comparator invoked per element.
7806      * @returns {Array} Returns `array`.
7807      * @example
7808      *
7809      * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
7810      *
7811      * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
7812      * console.log(array);
7813      * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
7814      */
7815     function pullAllWith(array, values, comparator) {
7816       return (array && array.length && values && values.length)
7817         ? basePullAll(array, values, undefined, comparator)
7818         : array;
7819     }
7820
7821     /**
7822      * Removes elements from `array` corresponding to `indexes` and returns an
7823      * array of removed elements.
7824      *
7825      * **Note:** Unlike `_.at`, this method mutates `array`.
7826      *
7827      * @static
7828      * @memberOf _
7829      * @since 3.0.0
7830      * @category Array
7831      * @param {Array} array The array to modify.
7832      * @param {...(number|number[])} [indexes] The indexes of elements to remove.
7833      * @returns {Array} Returns the new array of removed elements.
7834      * @example
7835      *
7836      * var array = ['a', 'b', 'c', 'd'];
7837      * var pulled = _.pullAt(array, [1, 3]);
7838      *
7839      * console.log(array);
7840      * // => ['a', 'c']
7841      *
7842      * console.log(pulled);
7843      * // => ['b', 'd']
7844      */
7845     var pullAt = flatRest(function(array, indexes) {
7846       var length = array == null ? 0 : array.length,
7847           result = baseAt(array, indexes);
7848
7849       basePullAt(array, arrayMap(indexes, function(index) {
7850         return isIndex(index, length) ? +index : index;
7851       }).sort(compareAscending));
7852
7853       return result;
7854     });
7855
7856     /**
7857      * Removes all elements from `array` that `predicate` returns truthy for
7858      * and returns an array of the removed elements. The predicate is invoked
7859      * with three arguments: (value, index, array).
7860      *
7861      * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
7862      * to pull elements from an array by value.
7863      *
7864      * @static
7865      * @memberOf _
7866      * @since 2.0.0
7867      * @category Array
7868      * @param {Array} array The array to modify.
7869      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7870      * @returns {Array} Returns the new array of removed elements.
7871      * @example
7872      *
7873      * var array = [1, 2, 3, 4];
7874      * var evens = _.remove(array, function(n) {
7875      *   return n % 2 == 0;
7876      * });
7877      *
7878      * console.log(array);
7879      * // => [1, 3]
7880      *
7881      * console.log(evens);
7882      * // => [2, 4]
7883      */
7884     function remove(array, predicate) {
7885       var result = [];
7886       if (!(array && array.length)) {
7887         return result;
7888       }
7889       var index = -1,
7890           indexes = [],
7891           length = array.length;
7892
7893       predicate = getIteratee(predicate, 3);
7894       while (++index < length) {
7895         var value = array[index];
7896         if (predicate(value, index, array)) {
7897           result.push(value);
7898           indexes.push(index);
7899         }
7900       }
7901       basePullAt(array, indexes);
7902       return result;
7903     }
7904
7905     /**
7906      * Reverses `array` so that the first element becomes the last, the second
7907      * element becomes the second to last, and so on.
7908      *
7909      * **Note:** This method mutates `array` and is based on
7910      * [`Array#reverse`](https://mdn.io/Array/reverse).
7911      *
7912      * @static
7913      * @memberOf _
7914      * @since 4.0.0
7915      * @category Array
7916      * @param {Array} array The array to modify.
7917      * @returns {Array} Returns `array`.
7918      * @example
7919      *
7920      * var array = [1, 2, 3];
7921      *
7922      * _.reverse(array);
7923      * // => [3, 2, 1]
7924      *
7925      * console.log(array);
7926      * // => [3, 2, 1]
7927      */
7928     function reverse(array) {
7929       return array == null ? array : nativeReverse.call(array);
7930     }
7931
7932     /**
7933      * Creates a slice of `array` from `start` up to, but not including, `end`.
7934      *
7935      * **Note:** This method is used instead of
7936      * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
7937      * returned.
7938      *
7939      * @static
7940      * @memberOf _
7941      * @since 3.0.0
7942      * @category Array
7943      * @param {Array} array The array to slice.
7944      * @param {number} [start=0] The start position.
7945      * @param {number} [end=array.length] The end position.
7946      * @returns {Array} Returns the slice of `array`.
7947      */
7948     function slice(array, start, end) {
7949       var length = array == null ? 0 : array.length;
7950       if (!length) {
7951         return [];
7952       }
7953       if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
7954         start = 0;
7955         end = length;
7956       }
7957       else {
7958         start = start == null ? 0 : toInteger(start);
7959         end = end === undefined ? length : toInteger(end);
7960       }
7961       return baseSlice(array, start, end);
7962     }
7963
7964     /**
7965      * Uses a binary search to determine the lowest index at which `value`
7966      * should be inserted into `array` in order to maintain its sort order.
7967      *
7968      * @static
7969      * @memberOf _
7970      * @since 0.1.0
7971      * @category Array
7972      * @param {Array} array The sorted array to inspect.
7973      * @param {*} value The value to evaluate.
7974      * @returns {number} Returns the index at which `value` should be inserted
7975      *  into `array`.
7976      * @example
7977      *
7978      * _.sortedIndex([30, 50], 40);
7979      * // => 1
7980      */
7981     function sortedIndex(array, value) {
7982       return baseSortedIndex(array, value);
7983     }
7984
7985     /**
7986      * This method is like `_.sortedIndex` except that it accepts `iteratee`
7987      * which is invoked for `value` and each element of `array` to compute their
7988      * sort ranking. The iteratee is invoked with one argument: (value).
7989      *
7990      * @static
7991      * @memberOf _
7992      * @since 4.0.0
7993      * @category Array
7994      * @param {Array} array The sorted array to inspect.
7995      * @param {*} value The value to evaluate.
7996      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7997      * @returns {number} Returns the index at which `value` should be inserted
7998      *  into `array`.
7999      * @example
8000      *
8001      * var objects = [{ 'x': 4 }, { 'x': 5 }];
8002      *
8003      * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
8004      * // => 0
8005      *
8006      * // The `_.property` iteratee shorthand.
8007      * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
8008      * // => 0
8009      */
8010     function sortedIndexBy(array, value, iteratee) {
8011       return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
8012     }
8013
8014     /**
8015      * This method is like `_.indexOf` except that it performs a binary
8016      * search on a sorted `array`.
8017      *
8018      * @static
8019      * @memberOf _
8020      * @since 4.0.0
8021      * @category Array
8022      * @param {Array} array The array to inspect.
8023      * @param {*} value The value to search for.
8024      * @returns {number} Returns the index of the matched value, else `-1`.
8025      * @example
8026      *
8027      * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
8028      * // => 1
8029      */
8030     function sortedIndexOf(array, value) {
8031       var length = array == null ? 0 : array.length;
8032       if (length) {
8033         var index = baseSortedIndex(array, value);
8034         if (index < length && eq(array[index], value)) {
8035           return index;
8036         }
8037       }
8038       return -1;
8039     }
8040
8041     /**
8042      * This method is like `_.sortedIndex` except that it returns the highest
8043      * index at which `value` should be inserted into `array` in order to
8044      * maintain its sort order.
8045      *
8046      * @static
8047      * @memberOf _
8048      * @since 3.0.0
8049      * @category Array
8050      * @param {Array} array The sorted array to inspect.
8051      * @param {*} value The value to evaluate.
8052      * @returns {number} Returns the index at which `value` should be inserted
8053      *  into `array`.
8054      * @example
8055      *
8056      * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
8057      * // => 4
8058      */
8059     function sortedLastIndex(array, value) {
8060       return baseSortedIndex(array, value, true);
8061     }
8062
8063     /**
8064      * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
8065      * which is invoked for `value` and each element of `array` to compute their
8066      * sort ranking. The iteratee is invoked with one argument: (value).
8067      *
8068      * @static
8069      * @memberOf _
8070      * @since 4.0.0
8071      * @category Array
8072      * @param {Array} array The sorted array to inspect.
8073      * @param {*} value The value to evaluate.
8074      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8075      * @returns {number} Returns the index at which `value` should be inserted
8076      *  into `array`.
8077      * @example
8078      *
8079      * var objects = [{ 'x': 4 }, { 'x': 5 }];
8080      *
8081      * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
8082      * // => 1
8083      *
8084      * // The `_.property` iteratee shorthand.
8085      * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
8086      * // => 1
8087      */
8088     function sortedLastIndexBy(array, value, iteratee) {
8089       return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
8090     }
8091
8092     /**
8093      * This method is like `_.lastIndexOf` except that it performs a binary
8094      * search on a sorted `array`.
8095      *
8096      * @static
8097      * @memberOf _
8098      * @since 4.0.0
8099      * @category Array
8100      * @param {Array} array The array to inspect.
8101      * @param {*} value The value to search for.
8102      * @returns {number} Returns the index of the matched value, else `-1`.
8103      * @example
8104      *
8105      * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
8106      * // => 3
8107      */
8108     function sortedLastIndexOf(array, value) {
8109       var length = array == null ? 0 : array.length;
8110       if (length) {
8111         var index = baseSortedIndex(array, value, true) - 1;
8112         if (eq(array[index], value)) {
8113           return index;
8114         }
8115       }
8116       return -1;
8117     }
8118
8119     /**
8120      * This method is like `_.uniq` except that it's designed and optimized
8121      * for sorted arrays.
8122      *
8123      * @static
8124      * @memberOf _
8125      * @since 4.0.0
8126      * @category Array
8127      * @param {Array} array The array to inspect.
8128      * @returns {Array} Returns the new duplicate free array.
8129      * @example
8130      *
8131      * _.sortedUniq([1, 1, 2]);
8132      * // => [1, 2]
8133      */
8134     function sortedUniq(array) {
8135       return (array && array.length)
8136         ? baseSortedUniq(array)
8137         : [];
8138     }
8139
8140     /**
8141      * This method is like `_.uniqBy` except that it's designed and optimized
8142      * for sorted arrays.
8143      *
8144      * @static
8145      * @memberOf _
8146      * @since 4.0.0
8147      * @category Array
8148      * @param {Array} array The array to inspect.
8149      * @param {Function} [iteratee] The iteratee invoked per element.
8150      * @returns {Array} Returns the new duplicate free array.
8151      * @example
8152      *
8153      * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
8154      * // => [1.1, 2.3]
8155      */
8156     function sortedUniqBy(array, iteratee) {
8157       return (array && array.length)
8158         ? baseSortedUniq(array, getIteratee(iteratee, 2))
8159         : [];
8160     }
8161
8162     /**
8163      * Gets all but the first element of `array`.
8164      *
8165      * @static
8166      * @memberOf _
8167      * @since 4.0.0
8168      * @category Array
8169      * @param {Array} array The array to query.
8170      * @returns {Array} Returns the slice of `array`.
8171      * @example
8172      *
8173      * _.tail([1, 2, 3]);
8174      * // => [2, 3]
8175      */
8176     function tail(array) {
8177       var length = array == null ? 0 : array.length;
8178       return length ? baseSlice(array, 1, length) : [];
8179     }
8180
8181     /**
8182      * Creates a slice of `array` with `n` elements taken from the beginning.
8183      *
8184      * @static
8185      * @memberOf _
8186      * @since 0.1.0
8187      * @category Array
8188      * @param {Array} array The array to query.
8189      * @param {number} [n=1] The number of elements to take.
8190      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8191      * @returns {Array} Returns the slice of `array`.
8192      * @example
8193      *
8194      * _.take([1, 2, 3]);
8195      * // => [1]
8196      *
8197      * _.take([1, 2, 3], 2);
8198      * // => [1, 2]
8199      *
8200      * _.take([1, 2, 3], 5);
8201      * // => [1, 2, 3]
8202      *
8203      * _.take([1, 2, 3], 0);
8204      * // => []
8205      */
8206     function take(array, n, guard) {
8207       if (!(array && array.length)) {
8208         return [];
8209       }
8210       n = (guard || n === undefined) ? 1 : toInteger(n);
8211       return baseSlice(array, 0, n < 0 ? 0 : n);
8212     }
8213
8214     /**
8215      * Creates a slice of `array` with `n` elements taken from the end.
8216      *
8217      * @static
8218      * @memberOf _
8219      * @since 3.0.0
8220      * @category Array
8221      * @param {Array} array The array to query.
8222      * @param {number} [n=1] The number of elements to take.
8223      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8224      * @returns {Array} Returns the slice of `array`.
8225      * @example
8226      *
8227      * _.takeRight([1, 2, 3]);
8228      * // => [3]
8229      *
8230      * _.takeRight([1, 2, 3], 2);
8231      * // => [2, 3]
8232      *
8233      * _.takeRight([1, 2, 3], 5);
8234      * // => [1, 2, 3]
8235      *
8236      * _.takeRight([1, 2, 3], 0);
8237      * // => []
8238      */
8239     function takeRight(array, n, guard) {
8240       var length = array == null ? 0 : array.length;
8241       if (!length) {
8242         return [];
8243       }
8244       n = (guard || n === undefined) ? 1 : toInteger(n);
8245       n = length - n;
8246       return baseSlice(array, n < 0 ? 0 : n, length);
8247     }
8248
8249     /**
8250      * Creates a slice of `array` with elements taken from the end. Elements are
8251      * taken until `predicate` returns falsey. The predicate is invoked with
8252      * three arguments: (value, index, array).
8253      *
8254      * @static
8255      * @memberOf _
8256      * @since 3.0.0
8257      * @category Array
8258      * @param {Array} array The array to query.
8259      * @param {Function} [predicate=_.identity] The function invoked per iteration.
8260      * @returns {Array} Returns the slice of `array`.
8261      * @example
8262      *
8263      * var users = [
8264      *   { 'user': 'barney',  'active': true },
8265      *   { 'user': 'fred',    'active': false },
8266      *   { 'user': 'pebbles', 'active': false }
8267      * ];
8268      *
8269      * _.takeRightWhile(users, function(o) { return !o.active; });
8270      * // => objects for ['fred', 'pebbles']
8271      *
8272      * // The `_.matches` iteratee shorthand.
8273      * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
8274      * // => objects for ['pebbles']
8275      *
8276      * // The `_.matchesProperty` iteratee shorthand.
8277      * _.takeRightWhile(users, ['active', false]);
8278      * // => objects for ['fred', 'pebbles']
8279      *
8280      * // The `_.property` iteratee shorthand.
8281      * _.takeRightWhile(users, 'active');
8282      * // => []
8283      */
8284     function takeRightWhile(array, predicate) {
8285       return (array && array.length)
8286         ? baseWhile(array, getIteratee(predicate, 3), false, true)
8287         : [];
8288     }
8289
8290     /**
8291      * Creates a slice of `array` with elements taken from the beginning. Elements
8292      * are taken until `predicate` returns falsey. The predicate is invoked with
8293      * three arguments: (value, index, array).
8294      *
8295      * @static
8296      * @memberOf _
8297      * @since 3.0.0
8298      * @category Array
8299      * @param {Array} array The array to query.
8300      * @param {Function} [predicate=_.identity] The function invoked per iteration.
8301      * @returns {Array} Returns the slice of `array`.
8302      * @example
8303      *
8304      * var users = [
8305      *   { 'user': 'barney',  'active': false },
8306      *   { 'user': 'fred',    'active': false },
8307      *   { 'user': 'pebbles', 'active': true }
8308      * ];
8309      *
8310      * _.takeWhile(users, function(o) { return !o.active; });
8311      * // => objects for ['barney', 'fred']
8312      *
8313      * // The `_.matches` iteratee shorthand.
8314      * _.takeWhile(users, { 'user': 'barney', 'active': false });
8315      * // => objects for ['barney']
8316      *
8317      * // The `_.matchesProperty` iteratee shorthand.
8318      * _.takeWhile(users, ['active', false]);
8319      * // => objects for ['barney', 'fred']
8320      *
8321      * // The `_.property` iteratee shorthand.
8322      * _.takeWhile(users, 'active');
8323      * // => []
8324      */
8325     function takeWhile(array, predicate) {
8326       return (array && array.length)
8327         ? baseWhile(array, getIteratee(predicate, 3))
8328         : [];
8329     }
8330
8331     /**
8332      * Creates an array of unique values, in order, from all given arrays using
8333      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8334      * for equality comparisons.
8335      *
8336      * @static
8337      * @memberOf _
8338      * @since 0.1.0
8339      * @category Array
8340      * @param {...Array} [arrays] The arrays to inspect.
8341      * @returns {Array} Returns the new array of combined values.
8342      * @example
8343      *
8344      * _.union([2], [1, 2]);
8345      * // => [2, 1]
8346      */
8347     var union = baseRest(function(arrays) {
8348       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
8349     });
8350
8351     /**
8352      * This method is like `_.union` except that it accepts `iteratee` which is
8353      * invoked for each element of each `arrays` to generate the criterion by
8354      * which uniqueness is computed. Result values are chosen from the first
8355      * array in which the value occurs. The iteratee is invoked with one argument:
8356      * (value).
8357      *
8358      * @static
8359      * @memberOf _
8360      * @since 4.0.0
8361      * @category Array
8362      * @param {...Array} [arrays] The arrays to inspect.
8363      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8364      * @returns {Array} Returns the new array of combined values.
8365      * @example
8366      *
8367      * _.unionBy([2.1], [1.2, 2.3], Math.floor);
8368      * // => [2.1, 1.2]
8369      *
8370      * // The `_.property` iteratee shorthand.
8371      * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
8372      * // => [{ 'x': 1 }, { 'x': 2 }]
8373      */
8374     var unionBy = baseRest(function(arrays) {
8375       var iteratee = last(arrays);
8376       if (isArrayLikeObject(iteratee)) {
8377         iteratee = undefined;
8378       }
8379       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
8380     });
8381
8382     /**
8383      * This method is like `_.union` except that it accepts `comparator` which
8384      * is invoked to compare elements of `arrays`. Result values are chosen from
8385      * the first array in which the value occurs. The comparator is invoked
8386      * with two arguments: (arrVal, othVal).
8387      *
8388      * @static
8389      * @memberOf _
8390      * @since 4.0.0
8391      * @category Array
8392      * @param {...Array} [arrays] The arrays to inspect.
8393      * @param {Function} [comparator] The comparator invoked per element.
8394      * @returns {Array} Returns the new array of combined values.
8395      * @example
8396      *
8397      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
8398      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
8399      *
8400      * _.unionWith(objects, others, _.isEqual);
8401      * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
8402      */
8403     var unionWith = baseRest(function(arrays) {
8404       var comparator = last(arrays);
8405       comparator = typeof comparator == 'function' ? comparator : undefined;
8406       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
8407     });
8408
8409     /**
8410      * Creates a duplicate-free version of an array, using
8411      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8412      * for equality comparisons, in which only the first occurrence of each element
8413      * is kept. The order of result values is determined by the order they occur
8414      * in the array.
8415      *
8416      * @static
8417      * @memberOf _
8418      * @since 0.1.0
8419      * @category Array
8420      * @param {Array} array The array to inspect.
8421      * @returns {Array} Returns the new duplicate free array.
8422      * @example
8423      *
8424      * _.uniq([2, 1, 2]);
8425      * // => [2, 1]
8426      */
8427     function uniq(array) {
8428       return (array && array.length) ? baseUniq(array) : [];
8429     }
8430
8431     /**
8432      * This method is like `_.uniq` except that it accepts `iteratee` which is
8433      * invoked for each element in `array` to generate the criterion by which
8434      * uniqueness is computed. The order of result values is determined by the
8435      * order they occur in the array. The iteratee is invoked with one argument:
8436      * (value).
8437      *
8438      * @static
8439      * @memberOf _
8440      * @since 4.0.0
8441      * @category Array
8442      * @param {Array} array The array to inspect.
8443      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8444      * @returns {Array} Returns the new duplicate free array.
8445      * @example
8446      *
8447      * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
8448      * // => [2.1, 1.2]
8449      *
8450      * // The `_.property` iteratee shorthand.
8451      * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
8452      * // => [{ 'x': 1 }, { 'x': 2 }]
8453      */
8454     function uniqBy(array, iteratee) {
8455       return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : [];
8456     }
8457
8458     /**
8459      * This method is like `_.uniq` except that it accepts `comparator` which
8460      * is invoked to compare elements of `array`. The order of result values is
8461      * determined by the order they occur in the array.The comparator is invoked
8462      * with two arguments: (arrVal, othVal).
8463      *
8464      * @static
8465      * @memberOf _
8466      * @since 4.0.0
8467      * @category Array
8468      * @param {Array} array The array to inspect.
8469      * @param {Function} [comparator] The comparator invoked per element.
8470      * @returns {Array} Returns the new duplicate free array.
8471      * @example
8472      *
8473      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
8474      *
8475      * _.uniqWith(objects, _.isEqual);
8476      * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
8477      */
8478     function uniqWith(array, comparator) {
8479       comparator = typeof comparator == 'function' ? comparator : undefined;
8480       return (array && array.length) ? baseUniq(array, undefined, comparator) : [];
8481     }
8482
8483     /**
8484      * This method is like `_.zip` except that it accepts an array of grouped
8485      * elements and creates an array regrouping the elements to their pre-zip
8486      * configuration.
8487      *
8488      * @static
8489      * @memberOf _
8490      * @since 1.2.0
8491      * @category Array
8492      * @param {Array} array The array of grouped elements to process.
8493      * @returns {Array} Returns the new array of regrouped elements.
8494      * @example
8495      *
8496      * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
8497      * // => [['a', 1, true], ['b', 2, false]]
8498      *
8499      * _.unzip(zipped);
8500      * // => [['a', 'b'], [1, 2], [true, false]]
8501      */
8502     function unzip(array) {
8503       if (!(array && array.length)) {
8504         return [];
8505       }
8506       var length = 0;
8507       array = arrayFilter(array, function(group) {
8508         if (isArrayLikeObject(group)) {
8509           length = nativeMax(group.length, length);
8510           return true;
8511         }
8512       });
8513       return baseTimes(length, function(index) {
8514         return arrayMap(array, baseProperty(index));
8515       });
8516     }
8517
8518     /**
8519      * This method is like `_.unzip` except that it accepts `iteratee` to specify
8520      * how regrouped values should be combined. The iteratee is invoked with the
8521      * elements of each group: (...group).
8522      *
8523      * @static
8524      * @memberOf _
8525      * @since 3.8.0
8526      * @category Array
8527      * @param {Array} array The array of grouped elements to process.
8528      * @param {Function} [iteratee=_.identity] The function to combine
8529      *  regrouped values.
8530      * @returns {Array} Returns the new array of regrouped elements.
8531      * @example
8532      *
8533      * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
8534      * // => [[1, 10, 100], [2, 20, 200]]
8535      *
8536      * _.unzipWith(zipped, _.add);
8537      * // => [3, 30, 300]
8538      */
8539     function unzipWith(array, iteratee) {
8540       if (!(array && array.length)) {
8541         return [];
8542       }
8543       var result = unzip(array);
8544       if (iteratee == null) {
8545         return result;
8546       }
8547       return arrayMap(result, function(group) {
8548         return apply(iteratee, undefined, group);
8549       });
8550     }
8551
8552     /**
8553      * Creates an array excluding all given values using
8554      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8555      * for equality comparisons.
8556      *
8557      * **Note:** Unlike `_.pull`, this method returns a new array.
8558      *
8559      * @static
8560      * @memberOf _
8561      * @since 0.1.0
8562      * @category Array
8563      * @param {Array} array The array to inspect.
8564      * @param {...*} [values] The values to exclude.
8565      * @returns {Array} Returns the new array of filtered values.
8566      * @see _.difference, _.xor
8567      * @example
8568      *
8569      * _.without([2, 1, 2, 3], 1, 2);
8570      * // => [3]
8571      */
8572     var without = baseRest(function(array, values) {
8573       return isArrayLikeObject(array)
8574         ? baseDifference(array, values)
8575         : [];
8576     });
8577
8578     /**
8579      * Creates an array of unique values that is the
8580      * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
8581      * of the given arrays. The order of result values is determined by the order
8582      * they occur in the arrays.
8583      *
8584      * @static
8585      * @memberOf _
8586      * @since 2.4.0
8587      * @category Array
8588      * @param {...Array} [arrays] The arrays to inspect.
8589      * @returns {Array} Returns the new array of filtered values.
8590      * @see _.difference, _.without
8591      * @example
8592      *
8593      * _.xor([2, 1], [2, 3]);
8594      * // => [1, 3]
8595      */
8596     var xor = baseRest(function(arrays) {
8597       return baseXor(arrayFilter(arrays, isArrayLikeObject));
8598     });
8599
8600     /**
8601      * This method is like `_.xor` except that it accepts `iteratee` which is
8602      * invoked for each element of each `arrays` to generate the criterion by
8603      * which by which they're compared. The order of result values is determined
8604      * by the order they occur in the arrays. The iteratee is invoked with one
8605      * argument: (value).
8606      *
8607      * @static
8608      * @memberOf _
8609      * @since 4.0.0
8610      * @category Array
8611      * @param {...Array} [arrays] The arrays to inspect.
8612      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8613      * @returns {Array} Returns the new array of filtered values.
8614      * @example
8615      *
8616      * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
8617      * // => [1.2, 3.4]
8618      *
8619      * // The `_.property` iteratee shorthand.
8620      * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
8621      * // => [{ 'x': 2 }]
8622      */
8623     var xorBy = baseRest(function(arrays) {
8624       var iteratee = last(arrays);
8625       if (isArrayLikeObject(iteratee)) {
8626         iteratee = undefined;
8627       }
8628       return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
8629     });
8630
8631     /**
8632      * This method is like `_.xor` except that it accepts `comparator` which is
8633      * invoked to compare elements of `arrays`. The order of result values is
8634      * determined by the order they occur in the arrays. The comparator is invoked
8635      * with two arguments: (arrVal, othVal).
8636      *
8637      * @static
8638      * @memberOf _
8639      * @since 4.0.0
8640      * @category Array
8641      * @param {...Array} [arrays] The arrays to inspect.
8642      * @param {Function} [comparator] The comparator invoked per element.
8643      * @returns {Array} Returns the new array of filtered values.
8644      * @example
8645      *
8646      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
8647      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
8648      *
8649      * _.xorWith(objects, others, _.isEqual);
8650      * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
8651      */
8652     var xorWith = baseRest(function(arrays) {
8653       var comparator = last(arrays);
8654       comparator = typeof comparator == 'function' ? comparator : undefined;
8655       return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
8656     });
8657
8658     /**
8659      * Creates an array of grouped elements, the first of which contains the
8660      * first elements of the given arrays, the second of which contains the
8661      * second elements of the given arrays, and so on.
8662      *
8663      * @static
8664      * @memberOf _
8665      * @since 0.1.0
8666      * @category Array
8667      * @param {...Array} [arrays] The arrays to process.
8668      * @returns {Array} Returns the new array of grouped elements.
8669      * @example
8670      *
8671      * _.zip(['a', 'b'], [1, 2], [true, false]);
8672      * // => [['a', 1, true], ['b', 2, false]]
8673      */
8674     var zip = baseRest(unzip);
8675
8676     /**
8677      * This method is like `_.fromPairs` except that it accepts two arrays,
8678      * one of property identifiers and one of corresponding values.
8679      *
8680      * @static
8681      * @memberOf _
8682      * @since 0.4.0
8683      * @category Array
8684      * @param {Array} [props=[]] The property identifiers.
8685      * @param {Array} [values=[]] The property values.
8686      * @returns {Object} Returns the new object.
8687      * @example
8688      *
8689      * _.zipObject(['a', 'b'], [1, 2]);
8690      * // => { 'a': 1, 'b': 2 }
8691      */
8692     function zipObject(props, values) {
8693       return baseZipObject(props || [], values || [], assignValue);
8694     }
8695
8696     /**
8697      * This method is like `_.zipObject` except that it supports property paths.
8698      *
8699      * @static
8700      * @memberOf _
8701      * @since 4.1.0
8702      * @category Array
8703      * @param {Array} [props=[]] The property identifiers.
8704      * @param {Array} [values=[]] The property values.
8705      * @returns {Object} Returns the new object.
8706      * @example
8707      *
8708      * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
8709      * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
8710      */
8711     function zipObjectDeep(props, values) {
8712       return baseZipObject(props || [], values || [], baseSet);
8713     }
8714
8715     /**
8716      * This method is like `_.zip` except that it accepts `iteratee` to specify
8717      * how grouped values should be combined. The iteratee is invoked with the
8718      * elements of each group: (...group).
8719      *
8720      * @static
8721      * @memberOf _
8722      * @since 3.8.0
8723      * @category Array
8724      * @param {...Array} [arrays] The arrays to process.
8725      * @param {Function} [iteratee=_.identity] The function to combine
8726      *  grouped values.
8727      * @returns {Array} Returns the new array of grouped elements.
8728      * @example
8729      *
8730      * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
8731      *   return a + b + c;
8732      * });
8733      * // => [111, 222]
8734      */
8735     var zipWith = baseRest(function(arrays) {
8736       var length = arrays.length,
8737           iteratee = length > 1 ? arrays[length - 1] : undefined;
8738
8739       iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
8740       return unzipWith(arrays, iteratee);
8741     });
8742
8743     /*------------------------------------------------------------------------*/
8744
8745     /**
8746      * Creates a `lodash` wrapper instance that wraps `value` with explicit method
8747      * chain sequences enabled. The result of such sequences must be unwrapped
8748      * with `_#value`.
8749      *
8750      * @static
8751      * @memberOf _
8752      * @since 1.3.0
8753      * @category Seq
8754      * @param {*} value The value to wrap.
8755      * @returns {Object} Returns the new `lodash` wrapper instance.
8756      * @example
8757      *
8758      * var users = [
8759      *   { 'user': 'barney',  'age': 36 },
8760      *   { 'user': 'fred',    'age': 40 },
8761      *   { 'user': 'pebbles', 'age': 1 }
8762      * ];
8763      *
8764      * var youngest = _
8765      *   .chain(users)
8766      *   .sortBy('age')
8767      *   .map(function(o) {
8768      *     return o.user + ' is ' + o.age;
8769      *   })
8770      *   .head()
8771      *   .value();
8772      * // => 'pebbles is 1'
8773      */
8774     function chain(value) {
8775       var result = lodash(value);
8776       result.__chain__ = true;
8777       return result;
8778     }
8779
8780     /**
8781      * This method invokes `interceptor` and returns `value`. The interceptor
8782      * is invoked with one argument; (value). The purpose of this method is to
8783      * "tap into" a method chain sequence in order to modify intermediate results.
8784      *
8785      * @static
8786      * @memberOf _
8787      * @since 0.1.0
8788      * @category Seq
8789      * @param {*} value The value to provide to `interceptor`.
8790      * @param {Function} interceptor The function to invoke.
8791      * @returns {*} Returns `value`.
8792      * @example
8793      *
8794      * _([1, 2, 3])
8795      *  .tap(function(array) {
8796      *    // Mutate input array.
8797      *    array.pop();
8798      *  })
8799      *  .reverse()
8800      *  .value();
8801      * // => [2, 1]
8802      */
8803     function tap(value, interceptor) {
8804       interceptor(value);
8805       return value;
8806     }
8807
8808     /**
8809      * This method is like `_.tap` except that it returns the result of `interceptor`.
8810      * The purpose of this method is to "pass thru" values replacing intermediate
8811      * results in a method chain sequence.
8812      *
8813      * @static
8814      * @memberOf _
8815      * @since 3.0.0
8816      * @category Seq
8817      * @param {*} value The value to provide to `interceptor`.
8818      * @param {Function} interceptor The function to invoke.
8819      * @returns {*} Returns the result of `interceptor`.
8820      * @example
8821      *
8822      * _('  abc  ')
8823      *  .chain()
8824      *  .trim()
8825      *  .thru(function(value) {
8826      *    return [value];
8827      *  })
8828      *  .value();
8829      * // => ['abc']
8830      */
8831     function thru(value, interceptor) {
8832       return interceptor(value);
8833     }
8834
8835     /**
8836      * This method is the wrapper version of `_.at`.
8837      *
8838      * @name at
8839      * @memberOf _
8840      * @since 1.0.0
8841      * @category Seq
8842      * @param {...(string|string[])} [paths] The property paths to pick.
8843      * @returns {Object} Returns the new `lodash` wrapper instance.
8844      * @example
8845      *
8846      * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
8847      *
8848      * _(object).at(['a[0].b.c', 'a[1]']).value();
8849      * // => [3, 4]
8850      */
8851     var wrapperAt = flatRest(function(paths) {
8852       var length = paths.length,
8853           start = length ? paths[0] : 0,
8854           value = this.__wrapped__,
8855           interceptor = function(object) { return baseAt(object, paths); };
8856
8857       if (length > 1 || this.__actions__.length ||
8858           !(value instanceof LazyWrapper) || !isIndex(start)) {
8859         return this.thru(interceptor);
8860       }
8861       value = value.slice(start, +start + (length ? 1 : 0));
8862       value.__actions__.push({
8863         'func': thru,
8864         'args': [interceptor],
8865         'thisArg': undefined
8866       });
8867       return new LodashWrapper(value, this.__chain__).thru(function(array) {
8868         if (length && !array.length) {
8869           array.push(undefined);
8870         }
8871         return array;
8872       });
8873     });
8874
8875     /**
8876      * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
8877      *
8878      * @name chain
8879      * @memberOf _
8880      * @since 0.1.0
8881      * @category Seq
8882      * @returns {Object} Returns the new `lodash` wrapper instance.
8883      * @example
8884      *
8885      * var users = [
8886      *   { 'user': 'barney', 'age': 36 },
8887      *   { 'user': 'fred',   'age': 40 }
8888      * ];
8889      *
8890      * // A sequence without explicit chaining.
8891      * _(users).head();
8892      * // => { 'user': 'barney', 'age': 36 }
8893      *
8894      * // A sequence with explicit chaining.
8895      * _(users)
8896      *   .chain()
8897      *   .head()
8898      *   .pick('user')
8899      *   .value();
8900      * // => { 'user': 'barney' }
8901      */
8902     function wrapperChain() {
8903       return chain(this);
8904     }
8905
8906     /**
8907      * Executes the chain sequence and returns the wrapped result.
8908      *
8909      * @name commit
8910      * @memberOf _
8911      * @since 3.2.0
8912      * @category Seq
8913      * @returns {Object} Returns the new `lodash` wrapper instance.
8914      * @example
8915      *
8916      * var array = [1, 2];
8917      * var wrapped = _(array).push(3);
8918      *
8919      * console.log(array);
8920      * // => [1, 2]
8921      *
8922      * wrapped = wrapped.commit();
8923      * console.log(array);
8924      * // => [1, 2, 3]
8925      *
8926      * wrapped.last();
8927      * // => 3
8928      *
8929      * console.log(array);
8930      * // => [1, 2, 3]
8931      */
8932     function wrapperCommit() {
8933       return new LodashWrapper(this.value(), this.__chain__);
8934     }
8935
8936     /**
8937      * Gets the next value on a wrapped object following the
8938      * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
8939      *
8940      * @name next
8941      * @memberOf _
8942      * @since 4.0.0
8943      * @category Seq
8944      * @returns {Object} Returns the next iterator value.
8945      * @example
8946      *
8947      * var wrapped = _([1, 2]);
8948      *
8949      * wrapped.next();
8950      * // => { 'done': false, 'value': 1 }
8951      *
8952      * wrapped.next();
8953      * // => { 'done': false, 'value': 2 }
8954      *
8955      * wrapped.next();
8956      * // => { 'done': true, 'value': undefined }
8957      */
8958     function wrapperNext() {
8959       if (this.__values__ === undefined) {
8960         this.__values__ = toArray(this.value());
8961       }
8962       var done = this.__index__ >= this.__values__.length,
8963           value = done ? undefined : this.__values__[this.__index__++];
8964
8965       return { 'done': done, 'value': value };
8966     }
8967
8968     /**
8969      * Enables the wrapper to be iterable.
8970      *
8971      * @name Symbol.iterator
8972      * @memberOf _
8973      * @since 4.0.0
8974      * @category Seq
8975      * @returns {Object} Returns the wrapper object.
8976      * @example
8977      *
8978      * var wrapped = _([1, 2]);
8979      *
8980      * wrapped[Symbol.iterator]() === wrapped;
8981      * // => true
8982      *
8983      * Array.from(wrapped);
8984      * // => [1, 2]
8985      */
8986     function wrapperToIterator() {
8987       return this;
8988     }
8989
8990     /**
8991      * Creates a clone of the chain sequence planting `value` as the wrapped value.
8992      *
8993      * @name plant
8994      * @memberOf _
8995      * @since 3.2.0
8996      * @category Seq
8997      * @param {*} value The value to plant.
8998      * @returns {Object} Returns the new `lodash` wrapper instance.
8999      * @example
9000      *
9001      * function square(n) {
9002      *   return n * n;
9003      * }
9004      *
9005      * var wrapped = _([1, 2]).map(square);
9006      * var other = wrapped.plant([3, 4]);
9007      *
9008      * other.value();
9009      * // => [9, 16]
9010      *
9011      * wrapped.value();
9012      * // => [1, 4]
9013      */
9014     function wrapperPlant(value) {
9015       var result,
9016           parent = this;
9017
9018       while (parent instanceof baseLodash) {
9019         var clone = wrapperClone(parent);
9020         clone.__index__ = 0;
9021         clone.__values__ = undefined;
9022         if (result) {
9023           previous.__wrapped__ = clone;
9024         } else {
9025           result = clone;
9026         }
9027         var previous = clone;
9028         parent = parent.__wrapped__;
9029       }
9030       previous.__wrapped__ = value;
9031       return result;
9032     }
9033
9034     /**
9035      * This method is the wrapper version of `_.reverse`.
9036      *
9037      * **Note:** This method mutates the wrapped array.
9038      *
9039      * @name reverse
9040      * @memberOf _
9041      * @since 0.1.0
9042      * @category Seq
9043      * @returns {Object} Returns the new `lodash` wrapper instance.
9044      * @example
9045      *
9046      * var array = [1, 2, 3];
9047      *
9048      * _(array).reverse().value()
9049      * // => [3, 2, 1]
9050      *
9051      * console.log(array);
9052      * // => [3, 2, 1]
9053      */
9054     function wrapperReverse() {
9055       var value = this.__wrapped__;
9056       if (value instanceof LazyWrapper) {
9057         var wrapped = value;
9058         if (this.__actions__.length) {
9059           wrapped = new LazyWrapper(this);
9060         }
9061         wrapped = wrapped.reverse();
9062         wrapped.__actions__.push({
9063           'func': thru,
9064           'args': [reverse],
9065           'thisArg': undefined
9066         });
9067         return new LodashWrapper(wrapped, this.__chain__);
9068       }
9069       return this.thru(reverse);
9070     }
9071
9072     /**
9073      * Executes the chain sequence to resolve the unwrapped value.
9074      *
9075      * @name value
9076      * @memberOf _
9077      * @since 0.1.0
9078      * @alias toJSON, valueOf
9079      * @category Seq
9080      * @returns {*} Returns the resolved unwrapped value.
9081      * @example
9082      *
9083      * _([1, 2, 3]).value();
9084      * // => [1, 2, 3]
9085      */
9086     function wrapperValue() {
9087       return baseWrapperValue(this.__wrapped__, this.__actions__);
9088     }
9089
9090     /*------------------------------------------------------------------------*/
9091
9092     /**
9093      * Creates an object composed of keys generated from the results of running
9094      * each element of `collection` thru `iteratee`. The corresponding value of
9095      * each key is the number of times the key was returned by `iteratee`. The
9096      * iteratee is invoked with one argument: (value).
9097      *
9098      * @static
9099      * @memberOf _
9100      * @since 0.5.0
9101      * @category Collection
9102      * @param {Array|Object} collection The collection to iterate over.
9103      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9104      * @returns {Object} Returns the composed aggregate object.
9105      * @example
9106      *
9107      * _.countBy([6.1, 4.2, 6.3], Math.floor);
9108      * // => { '4': 1, '6': 2 }
9109      *
9110      * // The `_.property` iteratee shorthand.
9111      * _.countBy(['one', 'two', 'three'], 'length');
9112      * // => { '3': 2, '5': 1 }
9113      */
9114     var countBy = createAggregator(function(result, value, key) {
9115       if (hasOwnProperty.call(result, key)) {
9116         ++result[key];
9117       } else {
9118         baseAssignValue(result, key, 1);
9119       }
9120     });
9121
9122     /**
9123      * Checks if `predicate` returns truthy for **all** elements of `collection`.
9124      * Iteration is stopped once `predicate` returns falsey. The predicate is
9125      * invoked with three arguments: (value, index|key, collection).
9126      *
9127      * **Note:** This method returns `true` for
9128      * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
9129      * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
9130      * elements of empty collections.
9131      *
9132      * @static
9133      * @memberOf _
9134      * @since 0.1.0
9135      * @category Collection
9136      * @param {Array|Object} collection The collection to iterate over.
9137      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9138      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9139      * @returns {boolean} Returns `true` if all elements pass the predicate check,
9140      *  else `false`.
9141      * @example
9142      *
9143      * _.every([true, 1, null, 'yes'], Boolean);
9144      * // => false
9145      *
9146      * var users = [
9147      *   { 'user': 'barney', 'age': 36, 'active': false },
9148      *   { 'user': 'fred',   'age': 40, 'active': false }
9149      * ];
9150      *
9151      * // The `_.matches` iteratee shorthand.
9152      * _.every(users, { 'user': 'barney', 'active': false });
9153      * // => false
9154      *
9155      * // The `_.matchesProperty` iteratee shorthand.
9156      * _.every(users, ['active', false]);
9157      * // => true
9158      *
9159      * // The `_.property` iteratee shorthand.
9160      * _.every(users, 'active');
9161      * // => false
9162      */
9163     function every(collection, predicate, guard) {
9164       var func = isArray(collection) ? arrayEvery : baseEvery;
9165       if (guard && isIterateeCall(collection, predicate, guard)) {
9166         predicate = undefined;
9167       }
9168       return func(collection, getIteratee(predicate, 3));
9169     }
9170
9171     /**
9172      * Iterates over elements of `collection`, returning an array of all elements
9173      * `predicate` returns truthy for. The predicate is invoked with three
9174      * arguments: (value, index|key, collection).
9175      *
9176      * **Note:** Unlike `_.remove`, this method returns a new array.
9177      *
9178      * @static
9179      * @memberOf _
9180      * @since 0.1.0
9181      * @category Collection
9182      * @param {Array|Object} collection The collection to iterate over.
9183      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9184      * @returns {Array} Returns the new filtered array.
9185      * @see _.reject
9186      * @example
9187      *
9188      * var users = [
9189      *   { 'user': 'barney', 'age': 36, 'active': true },
9190      *   { 'user': 'fred',   'age': 40, 'active': false }
9191      * ];
9192      *
9193      * _.filter(users, function(o) { return !o.active; });
9194      * // => objects for ['fred']
9195      *
9196      * // The `_.matches` iteratee shorthand.
9197      * _.filter(users, { 'age': 36, 'active': true });
9198      * // => objects for ['barney']
9199      *
9200      * // The `_.matchesProperty` iteratee shorthand.
9201      * _.filter(users, ['active', false]);
9202      * // => objects for ['fred']
9203      *
9204      * // The `_.property` iteratee shorthand.
9205      * _.filter(users, 'active');
9206      * // => objects for ['barney']
9207      */
9208     function filter(collection, predicate) {
9209       var func = isArray(collection) ? arrayFilter : baseFilter;
9210       return func(collection, getIteratee(predicate, 3));
9211     }
9212
9213     /**
9214      * Iterates over elements of `collection`, returning the first element
9215      * `predicate` returns truthy for. The predicate is invoked with three
9216      * arguments: (value, index|key, collection).
9217      *
9218      * @static
9219      * @memberOf _
9220      * @since 0.1.0
9221      * @category Collection
9222      * @param {Array|Object} collection The collection to inspect.
9223      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9224      * @param {number} [fromIndex=0] The index to search from.
9225      * @returns {*} Returns the matched element, else `undefined`.
9226      * @example
9227      *
9228      * var users = [
9229      *   { 'user': 'barney',  'age': 36, 'active': true },
9230      *   { 'user': 'fred',    'age': 40, 'active': false },
9231      *   { 'user': 'pebbles', 'age': 1,  'active': true }
9232      * ];
9233      *
9234      * _.find(users, function(o) { return o.age < 40; });
9235      * // => object for 'barney'
9236      *
9237      * // The `_.matches` iteratee shorthand.
9238      * _.find(users, { 'age': 1, 'active': true });
9239      * // => object for 'pebbles'
9240      *
9241      * // The `_.matchesProperty` iteratee shorthand.
9242      * _.find(users, ['active', false]);
9243      * // => object for 'fred'
9244      *
9245      * // The `_.property` iteratee shorthand.
9246      * _.find(users, 'active');
9247      * // => object for 'barney'
9248      */
9249     var find = createFind(findIndex);
9250
9251     /**
9252      * This method is like `_.find` except that it iterates over elements of
9253      * `collection` from right to left.
9254      *
9255      * @static
9256      * @memberOf _
9257      * @since 2.0.0
9258      * @category Collection
9259      * @param {Array|Object} collection The collection to inspect.
9260      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9261      * @param {number} [fromIndex=collection.length-1] The index to search from.
9262      * @returns {*} Returns the matched element, else `undefined`.
9263      * @example
9264      *
9265      * _.findLast([1, 2, 3, 4], function(n) {
9266      *   return n % 2 == 1;
9267      * });
9268      * // => 3
9269      */
9270     var findLast = createFind(findLastIndex);
9271
9272     /**
9273      * Creates a flattened array of values by running each element in `collection`
9274      * thru `iteratee` and flattening the mapped results. The iteratee is invoked
9275      * with three arguments: (value, index|key, collection).
9276      *
9277      * @static
9278      * @memberOf _
9279      * @since 4.0.0
9280      * @category Collection
9281      * @param {Array|Object} collection The collection to iterate over.
9282      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9283      * @returns {Array} Returns the new flattened array.
9284      * @example
9285      *
9286      * function duplicate(n) {
9287      *   return [n, n];
9288      * }
9289      *
9290      * _.flatMap([1, 2], duplicate);
9291      * // => [1, 1, 2, 2]
9292      */
9293     function flatMap(collection, iteratee) {
9294       return baseFlatten(map(collection, iteratee), 1);
9295     }
9296
9297     /**
9298      * This method is like `_.flatMap` except that it recursively flattens the
9299      * mapped results.
9300      *
9301      * @static
9302      * @memberOf _
9303      * @since 4.7.0
9304      * @category Collection
9305      * @param {Array|Object} collection The collection to iterate over.
9306      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9307      * @returns {Array} Returns the new flattened array.
9308      * @example
9309      *
9310      * function duplicate(n) {
9311      *   return [[[n, n]]];
9312      * }
9313      *
9314      * _.flatMapDeep([1, 2], duplicate);
9315      * // => [1, 1, 2, 2]
9316      */
9317     function flatMapDeep(collection, iteratee) {
9318       return baseFlatten(map(collection, iteratee), INFINITY);
9319     }
9320
9321     /**
9322      * This method is like `_.flatMap` except that it recursively flattens the
9323      * mapped results up to `depth` times.
9324      *
9325      * @static
9326      * @memberOf _
9327      * @since 4.7.0
9328      * @category Collection
9329      * @param {Array|Object} collection The collection to iterate over.
9330      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9331      * @param {number} [depth=1] The maximum recursion depth.
9332      * @returns {Array} Returns the new flattened array.
9333      * @example
9334      *
9335      * function duplicate(n) {
9336      *   return [[[n, n]]];
9337      * }
9338      *
9339      * _.flatMapDepth([1, 2], duplicate, 2);
9340      * // => [[1, 1], [2, 2]]
9341      */
9342     function flatMapDepth(collection, iteratee, depth) {
9343       depth = depth === undefined ? 1 : toInteger(depth);
9344       return baseFlatten(map(collection, iteratee), depth);
9345     }
9346
9347     /**
9348      * Iterates over elements of `collection` and invokes `iteratee` for each element.
9349      * The iteratee is invoked with three arguments: (value, index|key, collection).
9350      * Iteratee functions may exit iteration early by explicitly returning `false`.
9351      *
9352      * **Note:** As with other "Collections" methods, objects with a "length"
9353      * property are iterated like arrays. To avoid this behavior use `_.forIn`
9354      * or `_.forOwn` for object iteration.
9355      *
9356      * @static
9357      * @memberOf _
9358      * @since 0.1.0
9359      * @alias each
9360      * @category Collection
9361      * @param {Array|Object} collection The collection to iterate over.
9362      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9363      * @returns {Array|Object} Returns `collection`.
9364      * @see _.forEachRight
9365      * @example
9366      *
9367      * _.forEach([1, 2], function(value) {
9368      *   console.log(value);
9369      * });
9370      * // => Logs `1` then `2`.
9371      *
9372      * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
9373      *   console.log(key);
9374      * });
9375      * // => Logs 'a' then 'b' (iteration order is not guaranteed).
9376      */
9377     function forEach(collection, iteratee) {
9378       var func = isArray(collection) ? arrayEach : baseEach;
9379       return func(collection, getIteratee(iteratee, 3));
9380     }
9381
9382     /**
9383      * This method is like `_.forEach` except that it iterates over elements of
9384      * `collection` from right to left.
9385      *
9386      * @static
9387      * @memberOf _
9388      * @since 2.0.0
9389      * @alias eachRight
9390      * @category Collection
9391      * @param {Array|Object} collection The collection to iterate over.
9392      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9393      * @returns {Array|Object} Returns `collection`.
9394      * @see _.forEach
9395      * @example
9396      *
9397      * _.forEachRight([1, 2], function(value) {
9398      *   console.log(value);
9399      * });
9400      * // => Logs `2` then `1`.
9401      */
9402     function forEachRight(collection, iteratee) {
9403       var func = isArray(collection) ? arrayEachRight : baseEachRight;
9404       return func(collection, getIteratee(iteratee, 3));
9405     }
9406
9407     /**
9408      * Creates an object composed of keys generated from the results of running
9409      * each element of `collection` thru `iteratee`. The order of grouped values
9410      * is determined by the order they occur in `collection`. The corresponding
9411      * value of each key is an array of elements responsible for generating the
9412      * key. The iteratee is invoked with one argument: (value).
9413      *
9414      * @static
9415      * @memberOf _
9416      * @since 0.1.0
9417      * @category Collection
9418      * @param {Array|Object} collection The collection to iterate over.
9419      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9420      * @returns {Object} Returns the composed aggregate object.
9421      * @example
9422      *
9423      * _.groupBy([6.1, 4.2, 6.3], Math.floor);
9424      * // => { '4': [4.2], '6': [6.1, 6.3] }
9425      *
9426      * // The `_.property` iteratee shorthand.
9427      * _.groupBy(['one', 'two', 'three'], 'length');
9428      * // => { '3': ['one', 'two'], '5': ['three'] }
9429      */
9430     var groupBy = createAggregator(function(result, value, key) {
9431       if (hasOwnProperty.call(result, key)) {
9432         result[key].push(value);
9433       } else {
9434         baseAssignValue(result, key, [value]);
9435       }
9436     });
9437
9438     /**
9439      * Checks if `value` is in `collection`. If `collection` is a string, it's
9440      * checked for a substring of `value`, otherwise
9441      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
9442      * is used for equality comparisons. If `fromIndex` is negative, it's used as
9443      * the offset from the end of `collection`.
9444      *
9445      * @static
9446      * @memberOf _
9447      * @since 0.1.0
9448      * @category Collection
9449      * @param {Array|Object|string} collection The collection to inspect.
9450      * @param {*} value The value to search for.
9451      * @param {number} [fromIndex=0] The index to search from.
9452      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
9453      * @returns {boolean} Returns `true` if `value` is found, else `false`.
9454      * @example
9455      *
9456      * _.includes([1, 2, 3], 1);
9457      * // => true
9458      *
9459      * _.includes([1, 2, 3], 1, 2);
9460      * // => false
9461      *
9462      * _.includes({ 'a': 1, 'b': 2 }, 1);
9463      * // => true
9464      *
9465      * _.includes('abcd', 'bc');
9466      * // => true
9467      */
9468     function includes(collection, value, fromIndex, guard) {
9469       collection = isArrayLike(collection) ? collection : values(collection);
9470       fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
9471
9472       var length = collection.length;
9473       if (fromIndex < 0) {
9474         fromIndex = nativeMax(length + fromIndex, 0);
9475       }
9476       return isString(collection)
9477         ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
9478         : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
9479     }
9480
9481     /**
9482      * Invokes the method at `path` of each element in `collection`, returning
9483      * an array of the results of each invoked method. Any additional arguments
9484      * are provided to each invoked method. If `path` is a function, it's invoked
9485      * for, and `this` bound to, each element in `collection`.
9486      *
9487      * @static
9488      * @memberOf _
9489      * @since 4.0.0
9490      * @category Collection
9491      * @param {Array|Object} collection The collection to iterate over.
9492      * @param {Array|Function|string} path The path of the method to invoke or
9493      *  the function invoked per iteration.
9494      * @param {...*} [args] The arguments to invoke each method with.
9495      * @returns {Array} Returns the array of results.
9496      * @example
9497      *
9498      * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
9499      * // => [[1, 5, 7], [1, 2, 3]]
9500      *
9501      * _.invokeMap([123, 456], String.prototype.split, '');
9502      * // => [['1', '2', '3'], ['4', '5', '6']]
9503      */
9504     var invokeMap = baseRest(function(collection, path, args) {
9505       var index = -1,
9506           isFunc = typeof path == 'function',
9507           result = isArrayLike(collection) ? Array(collection.length) : [];
9508
9509       baseEach(collection, function(value) {
9510         result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
9511       });
9512       return result;
9513     });
9514
9515     /**
9516      * Creates an object composed of keys generated from the results of running
9517      * each element of `collection` thru `iteratee`. The corresponding value of
9518      * each key is the last element responsible for generating the key. The
9519      * iteratee is invoked with one argument: (value).
9520      *
9521      * @static
9522      * @memberOf _
9523      * @since 4.0.0
9524      * @category Collection
9525      * @param {Array|Object} collection The collection to iterate over.
9526      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9527      * @returns {Object} Returns the composed aggregate object.
9528      * @example
9529      *
9530      * var array = [
9531      *   { 'dir': 'left', 'code': 97 },
9532      *   { 'dir': 'right', 'code': 100 }
9533      * ];
9534      *
9535      * _.keyBy(array, function(o) {
9536      *   return String.fromCharCode(o.code);
9537      * });
9538      * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
9539      *
9540      * _.keyBy(array, 'dir');
9541      * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
9542      */
9543     var keyBy = createAggregator(function(result, value, key) {
9544       baseAssignValue(result, key, value);
9545     });
9546
9547     /**
9548      * Creates an array of values by running each element in `collection` thru
9549      * `iteratee`. The iteratee is invoked with three arguments:
9550      * (value, index|key, collection).
9551      *
9552      * Many lodash methods are guarded to work as iteratees for methods like
9553      * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
9554      *
9555      * The guarded methods are:
9556      * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
9557      * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
9558      * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
9559      * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
9560      *
9561      * @static
9562      * @memberOf _
9563      * @since 0.1.0
9564      * @category Collection
9565      * @param {Array|Object} collection The collection to iterate over.
9566      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9567      * @returns {Array} Returns the new mapped array.
9568      * @example
9569      *
9570      * function square(n) {
9571      *   return n * n;
9572      * }
9573      *
9574      * _.map([4, 8], square);
9575      * // => [16, 64]
9576      *
9577      * _.map({ 'a': 4, 'b': 8 }, square);
9578      * // => [16, 64] (iteration order is not guaranteed)
9579      *
9580      * var users = [
9581      *   { 'user': 'barney' },
9582      *   { 'user': 'fred' }
9583      * ];
9584      *
9585      * // The `_.property` iteratee shorthand.
9586      * _.map(users, 'user');
9587      * // => ['barney', 'fred']
9588      */
9589     function map(collection, iteratee) {
9590       var func = isArray(collection) ? arrayMap : baseMap;
9591       return func(collection, getIteratee(iteratee, 3));
9592     }
9593
9594     /**
9595      * This method is like `_.sortBy` except that it allows specifying the sort
9596      * orders of the iteratees to sort by. If `orders` is unspecified, all values
9597      * are sorted in ascending order. Otherwise, specify an order of "desc" for
9598      * descending or "asc" for ascending sort order of corresponding values.
9599      *
9600      * @static
9601      * @memberOf _
9602      * @since 4.0.0
9603      * @category Collection
9604      * @param {Array|Object} collection The collection to iterate over.
9605      * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
9606      *  The iteratees to sort by.
9607      * @param {string[]} [orders] The sort orders of `iteratees`.
9608      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
9609      * @returns {Array} Returns the new sorted array.
9610      * @example
9611      *
9612      * var users = [
9613      *   { 'user': 'fred',   'age': 48 },
9614      *   { 'user': 'barney', 'age': 34 },
9615      *   { 'user': 'fred',   'age': 40 },
9616      *   { 'user': 'barney', 'age': 36 }
9617      * ];
9618      *
9619      * // Sort by `user` in ascending order and by `age` in descending order.
9620      * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
9621      * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
9622      */
9623     function orderBy(collection, iteratees, orders, guard) {
9624       if (collection == null) {
9625         return [];
9626       }
9627       if (!isArray(iteratees)) {
9628         iteratees = iteratees == null ? [] : [iteratees];
9629       }
9630       orders = guard ? undefined : orders;
9631       if (!isArray(orders)) {
9632         orders = orders == null ? [] : [orders];
9633       }
9634       return baseOrderBy(collection, iteratees, orders);
9635     }
9636
9637     /**
9638      * Creates an array of elements split into two groups, the first of which
9639      * contains elements `predicate` returns truthy for, the second of which
9640      * contains elements `predicate` returns falsey for. The predicate is
9641      * invoked with one argument: (value).
9642      *
9643      * @static
9644      * @memberOf _
9645      * @since 3.0.0
9646      * @category Collection
9647      * @param {Array|Object} collection The collection to iterate over.
9648      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9649      * @returns {Array} Returns the array of grouped elements.
9650      * @example
9651      *
9652      * var users = [
9653      *   { 'user': 'barney',  'age': 36, 'active': false },
9654      *   { 'user': 'fred',    'age': 40, 'active': true },
9655      *   { 'user': 'pebbles', 'age': 1,  'active': false }
9656      * ];
9657      *
9658      * _.partition(users, function(o) { return o.active; });
9659      * // => objects for [['fred'], ['barney', 'pebbles']]
9660      *
9661      * // The `_.matches` iteratee shorthand.
9662      * _.partition(users, { 'age': 1, 'active': false });
9663      * // => objects for [['pebbles'], ['barney', 'fred']]
9664      *
9665      * // The `_.matchesProperty` iteratee shorthand.
9666      * _.partition(users, ['active', false]);
9667      * // => objects for [['barney', 'pebbles'], ['fred']]
9668      *
9669      * // The `_.property` iteratee shorthand.
9670      * _.partition(users, 'active');
9671      * // => objects for [['fred'], ['barney', 'pebbles']]
9672      */
9673     var partition = createAggregator(function(result, value, key) {
9674       result[key ? 0 : 1].push(value);
9675     }, function() { return [[], []]; });
9676
9677     /**
9678      * Reduces `collection` to a value which is the accumulated result of running
9679      * each element in `collection` thru `iteratee`, where each successive
9680      * invocation is supplied the return value of the previous. If `accumulator`
9681      * is not given, the first element of `collection` is used as the initial
9682      * value. The iteratee is invoked with four arguments:
9683      * (accumulator, value, index|key, collection).
9684      *
9685      * Many lodash methods are guarded to work as iteratees for methods like
9686      * `_.reduce`, `_.reduceRight`, and `_.transform`.
9687      *
9688      * The guarded methods are:
9689      * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
9690      * and `sortBy`
9691      *
9692      * @static
9693      * @memberOf _
9694      * @since 0.1.0
9695      * @category Collection
9696      * @param {Array|Object} collection The collection to iterate over.
9697      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9698      * @param {*} [accumulator] The initial value.
9699      * @returns {*} Returns the accumulated value.
9700      * @see _.reduceRight
9701      * @example
9702      *
9703      * _.reduce([1, 2], function(sum, n) {
9704      *   return sum + n;
9705      * }, 0);
9706      * // => 3
9707      *
9708      * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
9709      *   (result[value] || (result[value] = [])).push(key);
9710      *   return result;
9711      * }, {});
9712      * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
9713      */
9714     function reduce(collection, iteratee, accumulator) {
9715       var func = isArray(collection) ? arrayReduce : baseReduce,
9716           initAccum = arguments.length < 3;
9717
9718       return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
9719     }
9720
9721     /**
9722      * This method is like `_.reduce` except that it iterates over elements of
9723      * `collection` from right to left.
9724      *
9725      * @static
9726      * @memberOf _
9727      * @since 0.1.0
9728      * @category Collection
9729      * @param {Array|Object} collection The collection to iterate over.
9730      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9731      * @param {*} [accumulator] The initial value.
9732      * @returns {*} Returns the accumulated value.
9733      * @see _.reduce
9734      * @example
9735      *
9736      * var array = [[0, 1], [2, 3], [4, 5]];
9737      *
9738      * _.reduceRight(array, function(flattened, other) {
9739      *   return flattened.concat(other);
9740      * }, []);
9741      * // => [4, 5, 2, 3, 0, 1]
9742      */
9743     function reduceRight(collection, iteratee, accumulator) {
9744       var func = isArray(collection) ? arrayReduceRight : baseReduce,
9745           initAccum = arguments.length < 3;
9746
9747       return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
9748     }
9749
9750     /**
9751      * The opposite of `_.filter`; this method returns the elements of `collection`
9752      * that `predicate` does **not** return truthy for.
9753      *
9754      * @static
9755      * @memberOf _
9756      * @since 0.1.0
9757      * @category Collection
9758      * @param {Array|Object} collection The collection to iterate over.
9759      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9760      * @returns {Array} Returns the new filtered array.
9761      * @see _.filter
9762      * @example
9763      *
9764      * var users = [
9765      *   { 'user': 'barney', 'age': 36, 'active': false },
9766      *   { 'user': 'fred',   'age': 40, 'active': true }
9767      * ];
9768      *
9769      * _.reject(users, function(o) { return !o.active; });
9770      * // => objects for ['fred']
9771      *
9772      * // The `_.matches` iteratee shorthand.
9773      * _.reject(users, { 'age': 40, 'active': true });
9774      * // => objects for ['barney']
9775      *
9776      * // The `_.matchesProperty` iteratee shorthand.
9777      * _.reject(users, ['active', false]);
9778      * // => objects for ['fred']
9779      *
9780      * // The `_.property` iteratee shorthand.
9781      * _.reject(users, 'active');
9782      * // => objects for ['barney']
9783      */
9784     function reject(collection, predicate) {
9785       var func = isArray(collection) ? arrayFilter : baseFilter;
9786       return func(collection, negate(getIteratee(predicate, 3)));
9787     }
9788
9789     /**
9790      * Gets a random element from `collection`.
9791      *
9792      * @static
9793      * @memberOf _
9794      * @since 2.0.0
9795      * @category Collection
9796      * @param {Array|Object} collection The collection to sample.
9797      * @returns {*} Returns the random element.
9798      * @example
9799      *
9800      * _.sample([1, 2, 3, 4]);
9801      * // => 2
9802      */
9803     function sample(collection) {
9804       var func = isArray(collection) ? arraySample : baseSample;
9805       return func(collection);
9806     }
9807
9808     /**
9809      * Gets `n` random elements at unique keys from `collection` up to the
9810      * size of `collection`.
9811      *
9812      * @static
9813      * @memberOf _
9814      * @since 4.0.0
9815      * @category Collection
9816      * @param {Array|Object} collection The collection to sample.
9817      * @param {number} [n=1] The number of elements to sample.
9818      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9819      * @returns {Array} Returns the random elements.
9820      * @example
9821      *
9822      * _.sampleSize([1, 2, 3], 2);
9823      * // => [3, 1]
9824      *
9825      * _.sampleSize([1, 2, 3], 4);
9826      * // => [2, 3, 1]
9827      */
9828     function sampleSize(collection, n, guard) {
9829       if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
9830         n = 1;
9831       } else {
9832         n = toInteger(n);
9833       }
9834       var func = isArray(collection) ? arraySampleSize : baseSampleSize;
9835       return func(collection, n);
9836     }
9837
9838     /**
9839      * Creates an array of shuffled values, using a version of the
9840      * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
9841      *
9842      * @static
9843      * @memberOf _
9844      * @since 0.1.0
9845      * @category Collection
9846      * @param {Array|Object} collection The collection to shuffle.
9847      * @returns {Array} Returns the new shuffled array.
9848      * @example
9849      *
9850      * _.shuffle([1, 2, 3, 4]);
9851      * // => [4, 1, 3, 2]
9852      */
9853     function shuffle(collection) {
9854       var func = isArray(collection) ? arrayShuffle : baseShuffle;
9855       return func(collection);
9856     }
9857
9858     /**
9859      * Gets the size of `collection` by returning its length for array-like
9860      * values or the number of own enumerable string keyed properties for objects.
9861      *
9862      * @static
9863      * @memberOf _
9864      * @since 0.1.0
9865      * @category Collection
9866      * @param {Array|Object|string} collection The collection to inspect.
9867      * @returns {number} Returns the collection size.
9868      * @example
9869      *
9870      * _.size([1, 2, 3]);
9871      * // => 3
9872      *
9873      * _.size({ 'a': 1, 'b': 2 });
9874      * // => 2
9875      *
9876      * _.size('pebbles');
9877      * // => 7
9878      */
9879     function size(collection) {
9880       if (collection == null) {
9881         return 0;
9882       }
9883       if (isArrayLike(collection)) {
9884         return isString(collection) ? stringSize(collection) : collection.length;
9885       }
9886       var tag = getTag(collection);
9887       if (tag == mapTag || tag == setTag) {
9888         return collection.size;
9889       }
9890       return baseKeys(collection).length;
9891     }
9892
9893     /**
9894      * Checks if `predicate` returns truthy for **any** element of `collection`.
9895      * Iteration is stopped once `predicate` returns truthy. The predicate is
9896      * invoked with three arguments: (value, index|key, collection).
9897      *
9898      * @static
9899      * @memberOf _
9900      * @since 0.1.0
9901      * @category Collection
9902      * @param {Array|Object} collection The collection to iterate over.
9903      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9904      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9905      * @returns {boolean} Returns `true` if any element passes the predicate check,
9906      *  else `false`.
9907      * @example
9908      *
9909      * _.some([null, 0, 'yes', false], Boolean);
9910      * // => true
9911      *
9912      * var users = [
9913      *   { 'user': 'barney', 'active': true },
9914      *   { 'user': 'fred',   'active': false }
9915      * ];
9916      *
9917      * // The `_.matches` iteratee shorthand.
9918      * _.some(users, { 'user': 'barney', 'active': false });
9919      * // => false
9920      *
9921      * // The `_.matchesProperty` iteratee shorthand.
9922      * _.some(users, ['active', false]);
9923      * // => true
9924      *
9925      * // The `_.property` iteratee shorthand.
9926      * _.some(users, 'active');
9927      * // => true
9928      */
9929     function some(collection, predicate, guard) {
9930       var func = isArray(collection) ? arraySome : baseSome;
9931       if (guard && isIterateeCall(collection, predicate, guard)) {
9932         predicate = undefined;
9933       }
9934       return func(collection, getIteratee(predicate, 3));
9935     }
9936
9937     /**
9938      * Creates an array of elements, sorted in ascending order by the results of
9939      * running each element in a collection thru each iteratee. This method
9940      * performs a stable sort, that is, it preserves the original sort order of
9941      * equal elements. The iteratees are invoked with one argument: (value).
9942      *
9943      * @static
9944      * @memberOf _
9945      * @since 0.1.0
9946      * @category Collection
9947      * @param {Array|Object} collection The collection to iterate over.
9948      * @param {...(Function|Function[])} [iteratees=[_.identity]]
9949      *  The iteratees to sort by.
9950      * @returns {Array} Returns the new sorted array.
9951      * @example
9952      *
9953      * var users = [
9954      *   { 'user': 'fred',   'age': 48 },
9955      *   { 'user': 'barney', 'age': 36 },
9956      *   { 'user': 'fred',   'age': 40 },
9957      *   { 'user': 'barney', 'age': 34 }
9958      * ];
9959      *
9960      * _.sortBy(users, [function(o) { return o.user; }]);
9961      * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
9962      *
9963      * _.sortBy(users, ['user', 'age']);
9964      * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
9965      */
9966     var sortBy = baseRest(function(collection, iteratees) {
9967       if (collection == null) {
9968         return [];
9969       }
9970       var length = iteratees.length;
9971       if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
9972         iteratees = [];
9973       } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
9974         iteratees = [iteratees[0]];
9975       }
9976       return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
9977     });
9978
9979     /*------------------------------------------------------------------------*/
9980
9981     /**
9982      * Gets the timestamp of the number of milliseconds that have elapsed since
9983      * the Unix epoch (1 January 1970 00:00:00 UTC).
9984      *
9985      * @static
9986      * @memberOf _
9987      * @since 2.4.0
9988      * @category Date
9989      * @returns {number} Returns the timestamp.
9990      * @example
9991      *
9992      * _.defer(function(stamp) {
9993      *   console.log(_.now() - stamp);
9994      * }, _.now());
9995      * // => Logs the number of milliseconds it took for the deferred invocation.
9996      */
9997     var now = ctxNow || function() {
9998       return root.Date.now();
9999     };
10000
10001     /*------------------------------------------------------------------------*/
10002
10003     /**
10004      * The opposite of `_.before`; this method creates a function that invokes
10005      * `func` once it's called `n` or more times.
10006      *
10007      * @static
10008      * @memberOf _
10009      * @since 0.1.0
10010      * @category Function
10011      * @param {number} n The number of calls before `func` is invoked.
10012      * @param {Function} func The function to restrict.
10013      * @returns {Function} Returns the new restricted function.
10014      * @example
10015      *
10016      * var saves = ['profile', 'settings'];
10017      *
10018      * var done = _.after(saves.length, function() {
10019      *   console.log('done saving!');
10020      * });
10021      *
10022      * _.forEach(saves, function(type) {
10023      *   asyncSave({ 'type': type, 'complete': done });
10024      * });
10025      * // => Logs 'done saving!' after the two async saves have completed.
10026      */
10027     function after(n, func) {
10028       if (typeof func != 'function') {
10029         throw new TypeError(FUNC_ERROR_TEXT);
10030       }
10031       n = toInteger(n);
10032       return function() {
10033         if (--n < 1) {
10034           return func.apply(this, arguments);
10035         }
10036       };
10037     }
10038
10039     /**
10040      * Creates a function that invokes `func`, with up to `n` arguments,
10041      * ignoring any additional arguments.
10042      *
10043      * @static
10044      * @memberOf _
10045      * @since 3.0.0
10046      * @category Function
10047      * @param {Function} func The function to cap arguments for.
10048      * @param {number} [n=func.length] The arity cap.
10049      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10050      * @returns {Function} Returns the new capped function.
10051      * @example
10052      *
10053      * _.map(['6', '8', '10'], _.ary(parseInt, 1));
10054      * // => [6, 8, 10]
10055      */
10056     function ary(func, n, guard) {
10057       n = guard ? undefined : n;
10058       n = (func && n == null) ? func.length : n;
10059       return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
10060     }
10061
10062     /**
10063      * Creates a function that invokes `func`, with the `this` binding and arguments
10064      * of the created function, while it's called less than `n` times. Subsequent
10065      * calls to the created function return the result of the last `func` invocation.
10066      *
10067      * @static
10068      * @memberOf _
10069      * @since 3.0.0
10070      * @category Function
10071      * @param {number} n The number of calls at which `func` is no longer invoked.
10072      * @param {Function} func The function to restrict.
10073      * @returns {Function} Returns the new restricted function.
10074      * @example
10075      *
10076      * jQuery(element).on('click', _.before(5, addContactToList));
10077      * // => Allows adding up to 4 contacts to the list.
10078      */
10079     function before(n, func) {
10080       var result;
10081       if (typeof func != 'function') {
10082         throw new TypeError(FUNC_ERROR_TEXT);
10083       }
10084       n = toInteger(n);
10085       return function() {
10086         if (--n > 0) {
10087           result = func.apply(this, arguments);
10088         }
10089         if (n <= 1) {
10090           func = undefined;
10091         }
10092         return result;
10093       };
10094     }
10095
10096     /**
10097      * Creates a function that invokes `func` with the `this` binding of `thisArg`
10098      * and `partials` prepended to the arguments it receives.
10099      *
10100      * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
10101      * may be used as a placeholder for partially applied arguments.
10102      *
10103      * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
10104      * property of bound functions.
10105      *
10106      * @static
10107      * @memberOf _
10108      * @since 0.1.0
10109      * @category Function
10110      * @param {Function} func The function to bind.
10111      * @param {*} thisArg The `this` binding of `func`.
10112      * @param {...*} [partials] The arguments to be partially applied.
10113      * @returns {Function} Returns the new bound function.
10114      * @example
10115      *
10116      * function greet(greeting, punctuation) {
10117      *   return greeting + ' ' + this.user + punctuation;
10118      * }
10119      *
10120      * var object = { 'user': 'fred' };
10121      *
10122      * var bound = _.bind(greet, object, 'hi');
10123      * bound('!');
10124      * // => 'hi fred!'
10125      *
10126      * // Bound with placeholders.
10127      * var bound = _.bind(greet, object, _, '!');
10128      * bound('hi');
10129      * // => 'hi fred!'
10130      */
10131     var bind = baseRest(function(func, thisArg, partials) {
10132       var bitmask = WRAP_BIND_FLAG;
10133       if (partials.length) {
10134         var holders = replaceHolders(partials, getHolder(bind));
10135         bitmask |= WRAP_PARTIAL_FLAG;
10136       }
10137       return createWrap(func, bitmask, thisArg, partials, holders);
10138     });
10139
10140     /**
10141      * Creates a function that invokes the method at `object[key]` with `partials`
10142      * prepended to the arguments it receives.
10143      *
10144      * This method differs from `_.bind` by allowing bound functions to reference
10145      * methods that may be redefined or don't yet exist. See
10146      * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
10147      * for more details.
10148      *
10149      * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
10150      * builds, may be used as a placeholder for partially applied arguments.
10151      *
10152      * @static
10153      * @memberOf _
10154      * @since 0.10.0
10155      * @category Function
10156      * @param {Object} object The object to invoke the method on.
10157      * @param {string} key The key of the method.
10158      * @param {...*} [partials] The arguments to be partially applied.
10159      * @returns {Function} Returns the new bound function.
10160      * @example
10161      *
10162      * var object = {
10163      *   'user': 'fred',
10164      *   'greet': function(greeting, punctuation) {
10165      *     return greeting + ' ' + this.user + punctuation;
10166      *   }
10167      * };
10168      *
10169      * var bound = _.bindKey(object, 'greet', 'hi');
10170      * bound('!');
10171      * // => 'hi fred!'
10172      *
10173      * object.greet = function(greeting, punctuation) {
10174      *   return greeting + 'ya ' + this.user + punctuation;
10175      * };
10176      *
10177      * bound('!');
10178      * // => 'hiya fred!'
10179      *
10180      * // Bound with placeholders.
10181      * var bound = _.bindKey(object, 'greet', _, '!');
10182      * bound('hi');
10183      * // => 'hiya fred!'
10184      */
10185     var bindKey = baseRest(function(object, key, partials) {
10186       var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
10187       if (partials.length) {
10188         var holders = replaceHolders(partials, getHolder(bindKey));
10189         bitmask |= WRAP_PARTIAL_FLAG;
10190       }
10191       return createWrap(key, bitmask, object, partials, holders);
10192     });
10193
10194     /**
10195      * Creates a function that accepts arguments of `func` and either invokes
10196      * `func` returning its result, if at least `arity` number of arguments have
10197      * been provided, or returns a function that accepts the remaining `func`
10198      * arguments, and so on. The arity of `func` may be specified if `func.length`
10199      * is not sufficient.
10200      *
10201      * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
10202      * may be used as a placeholder for provided arguments.
10203      *
10204      * **Note:** This method doesn't set the "length" property of curried functions.
10205      *
10206      * @static
10207      * @memberOf _
10208      * @since 2.0.0
10209      * @category Function
10210      * @param {Function} func The function to curry.
10211      * @param {number} [arity=func.length] The arity of `func`.
10212      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10213      * @returns {Function} Returns the new curried function.
10214      * @example
10215      *
10216      * var abc = function(a, b, c) {
10217      *   return [a, b, c];
10218      * };
10219      *
10220      * var curried = _.curry(abc);
10221      *
10222      * curried(1)(2)(3);
10223      * // => [1, 2, 3]
10224      *
10225      * curried(1, 2)(3);
10226      * // => [1, 2, 3]
10227      *
10228      * curried(1, 2, 3);
10229      * // => [1, 2, 3]
10230      *
10231      * // Curried with placeholders.
10232      * curried(1)(_, 3)(2);
10233      * // => [1, 2, 3]
10234      */
10235     function curry(func, arity, guard) {
10236       arity = guard ? undefined : arity;
10237       var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
10238       result.placeholder = curry.placeholder;
10239       return result;
10240     }
10241
10242     /**
10243      * This method is like `_.curry` except that arguments are applied to `func`
10244      * in the manner of `_.partialRight` instead of `_.partial`.
10245      *
10246      * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
10247      * builds, may be used as a placeholder for provided arguments.
10248      *
10249      * **Note:** This method doesn't set the "length" property of curried functions.
10250      *
10251      * @static
10252      * @memberOf _
10253      * @since 3.0.0
10254      * @category Function
10255      * @param {Function} func The function to curry.
10256      * @param {number} [arity=func.length] The arity of `func`.
10257      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10258      * @returns {Function} Returns the new curried function.
10259      * @example
10260      *
10261      * var abc = function(a, b, c) {
10262      *   return [a, b, c];
10263      * };
10264      *
10265      * var curried = _.curryRight(abc);
10266      *
10267      * curried(3)(2)(1);
10268      * // => [1, 2, 3]
10269      *
10270      * curried(2, 3)(1);
10271      * // => [1, 2, 3]
10272      *
10273      * curried(1, 2, 3);
10274      * // => [1, 2, 3]
10275      *
10276      * // Curried with placeholders.
10277      * curried(3)(1, _)(2);
10278      * // => [1, 2, 3]
10279      */
10280     function curryRight(func, arity, guard) {
10281       arity = guard ? undefined : arity;
10282       var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
10283       result.placeholder = curryRight.placeholder;
10284       return result;
10285     }
10286
10287     /**
10288      * Creates a debounced function that delays invoking `func` until after `wait`
10289      * milliseconds have elapsed since the last time the debounced function was
10290      * invoked. The debounced function comes with a `cancel` method to cancel
10291      * delayed `func` invocations and a `flush` method to immediately invoke them.
10292      * Provide `options` to indicate whether `func` should be invoked on the
10293      * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
10294      * with the last arguments provided to the debounced function. Subsequent
10295      * calls to the debounced function return the result of the last `func`
10296      * invocation.
10297      *
10298      * **Note:** If `leading` and `trailing` options are `true`, `func` is
10299      * invoked on the trailing edge of the timeout only if the debounced function
10300      * is invoked more than once during the `wait` timeout.
10301      *
10302      * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
10303      * until to the next tick, similar to `setTimeout` with a timeout of `0`.
10304      *
10305      * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
10306      * for details over the differences between `_.debounce` and `_.throttle`.
10307      *
10308      * @static
10309      * @memberOf _
10310      * @since 0.1.0
10311      * @category Function
10312      * @param {Function} func The function to debounce.
10313      * @param {number} [wait=0] The number of milliseconds to delay.
10314      * @param {Object} [options={}] The options object.
10315      * @param {boolean} [options.leading=false]
10316      *  Specify invoking on the leading edge of the timeout.
10317      * @param {number} [options.maxWait]
10318      *  The maximum time `func` is allowed to be delayed before it's invoked.
10319      * @param {boolean} [options.trailing=true]
10320      *  Specify invoking on the trailing edge of the timeout.
10321      * @returns {Function} Returns the new debounced function.
10322      * @example
10323      *
10324      * // Avoid costly calculations while the window size is in flux.
10325      * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
10326      *
10327      * // Invoke `sendMail` when clicked, debouncing subsequent calls.
10328      * jQuery(element).on('click', _.debounce(sendMail, 300, {
10329      *   'leading': true,
10330      *   'trailing': false
10331      * }));
10332      *
10333      * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
10334      * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
10335      * var source = new EventSource('/stream');
10336      * jQuery(source).on('message', debounced);
10337      *
10338      * // Cancel the trailing debounced invocation.
10339      * jQuery(window).on('popstate', debounced.cancel);
10340      */
10341     function debounce(func, wait, options) {
10342       var lastArgs,
10343           lastThis,
10344           maxWait,
10345           result,
10346           timerId,
10347           lastCallTime,
10348           lastInvokeTime = 0,
10349           leading = false,
10350           maxing = false,
10351           trailing = true;
10352
10353       if (typeof func != 'function') {
10354         throw new TypeError(FUNC_ERROR_TEXT);
10355       }
10356       wait = toNumber(wait) || 0;
10357       if (isObject(options)) {
10358         leading = !!options.leading;
10359         maxing = 'maxWait' in options;
10360         maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
10361         trailing = 'trailing' in options ? !!options.trailing : trailing;
10362       }
10363
10364       function invokeFunc(time) {
10365         var args = lastArgs,
10366             thisArg = lastThis;
10367
10368         lastArgs = lastThis = undefined;
10369         lastInvokeTime = time;
10370         result = func.apply(thisArg, args);
10371         return result;
10372       }
10373
10374       function leadingEdge(time) {
10375         // Reset any `maxWait` timer.
10376         lastInvokeTime = time;
10377         // Start the timer for the trailing edge.
10378         timerId = setTimeout(timerExpired, wait);
10379         // Invoke the leading edge.
10380         return leading ? invokeFunc(time) : result;
10381       }
10382
10383       function remainingWait(time) {
10384         var timeSinceLastCall = time - lastCallTime,
10385             timeSinceLastInvoke = time - lastInvokeTime,
10386             result = wait - timeSinceLastCall;
10387
10388         return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
10389       }
10390
10391       function shouldInvoke(time) {
10392         var timeSinceLastCall = time - lastCallTime,
10393             timeSinceLastInvoke = time - lastInvokeTime;
10394
10395         // Either this is the first call, activity has stopped and we're at the
10396         // trailing edge, the system time has gone backwards and we're treating
10397         // it as the trailing edge, or we've hit the `maxWait` limit.
10398         return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
10399           (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
10400       }
10401
10402       function timerExpired() {
10403         var time = now();
10404         if (shouldInvoke(time)) {
10405           return trailingEdge(time);
10406         }
10407         // Restart the timer.
10408         timerId = setTimeout(timerExpired, remainingWait(time));
10409       }
10410
10411       function trailingEdge(time) {
10412         timerId = undefined;
10413
10414         // Only invoke if we have `lastArgs` which means `func` has been
10415         // debounced at least once.
10416         if (trailing && lastArgs) {
10417           return invokeFunc(time);
10418         }
10419         lastArgs = lastThis = undefined;
10420         return result;
10421       }
10422
10423       function cancel() {
10424         if (timerId !== undefined) {
10425           clearTimeout(timerId);
10426         }
10427         lastInvokeTime = 0;
10428         lastArgs = lastCallTime = lastThis = timerId = undefined;
10429       }
10430
10431       function flush() {
10432         return timerId === undefined ? result : trailingEdge(now());
10433       }
10434
10435       function debounced() {
10436         var time = now(),
10437             isInvoking = shouldInvoke(time);
10438
10439         lastArgs = arguments;
10440         lastThis = this;
10441         lastCallTime = time;
10442
10443         if (isInvoking) {
10444           if (timerId === undefined) {
10445             return leadingEdge(lastCallTime);
10446           }
10447           if (maxing) {
10448             // Handle invocations in a tight loop.
10449             timerId = setTimeout(timerExpired, wait);
10450             return invokeFunc(lastCallTime);
10451           }
10452         }
10453         if (timerId === undefined) {
10454           timerId = setTimeout(timerExpired, wait);
10455         }
10456         return result;
10457       }
10458       debounced.cancel = cancel;
10459       debounced.flush = flush;
10460       return debounced;
10461     }
10462
10463     /**
10464      * Defers invoking the `func` until the current call stack has cleared. Any
10465      * additional arguments are provided to `func` when it's invoked.
10466      *
10467      * @static
10468      * @memberOf _
10469      * @since 0.1.0
10470      * @category Function
10471      * @param {Function} func The function to defer.
10472      * @param {...*} [args] The arguments to invoke `func` with.
10473      * @returns {number} Returns the timer id.
10474      * @example
10475      *
10476      * _.defer(function(text) {
10477      *   console.log(text);
10478      * }, 'deferred');
10479      * // => Logs 'deferred' after one millisecond.
10480      */
10481     var defer = baseRest(function(func, args) {
10482       return baseDelay(func, 1, args);
10483     });
10484
10485     /**
10486      * Invokes `func` after `wait` milliseconds. Any additional arguments are
10487      * provided to `func` when it's invoked.
10488      *
10489      * @static
10490      * @memberOf _
10491      * @since 0.1.0
10492      * @category Function
10493      * @param {Function} func The function to delay.
10494      * @param {number} wait The number of milliseconds to delay invocation.
10495      * @param {...*} [args] The arguments to invoke `func` with.
10496      * @returns {number} Returns the timer id.
10497      * @example
10498      *
10499      * _.delay(function(text) {
10500      *   console.log(text);
10501      * }, 1000, 'later');
10502      * // => Logs 'later' after one second.
10503      */
10504     var delay = baseRest(function(func, wait, args) {
10505       return baseDelay(func, toNumber(wait) || 0, args);
10506     });
10507
10508     /**
10509      * Creates a function that invokes `func` with arguments reversed.
10510      *
10511      * @static
10512      * @memberOf _
10513      * @since 4.0.0
10514      * @category Function
10515      * @param {Function} func The function to flip arguments for.
10516      * @returns {Function} Returns the new flipped function.
10517      * @example
10518      *
10519      * var flipped = _.flip(function() {
10520      *   return _.toArray(arguments);
10521      * });
10522      *
10523      * flipped('a', 'b', 'c', 'd');
10524      * // => ['d', 'c', 'b', 'a']
10525      */
10526     function flip(func) {
10527       return createWrap(func, WRAP_FLIP_FLAG);
10528     }
10529
10530     /**
10531      * Creates a function that memoizes the result of `func`. If `resolver` is
10532      * provided, it determines the cache key for storing the result based on the
10533      * arguments provided to the memoized function. By default, the first argument
10534      * provided to the memoized function is used as the map cache key. The `func`
10535      * is invoked with the `this` binding of the memoized function.
10536      *
10537      * **Note:** The cache is exposed as the `cache` property on the memoized
10538      * function. Its creation may be customized by replacing the `_.memoize.Cache`
10539      * constructor with one whose instances implement the
10540      * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
10541      * method interface of `clear`, `delete`, `get`, `has`, and `set`.
10542      *
10543      * @static
10544      * @memberOf _
10545      * @since 0.1.0
10546      * @category Function
10547      * @param {Function} func The function to have its output memoized.
10548      * @param {Function} [resolver] The function to resolve the cache key.
10549      * @returns {Function} Returns the new memoized function.
10550      * @example
10551      *
10552      * var object = { 'a': 1, 'b': 2 };
10553      * var other = { 'c': 3, 'd': 4 };
10554      *
10555      * var values = _.memoize(_.values);
10556      * values(object);
10557      * // => [1, 2]
10558      *
10559      * values(other);
10560      * // => [3, 4]
10561      *
10562      * object.a = 2;
10563      * values(object);
10564      * // => [1, 2]
10565      *
10566      * // Modify the result cache.
10567      * values.cache.set(object, ['a', 'b']);
10568      * values(object);
10569      * // => ['a', 'b']
10570      *
10571      * // Replace `_.memoize.Cache`.
10572      * _.memoize.Cache = WeakMap;
10573      */
10574     function memoize(func, resolver) {
10575       if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
10576         throw new TypeError(FUNC_ERROR_TEXT);
10577       }
10578       var memoized = function() {
10579         var args = arguments,
10580             key = resolver ? resolver.apply(this, args) : args[0],
10581             cache = memoized.cache;
10582
10583         if (cache.has(key)) {
10584           return cache.get(key);
10585         }
10586         var result = func.apply(this, args);
10587         memoized.cache = cache.set(key, result) || cache;
10588         return result;
10589       };
10590       memoized.cache = new (memoize.Cache || MapCache);
10591       return memoized;
10592     }
10593
10594     // Expose `MapCache`.
10595     memoize.Cache = MapCache;
10596
10597     /**
10598      * Creates a function that negates the result of the predicate `func`. The
10599      * `func` predicate is invoked with the `this` binding and arguments of the
10600      * created function.
10601      *
10602      * @static
10603      * @memberOf _
10604      * @since 3.0.0
10605      * @category Function
10606      * @param {Function} predicate The predicate to negate.
10607      * @returns {Function} Returns the new negated function.
10608      * @example
10609      *
10610      * function isEven(n) {
10611      *   return n % 2 == 0;
10612      * }
10613      *
10614      * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
10615      * // => [1, 3, 5]
10616      */
10617     function negate(predicate) {
10618       if (typeof predicate != 'function') {
10619         throw new TypeError(FUNC_ERROR_TEXT);
10620       }
10621       return function() {
10622         var args = arguments;
10623         switch (args.length) {
10624           case 0: return !predicate.call(this);
10625           case 1: return !predicate.call(this, args[0]);
10626           case 2: return !predicate.call(this, args[0], args[1]);
10627           case 3: return !predicate.call(this, args[0], args[1], args[2]);
10628         }
10629         return !predicate.apply(this, args);
10630       };
10631     }
10632
10633     /**
10634      * Creates a function that is restricted to invoking `func` once. Repeat calls
10635      * to the function return the value of the first invocation. The `func` is
10636      * invoked with the `this` binding and arguments of the created function.
10637      *
10638      * @static
10639      * @memberOf _
10640      * @since 0.1.0
10641      * @category Function
10642      * @param {Function} func The function to restrict.
10643      * @returns {Function} Returns the new restricted function.
10644      * @example
10645      *
10646      * var initialize = _.once(createApplication);
10647      * initialize();
10648      * initialize();
10649      * // => `createApplication` is invoked once
10650      */
10651     function once(func) {
10652       return before(2, func);
10653     }
10654
10655     /**
10656      * Creates a function that invokes `func` with its arguments transformed.
10657      *
10658      * @static
10659      * @since 4.0.0
10660      * @memberOf _
10661      * @category Function
10662      * @param {Function} func The function to wrap.
10663      * @param {...(Function|Function[])} [transforms=[_.identity]]
10664      *  The argument transforms.
10665      * @returns {Function} Returns the new function.
10666      * @example
10667      *
10668      * function doubled(n) {
10669      *   return n * 2;
10670      * }
10671      *
10672      * function square(n) {
10673      *   return n * n;
10674      * }
10675      *
10676      * var func = _.overArgs(function(x, y) {
10677      *   return [x, y];
10678      * }, [square, doubled]);
10679      *
10680      * func(9, 3);
10681      * // => [81, 6]
10682      *
10683      * func(10, 5);
10684      * // => [100, 10]
10685      */
10686     var overArgs = castRest(function(func, transforms) {
10687       transforms = (transforms.length == 1 && isArray(transforms[0]))
10688         ? arrayMap(transforms[0], baseUnary(getIteratee()))
10689         : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));
10690
10691       var funcsLength = transforms.length;
10692       return baseRest(function(args) {
10693         var index = -1,
10694             length = nativeMin(args.length, funcsLength);
10695
10696         while (++index < length) {
10697           args[index] = transforms[index].call(this, args[index]);
10698         }
10699         return apply(func, this, args);
10700       });
10701     });
10702
10703     /**
10704      * Creates a function that invokes `func` with `partials` prepended to the
10705      * arguments it receives. This method is like `_.bind` except it does **not**
10706      * alter the `this` binding.
10707      *
10708      * The `_.partial.placeholder` value, which defaults to `_` in monolithic
10709      * builds, may be used as a placeholder for partially applied arguments.
10710      *
10711      * **Note:** This method doesn't set the "length" property of partially
10712      * applied functions.
10713      *
10714      * @static
10715      * @memberOf _
10716      * @since 0.2.0
10717      * @category Function
10718      * @param {Function} func The function to partially apply arguments to.
10719      * @param {...*} [partials] The arguments to be partially applied.
10720      * @returns {Function} Returns the new partially applied function.
10721      * @example
10722      *
10723      * function greet(greeting, name) {
10724      *   return greeting + ' ' + name;
10725      * }
10726      *
10727      * var sayHelloTo = _.partial(greet, 'hello');
10728      * sayHelloTo('fred');
10729      * // => 'hello fred'
10730      *
10731      * // Partially applied with placeholders.
10732      * var greetFred = _.partial(greet, _, 'fred');
10733      * greetFred('hi');
10734      * // => 'hi fred'
10735      */
10736     var partial = baseRest(function(func, partials) {
10737       var holders = replaceHolders(partials, getHolder(partial));
10738       return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
10739     });
10740
10741     /**
10742      * This method is like `_.partial` except that partially applied arguments
10743      * are appended to the arguments it receives.
10744      *
10745      * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
10746      * builds, may be used as a placeholder for partially applied arguments.
10747      *
10748      * **Note:** This method doesn't set the "length" property of partially
10749      * applied functions.
10750      *
10751      * @static
10752      * @memberOf _
10753      * @since 1.0.0
10754      * @category Function
10755      * @param {Function} func The function to partially apply arguments to.
10756      * @param {...*} [partials] The arguments to be partially applied.
10757      * @returns {Function} Returns the new partially applied function.
10758      * @example
10759      *
10760      * function greet(greeting, name) {
10761      *   return greeting + ' ' + name;
10762      * }
10763      *
10764      * var greetFred = _.partialRight(greet, 'fred');
10765      * greetFred('hi');
10766      * // => 'hi fred'
10767      *
10768      * // Partially applied with placeholders.
10769      * var sayHelloTo = _.partialRight(greet, 'hello', _);
10770      * sayHelloTo('fred');
10771      * // => 'hello fred'
10772      */
10773     var partialRight = baseRest(function(func, partials) {
10774       var holders = replaceHolders(partials, getHolder(partialRight));
10775       return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
10776     });
10777
10778     /**
10779      * Creates a function that invokes `func` with arguments arranged according
10780      * to the specified `indexes` where the argument value at the first index is
10781      * provided as the first argument, the argument value at the second index is
10782      * provided as the second argument, and so on.
10783      *
10784      * @static
10785      * @memberOf _
10786      * @since 3.0.0
10787      * @category Function
10788      * @param {Function} func The function to rearrange arguments for.
10789      * @param {...(number|number[])} indexes The arranged argument indexes.
10790      * @returns {Function} Returns the new function.
10791      * @example
10792      *
10793      * var rearged = _.rearg(function(a, b, c) {
10794      *   return [a, b, c];
10795      * }, [2, 0, 1]);
10796      *
10797      * rearged('b', 'c', 'a')
10798      * // => ['a', 'b', 'c']
10799      */
10800     var rearg = flatRest(function(func, indexes) {
10801       return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
10802     });
10803
10804     /**
10805      * Creates a function that invokes `func` with the `this` binding of the
10806      * created function and arguments from `start` and beyond provided as
10807      * an array.
10808      *
10809      * **Note:** This method is based on the
10810      * [rest parameter](https://mdn.io/rest_parameters).
10811      *
10812      * @static
10813      * @memberOf _
10814      * @since 4.0.0
10815      * @category Function
10816      * @param {Function} func The function to apply a rest parameter to.
10817      * @param {number} [start=func.length-1] The start position of the rest parameter.
10818      * @returns {Function} Returns the new function.
10819      * @example
10820      *
10821      * var say = _.rest(function(what, names) {
10822      *   return what + ' ' + _.initial(names).join(', ') +
10823      *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
10824      * });
10825      *
10826      * say('hello', 'fred', 'barney', 'pebbles');
10827      * // => 'hello fred, barney, & pebbles'
10828      */
10829     function rest(func, start) {
10830       if (typeof func != 'function') {
10831         throw new TypeError(FUNC_ERROR_TEXT);
10832       }
10833       start = start === undefined ? start : toInteger(start);
10834       return baseRest(func, start);
10835     }
10836
10837     /**
10838      * Creates a function that invokes `func` with the `this` binding of the
10839      * create function and an array of arguments much like
10840      * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
10841      *
10842      * **Note:** This method is based on the
10843      * [spread operator](https://mdn.io/spread_operator).
10844      *
10845      * @static
10846      * @memberOf _
10847      * @since 3.2.0
10848      * @category Function
10849      * @param {Function} func The function to spread arguments over.
10850      * @param {number} [start=0] The start position of the spread.
10851      * @returns {Function} Returns the new function.
10852      * @example
10853      *
10854      * var say = _.spread(function(who, what) {
10855      *   return who + ' says ' + what;
10856      * });
10857      *
10858      * say(['fred', 'hello']);
10859      * // => 'fred says hello'
10860      *
10861      * var numbers = Promise.all([
10862      *   Promise.resolve(40),
10863      *   Promise.resolve(36)
10864      * ]);
10865      *
10866      * numbers.then(_.spread(function(x, y) {
10867      *   return x + y;
10868      * }));
10869      * // => a Promise of 76
10870      */
10871     function spread(func, start) {
10872       if (typeof func != 'function') {
10873         throw new TypeError(FUNC_ERROR_TEXT);
10874       }
10875       start = start == null ? 0 : nativeMax(toInteger(start), 0);
10876       return baseRest(function(args) {
10877         var array = args[start],
10878             otherArgs = castSlice(args, 0, start);
10879
10880         if (array) {
10881           arrayPush(otherArgs, array);
10882         }
10883         return apply(func, this, otherArgs);
10884       });
10885     }
10886
10887     /**
10888      * Creates a throttled function that only invokes `func` at most once per
10889      * every `wait` milliseconds. The throttled function comes with a `cancel`
10890      * method to cancel delayed `func` invocations and a `flush` method to
10891      * immediately invoke them. Provide `options` to indicate whether `func`
10892      * should be invoked on the leading and/or trailing edge of the `wait`
10893      * timeout. The `func` is invoked with the last arguments provided to the
10894      * throttled function. Subsequent calls to the throttled function return the
10895      * result of the last `func` invocation.
10896      *
10897      * **Note:** If `leading` and `trailing` options are `true`, `func` is
10898      * invoked on the trailing edge of the timeout only if the throttled function
10899      * is invoked more than once during the `wait` timeout.
10900      *
10901      * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
10902      * until to the next tick, similar to `setTimeout` with a timeout of `0`.
10903      *
10904      * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
10905      * for details over the differences between `_.throttle` and `_.debounce`.
10906      *
10907      * @static
10908      * @memberOf _
10909      * @since 0.1.0
10910      * @category Function
10911      * @param {Function} func The function to throttle.
10912      * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
10913      * @param {Object} [options={}] The options object.
10914      * @param {boolean} [options.leading=true]
10915      *  Specify invoking on the leading edge of the timeout.
10916      * @param {boolean} [options.trailing=true]
10917      *  Specify invoking on the trailing edge of the timeout.
10918      * @returns {Function} Returns the new throttled function.
10919      * @example
10920      *
10921      * // Avoid excessively updating the position while scrolling.
10922      * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
10923      *
10924      * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
10925      * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
10926      * jQuery(element).on('click', throttled);
10927      *
10928      * // Cancel the trailing throttled invocation.
10929      * jQuery(window).on('popstate', throttled.cancel);
10930      */
10931     function throttle(func, wait, options) {
10932       var leading = true,
10933           trailing = true;
10934
10935       if (typeof func != 'function') {
10936         throw new TypeError(FUNC_ERROR_TEXT);
10937       }
10938       if (isObject(options)) {
10939         leading = 'leading' in options ? !!options.leading : leading;
10940         trailing = 'trailing' in options ? !!options.trailing : trailing;
10941       }
10942       return debounce(func, wait, {
10943         'leading': leading,
10944         'maxWait': wait,
10945         'trailing': trailing
10946       });
10947     }
10948
10949     /**
10950      * Creates a function that accepts up to one argument, ignoring any
10951      * additional arguments.
10952      *
10953      * @static
10954      * @memberOf _
10955      * @since 4.0.0
10956      * @category Function
10957      * @param {Function} func The function to cap arguments for.
10958      * @returns {Function} Returns the new capped function.
10959      * @example
10960      *
10961      * _.map(['6', '8', '10'], _.unary(parseInt));
10962      * // => [6, 8, 10]
10963      */
10964     function unary(func) {
10965       return ary(func, 1);
10966     }
10967
10968     /**
10969      * Creates a function that provides `value` to `wrapper` as its first
10970      * argument. Any additional arguments provided to the function are appended
10971      * to those provided to the `wrapper`. The wrapper is invoked with the `this`
10972      * binding of the created function.
10973      *
10974      * @static
10975      * @memberOf _
10976      * @since 0.1.0
10977      * @category Function
10978      * @param {*} value The value to wrap.
10979      * @param {Function} [wrapper=identity] The wrapper function.
10980      * @returns {Function} Returns the new function.
10981      * @example
10982      *
10983      * var p = _.wrap(_.escape, function(func, text) {
10984      *   return '<p>' + func(text) + '</p>';
10985      * });
10986      *
10987      * p('fred, barney, & pebbles');
10988      * // => '<p>fred, barney, &amp; pebbles</p>'
10989      */
10990     function wrap(value, wrapper) {
10991       return partial(castFunction(wrapper), value);
10992     }
10993
10994     /*------------------------------------------------------------------------*/
10995
10996     /**
10997      * Casts `value` as an array if it's not one.
10998      *
10999      * @static
11000      * @memberOf _
11001      * @since 4.4.0
11002      * @category Lang
11003      * @param {*} value The value to inspect.
11004      * @returns {Array} Returns the cast array.
11005      * @example
11006      *
11007      * _.castArray(1);
11008      * // => [1]
11009      *
11010      * _.castArray({ 'a': 1 });
11011      * // => [{ 'a': 1 }]
11012      *
11013      * _.castArray('abc');
11014      * // => ['abc']
11015      *
11016      * _.castArray(null);
11017      * // => [null]
11018      *
11019      * _.castArray(undefined);
11020      * // => [undefined]
11021      *
11022      * _.castArray();
11023      * // => []
11024      *
11025      * var array = [1, 2, 3];
11026      * console.log(_.castArray(array) === array);
11027      * // => true
11028      */
11029     function castArray() {
11030       if (!arguments.length) {
11031         return [];
11032       }
11033       var value = arguments[0];
11034       return isArray(value) ? value : [value];
11035     }
11036
11037     /**
11038      * Creates a shallow clone of `value`.
11039      *
11040      * **Note:** This method is loosely based on the
11041      * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
11042      * and supports cloning arrays, array buffers, booleans, date objects, maps,
11043      * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
11044      * arrays. The own enumerable properties of `arguments` objects are cloned
11045      * as plain objects. An empty object is returned for uncloneable values such
11046      * as error objects, functions, DOM nodes, and WeakMaps.
11047      *
11048      * @static
11049      * @memberOf _
11050      * @since 0.1.0
11051      * @category Lang
11052      * @param {*} value The value to clone.
11053      * @returns {*} Returns the cloned value.
11054      * @see _.cloneDeep
11055      * @example
11056      *
11057      * var objects = [{ 'a': 1 }, { 'b': 2 }];
11058      *
11059      * var shallow = _.clone(objects);
11060      * console.log(shallow[0] === objects[0]);
11061      * // => true
11062      */
11063     function clone(value) {
11064       return baseClone(value, CLONE_SYMBOLS_FLAG);
11065     }
11066
11067     /**
11068      * This method is like `_.clone` except that it accepts `customizer` which
11069      * is invoked to produce the cloned value. If `customizer` returns `undefined`,
11070      * cloning is handled by the method instead. The `customizer` is invoked with
11071      * up to four arguments; (value [, index|key, object, stack]).
11072      *
11073      * @static
11074      * @memberOf _
11075      * @since 4.0.0
11076      * @category Lang
11077      * @param {*} value The value to clone.
11078      * @param {Function} [customizer] The function to customize cloning.
11079      * @returns {*} Returns the cloned value.
11080      * @see _.cloneDeepWith
11081      * @example
11082      *
11083      * function customizer(value) {
11084      *   if (_.isElement(value)) {
11085      *     return value.cloneNode(false);
11086      *   }
11087      * }
11088      *
11089      * var el = _.cloneWith(document.body, customizer);
11090      *
11091      * console.log(el === document.body);
11092      * // => false
11093      * console.log(el.nodeName);
11094      * // => 'BODY'
11095      * console.log(el.childNodes.length);
11096      * // => 0
11097      */
11098     function cloneWith(value, customizer) {
11099       customizer = typeof customizer == 'function' ? customizer : undefined;
11100       return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);
11101     }
11102
11103     /**
11104      * This method is like `_.clone` except that it recursively clones `value`.
11105      *
11106      * @static
11107      * @memberOf _
11108      * @since 1.0.0
11109      * @category Lang
11110      * @param {*} value The value to recursively clone.
11111      * @returns {*} Returns the deep cloned value.
11112      * @see _.clone
11113      * @example
11114      *
11115      * var objects = [{ 'a': 1 }, { 'b': 2 }];
11116      *
11117      * var deep = _.cloneDeep(objects);
11118      * console.log(deep[0] === objects[0]);
11119      * // => false
11120      */
11121     function cloneDeep(value) {
11122       return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
11123     }
11124
11125     /**
11126      * This method is like `_.cloneWith` except that it recursively clones `value`.
11127      *
11128      * @static
11129      * @memberOf _
11130      * @since 4.0.0
11131      * @category Lang
11132      * @param {*} value The value to recursively clone.
11133      * @param {Function} [customizer] The function to customize cloning.
11134      * @returns {*} Returns the deep cloned value.
11135      * @see _.cloneWith
11136      * @example
11137      *
11138      * function customizer(value) {
11139      *   if (_.isElement(value)) {
11140      *     return value.cloneNode(true);
11141      *   }
11142      * }
11143      *
11144      * var el = _.cloneDeepWith(document.body, customizer);
11145      *
11146      * console.log(el === document.body);
11147      * // => false
11148      * console.log(el.nodeName);
11149      * // => 'BODY'
11150      * console.log(el.childNodes.length);
11151      * // => 20
11152      */
11153     function cloneDeepWith(value, customizer) {
11154       customizer = typeof customizer == 'function' ? customizer : undefined;
11155       return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
11156     }
11157
11158     /**
11159      * Checks if `object` conforms to `source` by invoking the predicate
11160      * properties of `source` with the corresponding property values of `object`.
11161      *
11162      * **Note:** This method is equivalent to `_.conforms` when `source` is
11163      * partially applied.
11164      *
11165      * @static
11166      * @memberOf _
11167      * @since 4.14.0
11168      * @category Lang
11169      * @param {Object} object The object to inspect.
11170      * @param {Object} source The object of property predicates to conform to.
11171      * @returns {boolean} Returns `true` if `object` conforms, else `false`.
11172      * @example
11173      *
11174      * var object = { 'a': 1, 'b': 2 };
11175      *
11176      * _.conformsTo(object, { 'b': function(n) { return n > 1; } });
11177      * // => true
11178      *
11179      * _.conformsTo(object, { 'b': function(n) { return n > 2; } });
11180      * // => false
11181      */
11182     function conformsTo(object, source) {
11183       return source == null || baseConformsTo(object, source, keys(source));
11184     }
11185
11186     /**
11187      * Performs a
11188      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
11189      * comparison between two values to determine if they are equivalent.
11190      *
11191      * @static
11192      * @memberOf _
11193      * @since 4.0.0
11194      * @category Lang
11195      * @param {*} value The value to compare.
11196      * @param {*} other The other value to compare.
11197      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11198      * @example
11199      *
11200      * var object = { 'a': 1 };
11201      * var other = { 'a': 1 };
11202      *
11203      * _.eq(object, object);
11204      * // => true
11205      *
11206      * _.eq(object, other);
11207      * // => false
11208      *
11209      * _.eq('a', 'a');
11210      * // => true
11211      *
11212      * _.eq('a', Object('a'));
11213      * // => false
11214      *
11215      * _.eq(NaN, NaN);
11216      * // => true
11217      */
11218     function eq(value, other) {
11219       return value === other || (value !== value && other !== other);
11220     }
11221
11222     /**
11223      * Checks if `value` is greater than `other`.
11224      *
11225      * @static
11226      * @memberOf _
11227      * @since 3.9.0
11228      * @category Lang
11229      * @param {*} value The value to compare.
11230      * @param {*} other The other value to compare.
11231      * @returns {boolean} Returns `true` if `value` is greater than `other`,
11232      *  else `false`.
11233      * @see _.lt
11234      * @example
11235      *
11236      * _.gt(3, 1);
11237      * // => true
11238      *
11239      * _.gt(3, 3);
11240      * // => false
11241      *
11242      * _.gt(1, 3);
11243      * // => false
11244      */
11245     var gt = createRelationalOperation(baseGt);
11246
11247     /**
11248      * Checks if `value` is greater than or equal to `other`.
11249      *
11250      * @static
11251      * @memberOf _
11252      * @since 3.9.0
11253      * @category Lang
11254      * @param {*} value The value to compare.
11255      * @param {*} other The other value to compare.
11256      * @returns {boolean} Returns `true` if `value` is greater than or equal to
11257      *  `other`, else `false`.
11258      * @see _.lte
11259      * @example
11260      *
11261      * _.gte(3, 1);
11262      * // => true
11263      *
11264      * _.gte(3, 3);
11265      * // => true
11266      *
11267      * _.gte(1, 3);
11268      * // => false
11269      */
11270     var gte = createRelationalOperation(function(value, other) {
11271       return value >= other;
11272     });
11273
11274     /**
11275      * Checks if `value` is likely an `arguments` object.
11276      *
11277      * @static
11278      * @memberOf _
11279      * @since 0.1.0
11280      * @category Lang
11281      * @param {*} value The value to check.
11282      * @returns {boolean} Returns `true` if `value` is an `arguments` object,
11283      *  else `false`.
11284      * @example
11285      *
11286      * _.isArguments(function() { return arguments; }());
11287      * // => true
11288      *
11289      * _.isArguments([1, 2, 3]);
11290      * // => false
11291      */
11292     var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
11293       return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
11294         !propertyIsEnumerable.call(value, 'callee');
11295     };
11296
11297     /**
11298      * Checks if `value` is classified as an `Array` object.
11299      *
11300      * @static
11301      * @memberOf _
11302      * @since 0.1.0
11303      * @category Lang
11304      * @param {*} value The value to check.
11305      * @returns {boolean} Returns `true` if `value` is an array, else `false`.
11306      * @example
11307      *
11308      * _.isArray([1, 2, 3]);
11309      * // => true
11310      *
11311      * _.isArray(document.body.children);
11312      * // => false
11313      *
11314      * _.isArray('abc');
11315      * // => false
11316      *
11317      * _.isArray(_.noop);
11318      * // => false
11319      */
11320     var isArray = Array.isArray;
11321
11322     /**
11323      * Checks if `value` is classified as an `ArrayBuffer` object.
11324      *
11325      * @static
11326      * @memberOf _
11327      * @since 4.3.0
11328      * @category Lang
11329      * @param {*} value The value to check.
11330      * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
11331      * @example
11332      *
11333      * _.isArrayBuffer(new ArrayBuffer(2));
11334      * // => true
11335      *
11336      * _.isArrayBuffer(new Array(2));
11337      * // => false
11338      */
11339     var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;
11340
11341     /**
11342      * Checks if `value` is array-like. A value is considered array-like if it's
11343      * not a function and has a `value.length` that's an integer greater than or
11344      * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
11345      *
11346      * @static
11347      * @memberOf _
11348      * @since 4.0.0
11349      * @category Lang
11350      * @param {*} value The value to check.
11351      * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
11352      * @example
11353      *
11354      * _.isArrayLike([1, 2, 3]);
11355      * // => true
11356      *
11357      * _.isArrayLike(document.body.children);
11358      * // => true
11359      *
11360      * _.isArrayLike('abc');
11361      * // => true
11362      *
11363      * _.isArrayLike(_.noop);
11364      * // => false
11365      */
11366     function isArrayLike(value) {
11367       return value != null && isLength(value.length) && !isFunction(value);
11368     }
11369
11370     /**
11371      * This method is like `_.isArrayLike` except that it also checks if `value`
11372      * is an object.
11373      *
11374      * @static
11375      * @memberOf _
11376      * @since 4.0.0
11377      * @category Lang
11378      * @param {*} value The value to check.
11379      * @returns {boolean} Returns `true` if `value` is an array-like object,
11380      *  else `false`.
11381      * @example
11382      *
11383      * _.isArrayLikeObject([1, 2, 3]);
11384      * // => true
11385      *
11386      * _.isArrayLikeObject(document.body.children);
11387      * // => true
11388      *
11389      * _.isArrayLikeObject('abc');
11390      * // => false
11391      *
11392      * _.isArrayLikeObject(_.noop);
11393      * // => false
11394      */
11395     function isArrayLikeObject(value) {
11396       return isObjectLike(value) && isArrayLike(value);
11397     }
11398
11399     /**
11400      * Checks if `value` is classified as a boolean primitive or object.
11401      *
11402      * @static
11403      * @memberOf _
11404      * @since 0.1.0
11405      * @category Lang
11406      * @param {*} value The value to check.
11407      * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
11408      * @example
11409      *
11410      * _.isBoolean(false);
11411      * // => true
11412      *
11413      * _.isBoolean(null);
11414      * // => false
11415      */
11416     function isBoolean(value) {
11417       return value === true || value === false ||
11418         (isObjectLike(value) && baseGetTag(value) == boolTag);
11419     }
11420
11421     /**
11422      * Checks if `value` is a buffer.
11423      *
11424      * @static
11425      * @memberOf _
11426      * @since 4.3.0
11427      * @category Lang
11428      * @param {*} value The value to check.
11429      * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
11430      * @example
11431      *
11432      * _.isBuffer(new Buffer(2));
11433      * // => true
11434      *
11435      * _.isBuffer(new Uint8Array(2));
11436      * // => false
11437      */
11438     var isBuffer = nativeIsBuffer || stubFalse;
11439
11440     /**
11441      * Checks if `value` is classified as a `Date` object.
11442      *
11443      * @static
11444      * @memberOf _
11445      * @since 0.1.0
11446      * @category Lang
11447      * @param {*} value The value to check.
11448      * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
11449      * @example
11450      *
11451      * _.isDate(new Date);
11452      * // => true
11453      *
11454      * _.isDate('Mon April 23 2012');
11455      * // => false
11456      */
11457     var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
11458
11459     /**
11460      * Checks if `value` is likely a DOM element.
11461      *
11462      * @static
11463      * @memberOf _
11464      * @since 0.1.0
11465      * @category Lang
11466      * @param {*} value The value to check.
11467      * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
11468      * @example
11469      *
11470      * _.isElement(document.body);
11471      * // => true
11472      *
11473      * _.isElement('<body>');
11474      * // => false
11475      */
11476     function isElement(value) {
11477       return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
11478     }
11479
11480     /**
11481      * Checks if `value` is an empty object, collection, map, or set.
11482      *
11483      * Objects are considered empty if they have no own enumerable string keyed
11484      * properties.
11485      *
11486      * Array-like values such as `arguments` objects, arrays, buffers, strings, or
11487      * jQuery-like collections are considered empty if they have a `length` of `0`.
11488      * Similarly, maps and sets are considered empty if they have a `size` of `0`.
11489      *
11490      * @static
11491      * @memberOf _
11492      * @since 0.1.0
11493      * @category Lang
11494      * @param {*} value The value to check.
11495      * @returns {boolean} Returns `true` if `value` is empty, else `false`.
11496      * @example
11497      *
11498      * _.isEmpty(null);
11499      * // => true
11500      *
11501      * _.isEmpty(true);
11502      * // => true
11503      *
11504      * _.isEmpty(1);
11505      * // => true
11506      *
11507      * _.isEmpty([1, 2, 3]);
11508      * // => false
11509      *
11510      * _.isEmpty({ 'a': 1 });
11511      * // => false
11512      */
11513     function isEmpty(value) {
11514       if (value == null) {
11515         return true;
11516       }
11517       if (isArrayLike(value) &&
11518           (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
11519             isBuffer(value) || isTypedArray(value) || isArguments(value))) {
11520         return !value.length;
11521       }
11522       var tag = getTag(value);
11523       if (tag == mapTag || tag == setTag) {
11524         return !value.size;
11525       }
11526       if (isPrototype(value)) {
11527         return !baseKeys(value).length;
11528       }
11529       for (var key in value) {
11530         if (hasOwnProperty.call(value, key)) {
11531           return false;
11532         }
11533       }
11534       return true;
11535     }
11536
11537     /**
11538      * Performs a deep comparison between two values to determine if they are
11539      * equivalent.
11540      *
11541      * **Note:** This method supports comparing arrays, array buffers, booleans,
11542      * date objects, error objects, maps, numbers, `Object` objects, regexes,
11543      * sets, strings, symbols, and typed arrays. `Object` objects are compared
11544      * by their own, not inherited, enumerable properties. Functions and DOM
11545      * nodes are compared by strict equality, i.e. `===`.
11546      *
11547      * @static
11548      * @memberOf _
11549      * @since 0.1.0
11550      * @category Lang
11551      * @param {*} value The value to compare.
11552      * @param {*} other The other value to compare.
11553      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11554      * @example
11555      *
11556      * var object = { 'a': 1 };
11557      * var other = { 'a': 1 };
11558      *
11559      * _.isEqual(object, other);
11560      * // => true
11561      *
11562      * object === other;
11563      * // => false
11564      */
11565     function isEqual(value, other) {
11566       return baseIsEqual(value, other);
11567     }
11568
11569     /**
11570      * This method is like `_.isEqual` except that it accepts `customizer` which
11571      * is invoked to compare values. If `customizer` returns `undefined`, comparisons
11572      * are handled by the method instead. The `customizer` is invoked with up to
11573      * six arguments: (objValue, othValue [, index|key, object, other, stack]).
11574      *
11575      * @static
11576      * @memberOf _
11577      * @since 4.0.0
11578      * @category Lang
11579      * @param {*} value The value to compare.
11580      * @param {*} other The other value to compare.
11581      * @param {Function} [customizer] The function to customize comparisons.
11582      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11583      * @example
11584      *
11585      * function isGreeting(value) {
11586      *   return /^h(?:i|ello)$/.test(value);
11587      * }
11588      *
11589      * function customizer(objValue, othValue) {
11590      *   if (isGreeting(objValue) && isGreeting(othValue)) {
11591      *     return true;
11592      *   }
11593      * }
11594      *
11595      * var array = ['hello', 'goodbye'];
11596      * var other = ['hi', 'goodbye'];
11597      *
11598      * _.isEqualWith(array, other, customizer);
11599      * // => true
11600      */
11601     function isEqualWith(value, other, customizer) {
11602       customizer = typeof customizer == 'function' ? customizer : undefined;
11603       var result = customizer ? customizer(value, other) : undefined;
11604       return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;
11605     }
11606
11607     /**
11608      * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
11609      * `SyntaxError`, `TypeError`, or `URIError` object.
11610      *
11611      * @static
11612      * @memberOf _
11613      * @since 3.0.0
11614      * @category Lang
11615      * @param {*} value The value to check.
11616      * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
11617      * @example
11618      *
11619      * _.isError(new Error);
11620      * // => true
11621      *
11622      * _.isError(Error);
11623      * // => false
11624      */
11625     function isError(value) {
11626       if (!isObjectLike(value)) {
11627         return false;
11628       }
11629       var tag = baseGetTag(value);
11630       return tag == errorTag || tag == domExcTag ||
11631         (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));
11632     }
11633
11634     /**
11635      * Checks if `value` is a finite primitive number.
11636      *
11637      * **Note:** This method is based on
11638      * [`Number.isFinite`](https://mdn.io/Number/isFinite).
11639      *
11640      * @static
11641      * @memberOf _
11642      * @since 0.1.0
11643      * @category Lang
11644      * @param {*} value The value to check.
11645      * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
11646      * @example
11647      *
11648      * _.isFinite(3);
11649      * // => true
11650      *
11651      * _.isFinite(Number.MIN_VALUE);
11652      * // => true
11653      *
11654      * _.isFinite(Infinity);
11655      * // => false
11656      *
11657      * _.isFinite('3');
11658      * // => false
11659      */
11660     function isFinite(value) {
11661       return typeof value == 'number' && nativeIsFinite(value);
11662     }
11663
11664     /**
11665      * Checks if `value` is classified as a `Function` object.
11666      *
11667      * @static
11668      * @memberOf _
11669      * @since 0.1.0
11670      * @category Lang
11671      * @param {*} value The value to check.
11672      * @returns {boolean} Returns `true` if `value` is a function, else `false`.
11673      * @example
11674      *
11675      * _.isFunction(_);
11676      * // => true
11677      *
11678      * _.isFunction(/abc/);
11679      * // => false
11680      */
11681     function isFunction(value) {
11682       if (!isObject(value)) {
11683         return false;
11684       }
11685       // The use of `Object#toString` avoids issues with the `typeof` operator
11686       // in Safari 9 which returns 'object' for typed arrays and other constructors.
11687       var tag = baseGetTag(value);
11688       return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
11689     }
11690
11691     /**
11692      * Checks if `value` is an integer.
11693      *
11694      * **Note:** This method is based on
11695      * [`Number.isInteger`](https://mdn.io/Number/isInteger).
11696      *
11697      * @static
11698      * @memberOf _
11699      * @since 4.0.0
11700      * @category Lang
11701      * @param {*} value The value to check.
11702      * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
11703      * @example
11704      *
11705      * _.isInteger(3);
11706      * // => true
11707      *
11708      * _.isInteger(Number.MIN_VALUE);
11709      * // => false
11710      *
11711      * _.isInteger(Infinity);
11712      * // => false
11713      *
11714      * _.isInteger('3');
11715      * // => false
11716      */
11717     function isInteger(value) {
11718       return typeof value == 'number' && value == toInteger(value);
11719     }
11720
11721     /**
11722      * Checks if `value` is a valid array-like length.
11723      *
11724      * **Note:** This method is loosely based on
11725      * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
11726      *
11727      * @static
11728      * @memberOf _
11729      * @since 4.0.0
11730      * @category Lang
11731      * @param {*} value The value to check.
11732      * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
11733      * @example
11734      *
11735      * _.isLength(3);
11736      * // => true
11737      *
11738      * _.isLength(Number.MIN_VALUE);
11739      * // => false
11740      *
11741      * _.isLength(Infinity);
11742      * // => false
11743      *
11744      * _.isLength('3');
11745      * // => false
11746      */
11747     function isLength(value) {
11748       return typeof value == 'number' &&
11749         value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
11750     }
11751
11752     /**
11753      * Checks if `value` is the
11754      * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
11755      * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
11756      *
11757      * @static
11758      * @memberOf _
11759      * @since 0.1.0
11760      * @category Lang
11761      * @param {*} value The value to check.
11762      * @returns {boolean} Returns `true` if `value` is an object, else `false`.
11763      * @example
11764      *
11765      * _.isObject({});
11766      * // => true
11767      *
11768      * _.isObject([1, 2, 3]);
11769      * // => true
11770      *
11771      * _.isObject(_.noop);
11772      * // => true
11773      *
11774      * _.isObject(null);
11775      * // => false
11776      */
11777     function isObject(value) {
11778       var type = typeof value;
11779       return value != null && (type == 'object' || type == 'function');
11780     }
11781
11782     /**
11783      * Checks if `value` is object-like. A value is object-like if it's not `null`
11784      * and has a `typeof` result of "object".
11785      *
11786      * @static
11787      * @memberOf _
11788      * @since 4.0.0
11789      * @category Lang
11790      * @param {*} value The value to check.
11791      * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
11792      * @example
11793      *
11794      * _.isObjectLike({});
11795      * // => true
11796      *
11797      * _.isObjectLike([1, 2, 3]);
11798      * // => true
11799      *
11800      * _.isObjectLike(_.noop);
11801      * // => false
11802      *
11803      * _.isObjectLike(null);
11804      * // => false
11805      */
11806     function isObjectLike(value) {
11807       return value != null && typeof value == 'object';
11808     }
11809
11810     /**
11811      * Checks if `value` is classified as a `Map` object.
11812      *
11813      * @static
11814      * @memberOf _
11815      * @since 4.3.0
11816      * @category Lang
11817      * @param {*} value The value to check.
11818      * @returns {boolean} Returns `true` if `value` is a map, else `false`.
11819      * @example
11820      *
11821      * _.isMap(new Map);
11822      * // => true
11823      *
11824      * _.isMap(new WeakMap);
11825      * // => false
11826      */
11827     var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;
11828
11829     /**
11830      * Performs a partial deep comparison between `object` and `source` to
11831      * determine if `object` contains equivalent property values.
11832      *
11833      * **Note:** This method is equivalent to `_.matches` when `source` is
11834      * partially applied.
11835      *
11836      * Partial comparisons will match empty array and empty object `source`
11837      * values against any array or object value, respectively. See `_.isEqual`
11838      * for a list of supported value comparisons.
11839      *
11840      * @static
11841      * @memberOf _
11842      * @since 3.0.0
11843      * @category Lang
11844      * @param {Object} object The object to inspect.
11845      * @param {Object} source The object of property values to match.
11846      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
11847      * @example
11848      *
11849      * var object = { 'a': 1, 'b': 2 };
11850      *
11851      * _.isMatch(object, { 'b': 2 });
11852      * // => true
11853      *
11854      * _.isMatch(object, { 'b': 1 });
11855      * // => false
11856      */
11857     function isMatch(object, source) {
11858       return object === source || baseIsMatch(object, source, getMatchData(source));
11859     }
11860
11861     /**
11862      * This method is like `_.isMatch` except that it accepts `customizer` which
11863      * is invoked to compare values. If `customizer` returns `undefined`, comparisons
11864      * are handled by the method instead. The `customizer` is invoked with five
11865      * arguments: (objValue, srcValue, index|key, object, source).
11866      *
11867      * @static
11868      * @memberOf _
11869      * @since 4.0.0
11870      * @category Lang
11871      * @param {Object} object The object to inspect.
11872      * @param {Object} source The object of property values to match.
11873      * @param {Function} [customizer] The function to customize comparisons.
11874      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
11875      * @example
11876      *
11877      * function isGreeting(value) {
11878      *   return /^h(?:i|ello)$/.test(value);
11879      * }
11880      *
11881      * function customizer(objValue, srcValue) {
11882      *   if (isGreeting(objValue) && isGreeting(srcValue)) {
11883      *     return true;
11884      *   }
11885      * }
11886      *
11887      * var object = { 'greeting': 'hello' };
11888      * var source = { 'greeting': 'hi' };
11889      *
11890      * _.isMatchWith(object, source, customizer);
11891      * // => true
11892      */
11893     function isMatchWith(object, source, customizer) {
11894       customizer = typeof customizer == 'function' ? customizer : undefined;
11895       return baseIsMatch(object, source, getMatchData(source), customizer);
11896     }
11897
11898     /**
11899      * Checks if `value` is `NaN`.
11900      *
11901      * **Note:** This method is based on
11902      * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
11903      * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
11904      * `undefined` and other non-number values.
11905      *
11906      * @static
11907      * @memberOf _
11908      * @since 0.1.0
11909      * @category Lang
11910      * @param {*} value The value to check.
11911      * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
11912      * @example
11913      *
11914      * _.isNaN(NaN);
11915      * // => true
11916      *
11917      * _.isNaN(new Number(NaN));
11918      * // => true
11919      *
11920      * isNaN(undefined);
11921      * // => true
11922      *
11923      * _.isNaN(undefined);
11924      * // => false
11925      */
11926     function isNaN(value) {
11927       // An `NaN` primitive is the only value that is not equal to itself.
11928       // Perform the `toStringTag` check first to avoid errors with some
11929       // ActiveX objects in IE.
11930       return isNumber(value) && value != +value;
11931     }
11932
11933     /**
11934      * Checks if `value` is a pristine native function.
11935      *
11936      * **Note:** This method can't reliably detect native functions in the presence
11937      * of the core-js package because core-js circumvents this kind of detection.
11938      * Despite multiple requests, the core-js maintainer has made it clear: any
11939      * attempt to fix the detection will be obstructed. As a result, we're left
11940      * with little choice but to throw an error. Unfortunately, this also affects
11941      * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
11942      * which rely on core-js.
11943      *
11944      * @static
11945      * @memberOf _
11946      * @since 3.0.0
11947      * @category Lang
11948      * @param {*} value The value to check.
11949      * @returns {boolean} Returns `true` if `value` is a native function,
11950      *  else `false`.
11951      * @example
11952      *
11953      * _.isNative(Array.prototype.push);
11954      * // => true
11955      *
11956      * _.isNative(_);
11957      * // => false
11958      */
11959     function isNative(value) {
11960       if (isMaskable(value)) {
11961         throw new Error(CORE_ERROR_TEXT);
11962       }
11963       return baseIsNative(value);
11964     }
11965
11966     /**
11967      * Checks if `value` is `null`.
11968      *
11969      * @static
11970      * @memberOf _
11971      * @since 0.1.0
11972      * @category Lang
11973      * @param {*} value The value to check.
11974      * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
11975      * @example
11976      *
11977      * _.isNull(null);
11978      * // => true
11979      *
11980      * _.isNull(void 0);
11981      * // => false
11982      */
11983     function isNull(value) {
11984       return value === null;
11985     }
11986
11987     /**
11988      * Checks if `value` is `null` or `undefined`.
11989      *
11990      * @static
11991      * @memberOf _
11992      * @since 4.0.0
11993      * @category Lang
11994      * @param {*} value The value to check.
11995      * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
11996      * @example
11997      *
11998      * _.isNil(null);
11999      * // => true
12000      *
12001      * _.isNil(void 0);
12002      * // => true
12003      *
12004      * _.isNil(NaN);
12005      * // => false
12006      */
12007     function isNil(value) {
12008       return value == null;
12009     }
12010
12011     /**
12012      * Checks if `value` is classified as a `Number` primitive or object.
12013      *
12014      * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
12015      * classified as numbers, use the `_.isFinite` method.
12016      *
12017      * @static
12018      * @memberOf _
12019      * @since 0.1.0
12020      * @category Lang
12021      * @param {*} value The value to check.
12022      * @returns {boolean} Returns `true` if `value` is a number, else `false`.
12023      * @example
12024      *
12025      * _.isNumber(3);
12026      * // => true
12027      *
12028      * _.isNumber(Number.MIN_VALUE);
12029      * // => true
12030      *
12031      * _.isNumber(Infinity);
12032      * // => true
12033      *
12034      * _.isNumber('3');
12035      * // => false
12036      */
12037     function isNumber(value) {
12038       return typeof value == 'number' ||
12039         (isObjectLike(value) && baseGetTag(value) == numberTag);
12040     }
12041
12042     /**
12043      * Checks if `value` is a plain object, that is, an object created by the
12044      * `Object` constructor or one with a `[[Prototype]]` of `null`.
12045      *
12046      * @static
12047      * @memberOf _
12048      * @since 0.8.0
12049      * @category Lang
12050      * @param {*} value The value to check.
12051      * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
12052      * @example
12053      *
12054      * function Foo() {
12055      *   this.a = 1;
12056      * }
12057      *
12058      * _.isPlainObject(new Foo);
12059      * // => false
12060      *
12061      * _.isPlainObject([1, 2, 3]);
12062      * // => false
12063      *
12064      * _.isPlainObject({ 'x': 0, 'y': 0 });
12065      * // => true
12066      *
12067      * _.isPlainObject(Object.create(null));
12068      * // => true
12069      */
12070     function isPlainObject(value) {
12071       if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
12072         return false;
12073       }
12074       var proto = getPrototype(value);
12075       if (proto === null) {
12076         return true;
12077       }
12078       var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
12079       return typeof Ctor == 'function' && Ctor instanceof Ctor &&
12080         funcToString.call(Ctor) == objectCtorString;
12081     }
12082
12083     /**
12084      * Checks if `value` is classified as a `RegExp` object.
12085      *
12086      * @static
12087      * @memberOf _
12088      * @since 0.1.0
12089      * @category Lang
12090      * @param {*} value The value to check.
12091      * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
12092      * @example
12093      *
12094      * _.isRegExp(/abc/);
12095      * // => true
12096      *
12097      * _.isRegExp('/abc/');
12098      * // => false
12099      */
12100     var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;
12101
12102     /**
12103      * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
12104      * double precision number which isn't the result of a rounded unsafe integer.
12105      *
12106      * **Note:** This method is based on
12107      * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
12108      *
12109      * @static
12110      * @memberOf _
12111      * @since 4.0.0
12112      * @category Lang
12113      * @param {*} value The value to check.
12114      * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
12115      * @example
12116      *
12117      * _.isSafeInteger(3);
12118      * // => true
12119      *
12120      * _.isSafeInteger(Number.MIN_VALUE);
12121      * // => false
12122      *
12123      * _.isSafeInteger(Infinity);
12124      * // => false
12125      *
12126      * _.isSafeInteger('3');
12127      * // => false
12128      */
12129     function isSafeInteger(value) {
12130       return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
12131     }
12132
12133     /**
12134      * Checks if `value` is classified as a `Set` object.
12135      *
12136      * @static
12137      * @memberOf _
12138      * @since 4.3.0
12139      * @category Lang
12140      * @param {*} value The value to check.
12141      * @returns {boolean} Returns `true` if `value` is a set, else `false`.
12142      * @example
12143      *
12144      * _.isSet(new Set);
12145      * // => true
12146      *
12147      * _.isSet(new WeakSet);
12148      * // => false
12149      */
12150     var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
12151
12152     /**
12153      * Checks if `value` is classified as a `String` primitive or object.
12154      *
12155      * @static
12156      * @since 0.1.0
12157      * @memberOf _
12158      * @category Lang
12159      * @param {*} value The value to check.
12160      * @returns {boolean} Returns `true` if `value` is a string, else `false`.
12161      * @example
12162      *
12163      * _.isString('abc');
12164      * // => true
12165      *
12166      * _.isString(1);
12167      * // => false
12168      */
12169     function isString(value) {
12170       return typeof value == 'string' ||
12171         (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);
12172     }
12173
12174     /**
12175      * Checks if `value` is classified as a `Symbol` primitive or object.
12176      *
12177      * @static
12178      * @memberOf _
12179      * @since 4.0.0
12180      * @category Lang
12181      * @param {*} value The value to check.
12182      * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
12183      * @example
12184      *
12185      * _.isSymbol(Symbol.iterator);
12186      * // => true
12187      *
12188      * _.isSymbol('abc');
12189      * // => false
12190      */
12191     function isSymbol(value) {
12192       return typeof value == 'symbol' ||
12193         (isObjectLike(value) && baseGetTag(value) == symbolTag);
12194     }
12195
12196     /**
12197      * Checks if `value` is classified as a typed array.
12198      *
12199      * @static
12200      * @memberOf _
12201      * @since 3.0.0
12202      * @category Lang
12203      * @param {*} value The value to check.
12204      * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
12205      * @example
12206      *
12207      * _.isTypedArray(new Uint8Array);
12208      * // => true
12209      *
12210      * _.isTypedArray([]);
12211      * // => false
12212      */
12213     var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
12214
12215     /**
12216      * Checks if `value` is `undefined`.
12217      *
12218      * @static
12219      * @since 0.1.0
12220      * @memberOf _
12221      * @category Lang
12222      * @param {*} value The value to check.
12223      * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
12224      * @example
12225      *
12226      * _.isUndefined(void 0);
12227      * // => true
12228      *
12229      * _.isUndefined(null);
12230      * // => false
12231      */
12232     function isUndefined(value) {
12233       return value === undefined;
12234     }
12235
12236     /**
12237      * Checks if `value` is classified as a `WeakMap` object.
12238      *
12239      * @static
12240      * @memberOf _
12241      * @since 4.3.0
12242      * @category Lang
12243      * @param {*} value The value to check.
12244      * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
12245      * @example
12246      *
12247      * _.isWeakMap(new WeakMap);
12248      * // => true
12249      *
12250      * _.isWeakMap(new Map);
12251      * // => false
12252      */
12253     function isWeakMap(value) {
12254       return isObjectLike(value) && getTag(value) == weakMapTag;
12255     }
12256
12257     /**
12258      * Checks if `value` is classified as a `WeakSet` object.
12259      *
12260      * @static
12261      * @memberOf _
12262      * @since 4.3.0
12263      * @category Lang
12264      * @param {*} value The value to check.
12265      * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
12266      * @example
12267      *
12268      * _.isWeakSet(new WeakSet);
12269      * // => true
12270      *
12271      * _.isWeakSet(new Set);
12272      * // => false
12273      */
12274     function isWeakSet(value) {
12275       return isObjectLike(value) && baseGetTag(value) == weakSetTag;
12276     }
12277
12278     /**
12279      * Checks if `value` is less than `other`.
12280      *
12281      * @static
12282      * @memberOf _
12283      * @since 3.9.0
12284      * @category Lang
12285      * @param {*} value The value to compare.
12286      * @param {*} other The other value to compare.
12287      * @returns {boolean} Returns `true` if `value` is less than `other`,
12288      *  else `false`.
12289      * @see _.gt
12290      * @example
12291      *
12292      * _.lt(1, 3);
12293      * // => true
12294      *
12295      * _.lt(3, 3);
12296      * // => false
12297      *
12298      * _.lt(3, 1);
12299      * // => false
12300      */
12301     var lt = createRelationalOperation(baseLt);
12302
12303     /**
12304      * Checks if `value` is less than or equal to `other`.
12305      *
12306      * @static
12307      * @memberOf _
12308      * @since 3.9.0
12309      * @category Lang
12310      * @param {*} value The value to compare.
12311      * @param {*} other The other value to compare.
12312      * @returns {boolean} Returns `true` if `value` is less than or equal to
12313      *  `other`, else `false`.
12314      * @see _.gte
12315      * @example
12316      *
12317      * _.lte(1, 3);
12318      * // => true
12319      *
12320      * _.lte(3, 3);
12321      * // => true
12322      *
12323      * _.lte(3, 1);
12324      * // => false
12325      */
12326     var lte = createRelationalOperation(function(value, other) {
12327       return value <= other;
12328     });
12329
12330     /**
12331      * Converts `value` to an array.
12332      *
12333      * @static
12334      * @since 0.1.0
12335      * @memberOf _
12336      * @category Lang
12337      * @param {*} value The value to convert.
12338      * @returns {Array} Returns the converted array.
12339      * @example
12340      *
12341      * _.toArray({ 'a': 1, 'b': 2 });
12342      * // => [1, 2]
12343      *
12344      * _.toArray('abc');
12345      * // => ['a', 'b', 'c']
12346      *
12347      * _.toArray(1);
12348      * // => []
12349      *
12350      * _.toArray(null);
12351      * // => []
12352      */
12353     function toArray(value) {
12354       if (!value) {
12355         return [];
12356       }
12357       if (isArrayLike(value)) {
12358         return isString(value) ? stringToArray(value) : copyArray(value);
12359       }
12360       if (symIterator && value[symIterator]) {
12361         return iteratorToArray(value[symIterator]());
12362       }
12363       var tag = getTag(value),
12364           func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
12365
12366       return func(value);
12367     }
12368
12369     /**
12370      * Converts `value` to a finite number.
12371      *
12372      * @static
12373      * @memberOf _
12374      * @since 4.12.0
12375      * @category Lang
12376      * @param {*} value The value to convert.
12377      * @returns {number} Returns the converted number.
12378      * @example
12379      *
12380      * _.toFinite(3.2);
12381      * // => 3.2
12382      *
12383      * _.toFinite(Number.MIN_VALUE);
12384      * // => 5e-324
12385      *
12386      * _.toFinite(Infinity);
12387      * // => 1.7976931348623157e+308
12388      *
12389      * _.toFinite('3.2');
12390      * // => 3.2
12391      */
12392     function toFinite(value) {
12393       if (!value) {
12394         return value === 0 ? value : 0;
12395       }
12396       value = toNumber(value);
12397       if (value === INFINITY || value === -INFINITY) {
12398         var sign = (value < 0 ? -1 : 1);
12399         return sign * MAX_INTEGER;
12400       }
12401       return value === value ? value : 0;
12402     }
12403
12404     /**
12405      * Converts `value` to an integer.
12406      *
12407      * **Note:** This method is loosely based on
12408      * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
12409      *
12410      * @static
12411      * @memberOf _
12412      * @since 4.0.0
12413      * @category Lang
12414      * @param {*} value The value to convert.
12415      * @returns {number} Returns the converted integer.
12416      * @example
12417      *
12418      * _.toInteger(3.2);
12419      * // => 3
12420      *
12421      * _.toInteger(Number.MIN_VALUE);
12422      * // => 0
12423      *
12424      * _.toInteger(Infinity);
12425      * // => 1.7976931348623157e+308
12426      *
12427      * _.toInteger('3.2');
12428      * // => 3
12429      */
12430     function toInteger(value) {
12431       var result = toFinite(value),
12432           remainder = result % 1;
12433
12434       return result === result ? (remainder ? result - remainder : result) : 0;
12435     }
12436
12437     /**
12438      * Converts `value` to an integer suitable for use as the length of an
12439      * array-like object.
12440      *
12441      * **Note:** This method is based on
12442      * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
12443      *
12444      * @static
12445      * @memberOf _
12446      * @since 4.0.0
12447      * @category Lang
12448      * @param {*} value The value to convert.
12449      * @returns {number} Returns the converted integer.
12450      * @example
12451      *
12452      * _.toLength(3.2);
12453      * // => 3
12454      *
12455      * _.toLength(Number.MIN_VALUE);
12456      * // => 0
12457      *
12458      * _.toLength(Infinity);
12459      * // => 4294967295
12460      *
12461      * _.toLength('3.2');
12462      * // => 3
12463      */
12464     function toLength(value) {
12465       return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
12466     }
12467
12468     /**
12469      * Converts `value` to a number.
12470      *
12471      * @static
12472      * @memberOf _
12473      * @since 4.0.0
12474      * @category Lang
12475      * @param {*} value The value to process.
12476      * @returns {number} Returns the number.
12477      * @example
12478      *
12479      * _.toNumber(3.2);
12480      * // => 3.2
12481      *
12482      * _.toNumber(Number.MIN_VALUE);
12483      * // => 5e-324
12484      *
12485      * _.toNumber(Infinity);
12486      * // => Infinity
12487      *
12488      * _.toNumber('3.2');
12489      * // => 3.2
12490      */
12491     function toNumber(value) {
12492       if (typeof value == 'number') {
12493         return value;
12494       }
12495       if (isSymbol(value)) {
12496         return NAN;
12497       }
12498       if (isObject(value)) {
12499         var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
12500         value = isObject(other) ? (other + '') : other;
12501       }
12502       if (typeof value != 'string') {
12503         return value === 0 ? value : +value;
12504       }
12505       value = value.replace(reTrim, '');
12506       var isBinary = reIsBinary.test(value);
12507       return (isBinary || reIsOctal.test(value))
12508         ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
12509         : (reIsBadHex.test(value) ? NAN : +value);
12510     }
12511
12512     /**
12513      * Converts `value` to a plain object flattening inherited enumerable string
12514      * keyed properties of `value` to own properties of the plain object.
12515      *
12516      * @static
12517      * @memberOf _
12518      * @since 3.0.0
12519      * @category Lang
12520      * @param {*} value The value to convert.
12521      * @returns {Object} Returns the converted plain object.
12522      * @example
12523      *
12524      * function Foo() {
12525      *   this.b = 2;
12526      * }
12527      *
12528      * Foo.prototype.c = 3;
12529      *
12530      * _.assign({ 'a': 1 }, new Foo);
12531      * // => { 'a': 1, 'b': 2 }
12532      *
12533      * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
12534      * // => { 'a': 1, 'b': 2, 'c': 3 }
12535      */
12536     function toPlainObject(value) {
12537       return copyObject(value, keysIn(value));
12538     }
12539
12540     /**
12541      * Converts `value` to a safe integer. A safe integer can be compared and
12542      * represented correctly.
12543      *
12544      * @static
12545      * @memberOf _
12546      * @since 4.0.0
12547      * @category Lang
12548      * @param {*} value The value to convert.
12549      * @returns {number} Returns the converted integer.
12550      * @example
12551      *
12552      * _.toSafeInteger(3.2);
12553      * // => 3
12554      *
12555      * _.toSafeInteger(Number.MIN_VALUE);
12556      * // => 0
12557      *
12558      * _.toSafeInteger(Infinity);
12559      * // => 9007199254740991
12560      *
12561      * _.toSafeInteger('3.2');
12562      * // => 3
12563      */
12564     function toSafeInteger(value) {
12565       return value
12566         ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)
12567         : (value === 0 ? value : 0);
12568     }
12569
12570     /**
12571      * Converts `value` to a string. An empty string is returned for `null`
12572      * and `undefined` values. The sign of `-0` is preserved.
12573      *
12574      * @static
12575      * @memberOf _
12576      * @since 4.0.0
12577      * @category Lang
12578      * @param {*} value The value to convert.
12579      * @returns {string} Returns the converted string.
12580      * @example
12581      *
12582      * _.toString(null);
12583      * // => ''
12584      *
12585      * _.toString(-0);
12586      * // => '-0'
12587      *
12588      * _.toString([1, 2, 3]);
12589      * // => '1,2,3'
12590      */
12591     function toString(value) {
12592       return value == null ? '' : baseToString(value);
12593     }
12594
12595     /*------------------------------------------------------------------------*/
12596
12597     /**
12598      * Assigns own enumerable string keyed properties of source objects to the
12599      * destination object. Source objects are applied from left to right.
12600      * Subsequent sources overwrite property assignments of previous sources.
12601      *
12602      * **Note:** This method mutates `object` and is loosely based on
12603      * [`Object.assign`](https://mdn.io/Object/assign).
12604      *
12605      * @static
12606      * @memberOf _
12607      * @since 0.10.0
12608      * @category Object
12609      * @param {Object} object The destination object.
12610      * @param {...Object} [sources] The source objects.
12611      * @returns {Object} Returns `object`.
12612      * @see _.assignIn
12613      * @example
12614      *
12615      * function Foo() {
12616      *   this.a = 1;
12617      * }
12618      *
12619      * function Bar() {
12620      *   this.c = 3;
12621      * }
12622      *
12623      * Foo.prototype.b = 2;
12624      * Bar.prototype.d = 4;
12625      *
12626      * _.assign({ 'a': 0 }, new Foo, new Bar);
12627      * // => { 'a': 1, 'c': 3 }
12628      */
12629     var assign = createAssigner(function(object, source) {
12630       if (isPrototype(source) || isArrayLike(source)) {
12631         copyObject(source, keys(source), object);
12632         return;
12633       }
12634       for (var key in source) {
12635         if (hasOwnProperty.call(source, key)) {
12636           assignValue(object, key, source[key]);
12637         }
12638       }
12639     });
12640
12641     /**
12642      * This method is like `_.assign` except that it iterates over own and
12643      * inherited source properties.
12644      *
12645      * **Note:** This method mutates `object`.
12646      *
12647      * @static
12648      * @memberOf _
12649      * @since 4.0.0
12650      * @alias extend
12651      * @category Object
12652      * @param {Object} object The destination object.
12653      * @param {...Object} [sources] The source objects.
12654      * @returns {Object} Returns `object`.
12655      * @see _.assign
12656      * @example
12657      *
12658      * function Foo() {
12659      *   this.a = 1;
12660      * }
12661      *
12662      * function Bar() {
12663      *   this.c = 3;
12664      * }
12665      *
12666      * Foo.prototype.b = 2;
12667      * Bar.prototype.d = 4;
12668      *
12669      * _.assignIn({ 'a': 0 }, new Foo, new Bar);
12670      * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
12671      */
12672     var assignIn = createAssigner(function(object, source) {
12673       copyObject(source, keysIn(source), object);
12674     });
12675
12676     /**
12677      * This method is like `_.assignIn` except that it accepts `customizer`
12678      * which is invoked to produce the assigned values. If `customizer` returns
12679      * `undefined`, assignment is handled by the method instead. The `customizer`
12680      * is invoked with five arguments: (objValue, srcValue, key, object, source).
12681      *
12682      * **Note:** This method mutates `object`.
12683      *
12684      * @static
12685      * @memberOf _
12686      * @since 4.0.0
12687      * @alias extendWith
12688      * @category Object
12689      * @param {Object} object The destination object.
12690      * @param {...Object} sources The source objects.
12691      * @param {Function} [customizer] The function to customize assigned values.
12692      * @returns {Object} Returns `object`.
12693      * @see _.assignWith
12694      * @example
12695      *
12696      * function customizer(objValue, srcValue) {
12697      *   return _.isUndefined(objValue) ? srcValue : objValue;
12698      * }
12699      *
12700      * var defaults = _.partialRight(_.assignInWith, customizer);
12701      *
12702      * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12703      * // => { 'a': 1, 'b': 2 }
12704      */
12705     var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {
12706       copyObject(source, keysIn(source), object, customizer);
12707     });
12708
12709     /**
12710      * This method is like `_.assign` except that it accepts `customizer`
12711      * which is invoked to produce the assigned values. If `customizer` returns
12712      * `undefined`, assignment is handled by the method instead. The `customizer`
12713      * is invoked with five arguments: (objValue, srcValue, key, object, source).
12714      *
12715      * **Note:** This method mutates `object`.
12716      *
12717      * @static
12718      * @memberOf _
12719      * @since 4.0.0
12720      * @category Object
12721      * @param {Object} object The destination object.
12722      * @param {...Object} sources The source objects.
12723      * @param {Function} [customizer] The function to customize assigned values.
12724      * @returns {Object} Returns `object`.
12725      * @see _.assignInWith
12726      * @example
12727      *
12728      * function customizer(objValue, srcValue) {
12729      *   return _.isUndefined(objValue) ? srcValue : objValue;
12730      * }
12731      *
12732      * var defaults = _.partialRight(_.assignWith, customizer);
12733      *
12734      * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12735      * // => { 'a': 1, 'b': 2 }
12736      */
12737     var assignWith = createAssigner(function(object, source, srcIndex, customizer) {
12738       copyObject(source, keys(source), object, customizer);
12739     });
12740
12741     /**
12742      * Creates an array of values corresponding to `paths` of `object`.
12743      *
12744      * @static
12745      * @memberOf _
12746      * @since 1.0.0
12747      * @category Object
12748      * @param {Object} object The object to iterate over.
12749      * @param {...(string|string[])} [paths] The property paths to pick.
12750      * @returns {Array} Returns the picked values.
12751      * @example
12752      *
12753      * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
12754      *
12755      * _.at(object, ['a[0].b.c', 'a[1]']);
12756      * // => [3, 4]
12757      */
12758     var at = flatRest(baseAt);
12759
12760     /**
12761      * Creates an object that inherits from the `prototype` object. If a
12762      * `properties` object is given, its own enumerable string keyed properties
12763      * are assigned to the created object.
12764      *
12765      * @static
12766      * @memberOf _
12767      * @since 2.3.0
12768      * @category Object
12769      * @param {Object} prototype The object to inherit from.
12770      * @param {Object} [properties] The properties to assign to the object.
12771      * @returns {Object} Returns the new object.
12772      * @example
12773      *
12774      * function Shape() {
12775      *   this.x = 0;
12776      *   this.y = 0;
12777      * }
12778      *
12779      * function Circle() {
12780      *   Shape.call(this);
12781      * }
12782      *
12783      * Circle.prototype = _.create(Shape.prototype, {
12784      *   'constructor': Circle
12785      * });
12786      *
12787      * var circle = new Circle;
12788      * circle instanceof Circle;
12789      * // => true
12790      *
12791      * circle instanceof Shape;
12792      * // => true
12793      */
12794     function create(prototype, properties) {
12795       var result = baseCreate(prototype);
12796       return properties == null ? result : baseAssign(result, properties);
12797     }
12798
12799     /**
12800      * Assigns own and inherited enumerable string keyed properties of source
12801      * objects to the destination object for all destination properties that
12802      * resolve to `undefined`. Source objects are applied from left to right.
12803      * Once a property is set, additional values of the same property are ignored.
12804      *
12805      * **Note:** This method mutates `object`.
12806      *
12807      * @static
12808      * @since 0.1.0
12809      * @memberOf _
12810      * @category Object
12811      * @param {Object} object The destination object.
12812      * @param {...Object} [sources] The source objects.
12813      * @returns {Object} Returns `object`.
12814      * @see _.defaultsDeep
12815      * @example
12816      *
12817      * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12818      * // => { 'a': 1, 'b': 2 }
12819      */
12820     var defaults = baseRest(function(args) {
12821       args.push(undefined, customDefaultsAssignIn);
12822       return apply(assignInWith, undefined, args);
12823     });
12824
12825     /**
12826      * This method is like `_.defaults` except that it recursively assigns
12827      * default properties.
12828      *
12829      * **Note:** This method mutates `object`.
12830      *
12831      * @static
12832      * @memberOf _
12833      * @since 3.10.0
12834      * @category Object
12835      * @param {Object} object The destination object.
12836      * @param {...Object} [sources] The source objects.
12837      * @returns {Object} Returns `object`.
12838      * @see _.defaults
12839      * @example
12840      *
12841      * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
12842      * // => { 'a': { 'b': 2, 'c': 3 } }
12843      */
12844     var defaultsDeep = baseRest(function(args) {
12845       args.push(undefined, customDefaultsMerge);
12846       return apply(mergeWith, undefined, args);
12847     });
12848
12849     /**
12850      * This method is like `_.find` except that it returns the key of the first
12851      * element `predicate` returns truthy for instead of the element itself.
12852      *
12853      * @static
12854      * @memberOf _
12855      * @since 1.1.0
12856      * @category Object
12857      * @param {Object} object The object to inspect.
12858      * @param {Function} [predicate=_.identity] The function invoked per iteration.
12859      * @returns {string|undefined} Returns the key of the matched element,
12860      *  else `undefined`.
12861      * @example
12862      *
12863      * var users = {
12864      *   'barney':  { 'age': 36, 'active': true },
12865      *   'fred':    { 'age': 40, 'active': false },
12866      *   'pebbles': { 'age': 1,  'active': true }
12867      * };
12868      *
12869      * _.findKey(users, function(o) { return o.age < 40; });
12870      * // => 'barney' (iteration order is not guaranteed)
12871      *
12872      * // The `_.matches` iteratee shorthand.
12873      * _.findKey(users, { 'age': 1, 'active': true });
12874      * // => 'pebbles'
12875      *
12876      * // The `_.matchesProperty` iteratee shorthand.
12877      * _.findKey(users, ['active', false]);
12878      * // => 'fred'
12879      *
12880      * // The `_.property` iteratee shorthand.
12881      * _.findKey(users, 'active');
12882      * // => 'barney'
12883      */
12884     function findKey(object, predicate) {
12885       return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);
12886     }
12887
12888     /**
12889      * This method is like `_.findKey` except that it iterates over elements of
12890      * a collection in the opposite order.
12891      *
12892      * @static
12893      * @memberOf _
12894      * @since 2.0.0
12895      * @category Object
12896      * @param {Object} object The object to inspect.
12897      * @param {Function} [predicate=_.identity] The function invoked per iteration.
12898      * @returns {string|undefined} Returns the key of the matched element,
12899      *  else `undefined`.
12900      * @example
12901      *
12902      * var users = {
12903      *   'barney':  { 'age': 36, 'active': true },
12904      *   'fred':    { 'age': 40, 'active': false },
12905      *   'pebbles': { 'age': 1,  'active': true }
12906      * };
12907      *
12908      * _.findLastKey(users, function(o) { return o.age < 40; });
12909      * // => returns 'pebbles' assuming `_.findKey` returns 'barney'
12910      *
12911      * // The `_.matches` iteratee shorthand.
12912      * _.findLastKey(users, { 'age': 36, 'active': true });
12913      * // => 'barney'
12914      *
12915      * // The `_.matchesProperty` iteratee shorthand.
12916      * _.findLastKey(users, ['active', false]);
12917      * // => 'fred'
12918      *
12919      * // The `_.property` iteratee shorthand.
12920      * _.findLastKey(users, 'active');
12921      * // => 'pebbles'
12922      */
12923     function findLastKey(object, predicate) {
12924       return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);
12925     }
12926
12927     /**
12928      * Iterates over own and inherited enumerable string keyed properties of an
12929      * object and invokes `iteratee` for each property. The iteratee is invoked
12930      * with three arguments: (value, key, object). Iteratee functions may exit
12931      * iteration early by explicitly returning `false`.
12932      *
12933      * @static
12934      * @memberOf _
12935      * @since 0.3.0
12936      * @category Object
12937      * @param {Object} object The object to iterate over.
12938      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12939      * @returns {Object} Returns `object`.
12940      * @see _.forInRight
12941      * @example
12942      *
12943      * function Foo() {
12944      *   this.a = 1;
12945      *   this.b = 2;
12946      * }
12947      *
12948      * Foo.prototype.c = 3;
12949      *
12950      * _.forIn(new Foo, function(value, key) {
12951      *   console.log(key);
12952      * });
12953      * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
12954      */
12955     function forIn(object, iteratee) {
12956       return object == null
12957         ? object
12958         : baseFor(object, getIteratee(iteratee, 3), keysIn);
12959     }
12960
12961     /**
12962      * This method is like `_.forIn` except that it iterates over properties of
12963      * `object` in the opposite order.
12964      *
12965      * @static
12966      * @memberOf _
12967      * @since 2.0.0
12968      * @category Object
12969      * @param {Object} object The object to iterate over.
12970      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12971      * @returns {Object} Returns `object`.
12972      * @see _.forIn
12973      * @example
12974      *
12975      * function Foo() {
12976      *   this.a = 1;
12977      *   this.b = 2;
12978      * }
12979      *
12980      * Foo.prototype.c = 3;
12981      *
12982      * _.forInRight(new Foo, function(value, key) {
12983      *   console.log(key);
12984      * });
12985      * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
12986      */
12987     function forInRight(object, iteratee) {
12988       return object == null
12989         ? object
12990         : baseForRight(object, getIteratee(iteratee, 3), keysIn);
12991     }
12992
12993     /**
12994      * Iterates over own enumerable string keyed properties of an object and
12995      * invokes `iteratee` for each property. The iteratee is invoked with three
12996      * arguments: (value, key, object). Iteratee functions may exit iteration
12997      * early by explicitly returning `false`.
12998      *
12999      * @static
13000      * @memberOf _
13001      * @since 0.3.0
13002      * @category Object
13003      * @param {Object} object The object to iterate over.
13004      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13005      * @returns {Object} Returns `object`.
13006      * @see _.forOwnRight
13007      * @example
13008      *
13009      * function Foo() {
13010      *   this.a = 1;
13011      *   this.b = 2;
13012      * }
13013      *
13014      * Foo.prototype.c = 3;
13015      *
13016      * _.forOwn(new Foo, function(value, key) {
13017      *   console.log(key);
13018      * });
13019      * // => Logs 'a' then 'b' (iteration order is not guaranteed).
13020      */
13021     function forOwn(object, iteratee) {
13022       return object && baseForOwn(object, getIteratee(iteratee, 3));
13023     }
13024
13025     /**
13026      * This method is like `_.forOwn` except that it iterates over properties of
13027      * `object` in the opposite order.
13028      *
13029      * @static
13030      * @memberOf _
13031      * @since 2.0.0
13032      * @category Object
13033      * @param {Object} object The object to iterate over.
13034      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13035      * @returns {Object} Returns `object`.
13036      * @see _.forOwn
13037      * @example
13038      *
13039      * function Foo() {
13040      *   this.a = 1;
13041      *   this.b = 2;
13042      * }
13043      *
13044      * Foo.prototype.c = 3;
13045      *
13046      * _.forOwnRight(new Foo, function(value, key) {
13047      *   console.log(key);
13048      * });
13049      * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
13050      */
13051     function forOwnRight(object, iteratee) {
13052       return object && baseForOwnRight(object, getIteratee(iteratee, 3));
13053     }
13054
13055     /**
13056      * Creates an array of function property names from own enumerable properties
13057      * of `object`.
13058      *
13059      * @static
13060      * @since 0.1.0
13061      * @memberOf _
13062      * @category Object
13063      * @param {Object} object The object to inspect.
13064      * @returns {Array} Returns the function names.
13065      * @see _.functionsIn
13066      * @example
13067      *
13068      * function Foo() {
13069      *   this.a = _.constant('a');
13070      *   this.b = _.constant('b');
13071      * }
13072      *
13073      * Foo.prototype.c = _.constant('c');
13074      *
13075      * _.functions(new Foo);
13076      * // => ['a', 'b']
13077      */
13078     function functions(object) {
13079       return object == null ? [] : baseFunctions(object, keys(object));
13080     }
13081
13082     /**
13083      * Creates an array of function property names from own and inherited
13084      * enumerable properties of `object`.
13085      *
13086      * @static
13087      * @memberOf _
13088      * @since 4.0.0
13089      * @category Object
13090      * @param {Object} object The object to inspect.
13091      * @returns {Array} Returns the function names.
13092      * @see _.functions
13093      * @example
13094      *
13095      * function Foo() {
13096      *   this.a = _.constant('a');
13097      *   this.b = _.constant('b');
13098      * }
13099      *
13100      * Foo.prototype.c = _.constant('c');
13101      *
13102      * _.functionsIn(new Foo);
13103      * // => ['a', 'b', 'c']
13104      */
13105     function functionsIn(object) {
13106       return object == null ? [] : baseFunctions(object, keysIn(object));
13107     }
13108
13109     /**
13110      * Gets the value at `path` of `object`. If the resolved value is
13111      * `undefined`, the `defaultValue` is returned in its place.
13112      *
13113      * @static
13114      * @memberOf _
13115      * @since 3.7.0
13116      * @category Object
13117      * @param {Object} object The object to query.
13118      * @param {Array|string} path The path of the property to get.
13119      * @param {*} [defaultValue] The value returned for `undefined` resolved values.
13120      * @returns {*} Returns the resolved value.
13121      * @example
13122      *
13123      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13124      *
13125      * _.get(object, 'a[0].b.c');
13126      * // => 3
13127      *
13128      * _.get(object, ['a', '0', 'b', 'c']);
13129      * // => 3
13130      *
13131      * _.get(object, 'a.b.c', 'default');
13132      * // => 'default'
13133      */
13134     function get(object, path, defaultValue) {
13135       var result = object == null ? undefined : baseGet(object, path);
13136       return result === undefined ? defaultValue : result;
13137     }
13138
13139     /**
13140      * Checks if `path` is a direct property of `object`.
13141      *
13142      * @static
13143      * @since 0.1.0
13144      * @memberOf _
13145      * @category Object
13146      * @param {Object} object The object to query.
13147      * @param {Array|string} path The path to check.
13148      * @returns {boolean} Returns `true` if `path` exists, else `false`.
13149      * @example
13150      *
13151      * var object = { 'a': { 'b': 2 } };
13152      * var other = _.create({ 'a': _.create({ 'b': 2 }) });
13153      *
13154      * _.has(object, 'a');
13155      * // => true
13156      *
13157      * _.has(object, 'a.b');
13158      * // => true
13159      *
13160      * _.has(object, ['a', 'b']);
13161      * // => true
13162      *
13163      * _.has(other, 'a');
13164      * // => false
13165      */
13166     function has(object, path) {
13167       return object != null && hasPath(object, path, baseHas);
13168     }
13169
13170     /**
13171      * Checks if `path` is a direct or inherited property of `object`.
13172      *
13173      * @static
13174      * @memberOf _
13175      * @since 4.0.0
13176      * @category Object
13177      * @param {Object} object The object to query.
13178      * @param {Array|string} path The path to check.
13179      * @returns {boolean} Returns `true` if `path` exists, else `false`.
13180      * @example
13181      *
13182      * var object = _.create({ 'a': _.create({ 'b': 2 }) });
13183      *
13184      * _.hasIn(object, 'a');
13185      * // => true
13186      *
13187      * _.hasIn(object, 'a.b');
13188      * // => true
13189      *
13190      * _.hasIn(object, ['a', 'b']);
13191      * // => true
13192      *
13193      * _.hasIn(object, 'b');
13194      * // => false
13195      */
13196     function hasIn(object, path) {
13197       return object != null && hasPath(object, path, baseHasIn);
13198     }
13199
13200     /**
13201      * Creates an object composed of the inverted keys and values of `object`.
13202      * If `object` contains duplicate values, subsequent values overwrite
13203      * property assignments of previous values.
13204      *
13205      * @static
13206      * @memberOf _
13207      * @since 0.7.0
13208      * @category Object
13209      * @param {Object} object The object to invert.
13210      * @returns {Object} Returns the new inverted object.
13211      * @example
13212      *
13213      * var object = { 'a': 1, 'b': 2, 'c': 1 };
13214      *
13215      * _.invert(object);
13216      * // => { '1': 'c', '2': 'b' }
13217      */
13218     var invert = createInverter(function(result, value, key) {
13219       result[value] = key;
13220     }, constant(identity));
13221
13222     /**
13223      * This method is like `_.invert` except that the inverted object is generated
13224      * from the results of running each element of `object` thru `iteratee`. The
13225      * corresponding inverted value of each inverted key is an array of keys
13226      * responsible for generating the inverted value. The iteratee is invoked
13227      * with one argument: (value).
13228      *
13229      * @static
13230      * @memberOf _
13231      * @since 4.1.0
13232      * @category Object
13233      * @param {Object} object The object to invert.
13234      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
13235      * @returns {Object} Returns the new inverted object.
13236      * @example
13237      *
13238      * var object = { 'a': 1, 'b': 2, 'c': 1 };
13239      *
13240      * _.invertBy(object);
13241      * // => { '1': ['a', 'c'], '2': ['b'] }
13242      *
13243      * _.invertBy(object, function(value) {
13244      *   return 'group' + value;
13245      * });
13246      * // => { 'group1': ['a', 'c'], 'group2': ['b'] }
13247      */
13248     var invertBy = createInverter(function(result, value, key) {
13249       if (hasOwnProperty.call(result, value)) {
13250         result[value].push(key);
13251       } else {
13252         result[value] = [key];
13253       }
13254     }, getIteratee);
13255
13256     /**
13257      * Invokes the method at `path` of `object`.
13258      *
13259      * @static
13260      * @memberOf _
13261      * @since 4.0.0
13262      * @category Object
13263      * @param {Object} object The object to query.
13264      * @param {Array|string} path The path of the method to invoke.
13265      * @param {...*} [args] The arguments to invoke the method with.
13266      * @returns {*} Returns the result of the invoked method.
13267      * @example
13268      *
13269      * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
13270      *
13271      * _.invoke(object, 'a[0].b.c.slice', 1, 3);
13272      * // => [2, 3]
13273      */
13274     var invoke = baseRest(baseInvoke);
13275
13276     /**
13277      * Creates an array of the own enumerable property names of `object`.
13278      *
13279      * **Note:** Non-object values are coerced to objects. See the
13280      * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
13281      * for more details.
13282      *
13283      * @static
13284      * @since 0.1.0
13285      * @memberOf _
13286      * @category Object
13287      * @param {Object} object The object to query.
13288      * @returns {Array} Returns the array of property names.
13289      * @example
13290      *
13291      * function Foo() {
13292      *   this.a = 1;
13293      *   this.b = 2;
13294      * }
13295      *
13296      * Foo.prototype.c = 3;
13297      *
13298      * _.keys(new Foo);
13299      * // => ['a', 'b'] (iteration order is not guaranteed)
13300      *
13301      * _.keys('hi');
13302      * // => ['0', '1']
13303      */
13304     function keys(object) {
13305       return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
13306     }
13307
13308     /**
13309      * Creates an array of the own and inherited enumerable property names of `object`.
13310      *
13311      * **Note:** Non-object values are coerced to objects.
13312      *
13313      * @static
13314      * @memberOf _
13315      * @since 3.0.0
13316      * @category Object
13317      * @param {Object} object The object to query.
13318      * @returns {Array} Returns the array of property names.
13319      * @example
13320      *
13321      * function Foo() {
13322      *   this.a = 1;
13323      *   this.b = 2;
13324      * }
13325      *
13326      * Foo.prototype.c = 3;
13327      *
13328      * _.keysIn(new Foo);
13329      * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
13330      */
13331     function keysIn(object) {
13332       return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
13333     }
13334
13335     /**
13336      * The opposite of `_.mapValues`; this method creates an object with the
13337      * same values as `object` and keys generated by running each own enumerable
13338      * string keyed property of `object` thru `iteratee`. The iteratee is invoked
13339      * with three arguments: (value, key, object).
13340      *
13341      * @static
13342      * @memberOf _
13343      * @since 3.8.0
13344      * @category Object
13345      * @param {Object} object The object to iterate over.
13346      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13347      * @returns {Object} Returns the new mapped object.
13348      * @see _.mapValues
13349      * @example
13350      *
13351      * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
13352      *   return key + value;
13353      * });
13354      * // => { 'a1': 1, 'b2': 2 }
13355      */
13356     function mapKeys(object, iteratee) {
13357       var result = {};
13358       iteratee = getIteratee(iteratee, 3);
13359
13360       baseForOwn(object, function(value, key, object) {
13361         baseAssignValue(result, iteratee(value, key, object), value);
13362       });
13363       return result;
13364     }
13365
13366     /**
13367      * Creates an object with the same keys as `object` and values generated
13368      * by running each own enumerable string keyed property of `object` thru
13369      * `iteratee`. The iteratee is invoked with three arguments:
13370      * (value, key, object).
13371      *
13372      * @static
13373      * @memberOf _
13374      * @since 2.4.0
13375      * @category Object
13376      * @param {Object} object The object to iterate over.
13377      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13378      * @returns {Object} Returns the new mapped object.
13379      * @see _.mapKeys
13380      * @example
13381      *
13382      * var users = {
13383      *   'fred':    { 'user': 'fred',    'age': 40 },
13384      *   'pebbles': { 'user': 'pebbles', 'age': 1 }
13385      * };
13386      *
13387      * _.mapValues(users, function(o) { return o.age; });
13388      * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
13389      *
13390      * // The `_.property` iteratee shorthand.
13391      * _.mapValues(users, 'age');
13392      * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
13393      */
13394     function mapValues(object, iteratee) {
13395       var result = {};
13396       iteratee = getIteratee(iteratee, 3);
13397
13398       baseForOwn(object, function(value, key, object) {
13399         baseAssignValue(result, key, iteratee(value, key, object));
13400       });
13401       return result;
13402     }
13403
13404     /**
13405      * This method is like `_.assign` except that it recursively merges own and
13406      * inherited enumerable string keyed properties of source objects into the
13407      * destination object. Source properties that resolve to `undefined` are
13408      * skipped if a destination value exists. Array and plain object properties
13409      * are merged recursively. Other objects and value types are overridden by
13410      * assignment. Source objects are applied from left to right. Subsequent
13411      * sources overwrite property assignments of previous sources.
13412      *
13413      * **Note:** This method mutates `object`.
13414      *
13415      * @static
13416      * @memberOf _
13417      * @since 0.5.0
13418      * @category Object
13419      * @param {Object} object The destination object.
13420      * @param {...Object} [sources] The source objects.
13421      * @returns {Object} Returns `object`.
13422      * @example
13423      *
13424      * var object = {
13425      *   'a': [{ 'b': 2 }, { 'd': 4 }]
13426      * };
13427      *
13428      * var other = {
13429      *   'a': [{ 'c': 3 }, { 'e': 5 }]
13430      * };
13431      *
13432      * _.merge(object, other);
13433      * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
13434      */
13435     var merge = createAssigner(function(object, source, srcIndex) {
13436       baseMerge(object, source, srcIndex);
13437     });
13438
13439     /**
13440      * This method is like `_.merge` except that it accepts `customizer` which
13441      * is invoked to produce the merged values of the destination and source
13442      * properties. If `customizer` returns `undefined`, merging is handled by the
13443      * method instead. The `customizer` is invoked with six arguments:
13444      * (objValue, srcValue, key, object, source, stack).
13445      *
13446      * **Note:** This method mutates `object`.
13447      *
13448      * @static
13449      * @memberOf _
13450      * @since 4.0.0
13451      * @category Object
13452      * @param {Object} object The destination object.
13453      * @param {...Object} sources The source objects.
13454      * @param {Function} customizer The function to customize assigned values.
13455      * @returns {Object} Returns `object`.
13456      * @example
13457      *
13458      * function customizer(objValue, srcValue) {
13459      *   if (_.isArray(objValue)) {
13460      *     return objValue.concat(srcValue);
13461      *   }
13462      * }
13463      *
13464      * var object = { 'a': [1], 'b': [2] };
13465      * var other = { 'a': [3], 'b': [4] };
13466      *
13467      * _.mergeWith(object, other, customizer);
13468      * // => { 'a': [1, 3], 'b': [2, 4] }
13469      */
13470     var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {
13471       baseMerge(object, source, srcIndex, customizer);
13472     });
13473
13474     /**
13475      * The opposite of `_.pick`; this method creates an object composed of the
13476      * own and inherited enumerable property paths of `object` that are not omitted.
13477      *
13478      * **Note:** This method is considerably slower than `_.pick`.
13479      *
13480      * @static
13481      * @since 0.1.0
13482      * @memberOf _
13483      * @category Object
13484      * @param {Object} object The source object.
13485      * @param {...(string|string[])} [paths] The property paths to omit.
13486      * @returns {Object} Returns the new object.
13487      * @example
13488      *
13489      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13490      *
13491      * _.omit(object, ['a', 'c']);
13492      * // => { 'b': '2' }
13493      */
13494     var omit = flatRest(function(object, paths) {
13495       var result = {};
13496       if (object == null) {
13497         return result;
13498       }
13499       var isDeep = false;
13500       paths = arrayMap(paths, function(path) {
13501         path = castPath(path, object);
13502         isDeep || (isDeep = path.length > 1);
13503         return path;
13504       });
13505       copyObject(object, getAllKeysIn(object), result);
13506       if (isDeep) {
13507         result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);
13508       }
13509       var length = paths.length;
13510       while (length--) {
13511         baseUnset(result, paths[length]);
13512       }
13513       return result;
13514     });
13515
13516     /**
13517      * The opposite of `_.pickBy`; this method creates an object composed of
13518      * the own and inherited enumerable string keyed properties of `object` that
13519      * `predicate` doesn't return truthy for. The predicate is invoked with two
13520      * arguments: (value, key).
13521      *
13522      * @static
13523      * @memberOf _
13524      * @since 4.0.0
13525      * @category Object
13526      * @param {Object} object The source object.
13527      * @param {Function} [predicate=_.identity] The function invoked per property.
13528      * @returns {Object} Returns the new object.
13529      * @example
13530      *
13531      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13532      *
13533      * _.omitBy(object, _.isNumber);
13534      * // => { 'b': '2' }
13535      */
13536     function omitBy(object, predicate) {
13537       return pickBy(object, negate(getIteratee(predicate)));
13538     }
13539
13540     /**
13541      * Creates an object composed of the picked `object` properties.
13542      *
13543      * @static
13544      * @since 0.1.0
13545      * @memberOf _
13546      * @category Object
13547      * @param {Object} object The source object.
13548      * @param {...(string|string[])} [paths] The property paths to pick.
13549      * @returns {Object} Returns the new object.
13550      * @example
13551      *
13552      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13553      *
13554      * _.pick(object, ['a', 'c']);
13555      * // => { 'a': 1, 'c': 3 }
13556      */
13557     var pick = flatRest(function(object, paths) {
13558       return object == null ? {} : basePick(object, paths);
13559     });
13560
13561     /**
13562      * Creates an object composed of the `object` properties `predicate` returns
13563      * truthy for. The predicate is invoked with two arguments: (value, key).
13564      *
13565      * @static
13566      * @memberOf _
13567      * @since 4.0.0
13568      * @category Object
13569      * @param {Object} object The source object.
13570      * @param {Function} [predicate=_.identity] The function invoked per property.
13571      * @returns {Object} Returns the new object.
13572      * @example
13573      *
13574      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13575      *
13576      * _.pickBy(object, _.isNumber);
13577      * // => { 'a': 1, 'c': 3 }
13578      */
13579     function pickBy(object, predicate) {
13580       if (object == null) {
13581         return {};
13582       }
13583       var props = arrayMap(getAllKeysIn(object), function(prop) {
13584         return [prop];
13585       });
13586       predicate = getIteratee(predicate);
13587       return basePickBy(object, props, function(value, path) {
13588         return predicate(value, path[0]);
13589       });
13590     }
13591
13592     /**
13593      * This method is like `_.get` except that if the resolved value is a
13594      * function it's invoked with the `this` binding of its parent object and
13595      * its result is returned.
13596      *
13597      * @static
13598      * @since 0.1.0
13599      * @memberOf _
13600      * @category Object
13601      * @param {Object} object The object to query.
13602      * @param {Array|string} path The path of the property to resolve.
13603      * @param {*} [defaultValue] The value returned for `undefined` resolved values.
13604      * @returns {*} Returns the resolved value.
13605      * @example
13606      *
13607      * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
13608      *
13609      * _.result(object, 'a[0].b.c1');
13610      * // => 3
13611      *
13612      * _.result(object, 'a[0].b.c2');
13613      * // => 4
13614      *
13615      * _.result(object, 'a[0].b.c3', 'default');
13616      * // => 'default'
13617      *
13618      * _.result(object, 'a[0].b.c3', _.constant('default'));
13619      * // => 'default'
13620      */
13621     function result(object, path, defaultValue) {
13622       path = castPath(path, object);
13623
13624       var index = -1,
13625           length = path.length;
13626
13627       // Ensure the loop is entered when path is empty.
13628       if (!length) {
13629         length = 1;
13630         object = undefined;
13631       }
13632       while (++index < length) {
13633         var value = object == null ? undefined : object[toKey(path[index])];
13634         if (value === undefined) {
13635           index = length;
13636           value = defaultValue;
13637         }
13638         object = isFunction(value) ? value.call(object) : value;
13639       }
13640       return object;
13641     }
13642
13643     /**
13644      * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
13645      * it's created. Arrays are created for missing index properties while objects
13646      * are created for all other missing properties. Use `_.setWith` to customize
13647      * `path` creation.
13648      *
13649      * **Note:** This method mutates `object`.
13650      *
13651      * @static
13652      * @memberOf _
13653      * @since 3.7.0
13654      * @category Object
13655      * @param {Object} object The object to modify.
13656      * @param {Array|string} path The path of the property to set.
13657      * @param {*} value The value to set.
13658      * @returns {Object} Returns `object`.
13659      * @example
13660      *
13661      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13662      *
13663      * _.set(object, 'a[0].b.c', 4);
13664      * console.log(object.a[0].b.c);
13665      * // => 4
13666      *
13667      * _.set(object, ['x', '0', 'y', 'z'], 5);
13668      * console.log(object.x[0].y.z);
13669      * // => 5
13670      */
13671     function set(object, path, value) {
13672       return object == null ? object : baseSet(object, path, value);
13673     }
13674
13675     /**
13676      * This method is like `_.set` except that it accepts `customizer` which is
13677      * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
13678      * path creation is handled by the method instead. The `customizer` is invoked
13679      * with three arguments: (nsValue, key, nsObject).
13680      *
13681      * **Note:** This method mutates `object`.
13682      *
13683      * @static
13684      * @memberOf _
13685      * @since 4.0.0
13686      * @category Object
13687      * @param {Object} object The object to modify.
13688      * @param {Array|string} path The path of the property to set.
13689      * @param {*} value The value to set.
13690      * @param {Function} [customizer] The function to customize assigned values.
13691      * @returns {Object} Returns `object`.
13692      * @example
13693      *
13694      * var object = {};
13695      *
13696      * _.setWith(object, '[0][1]', 'a', Object);
13697      * // => { '0': { '1': 'a' } }
13698      */
13699     function setWith(object, path, value, customizer) {
13700       customizer = typeof customizer == 'function' ? customizer : undefined;
13701       return object == null ? object : baseSet(object, path, value, customizer);
13702     }
13703
13704     /**
13705      * Creates an array of own enumerable string keyed-value pairs for `object`
13706      * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
13707      * entries are returned.
13708      *
13709      * @static
13710      * @memberOf _
13711      * @since 4.0.0
13712      * @alias entries
13713      * @category Object
13714      * @param {Object} object The object to query.
13715      * @returns {Array} Returns the key-value pairs.
13716      * @example
13717      *
13718      * function Foo() {
13719      *   this.a = 1;
13720      *   this.b = 2;
13721      * }
13722      *
13723      * Foo.prototype.c = 3;
13724      *
13725      * _.toPairs(new Foo);
13726      * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
13727      */
13728     var toPairs = createToPairs(keys);
13729
13730     /**
13731      * Creates an array of own and inherited enumerable string keyed-value pairs
13732      * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
13733      * or set, its entries are returned.
13734      *
13735      * @static
13736      * @memberOf _
13737      * @since 4.0.0
13738      * @alias entriesIn
13739      * @category Object
13740      * @param {Object} object The object to query.
13741      * @returns {Array} Returns the key-value pairs.
13742      * @example
13743      *
13744      * function Foo() {
13745      *   this.a = 1;
13746      *   this.b = 2;
13747      * }
13748      *
13749      * Foo.prototype.c = 3;
13750      *
13751      * _.toPairsIn(new Foo);
13752      * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
13753      */
13754     var toPairsIn = createToPairs(keysIn);
13755
13756     /**
13757      * An alternative to `_.reduce`; this method transforms `object` to a new
13758      * `accumulator` object which is the result of running each of its own
13759      * enumerable string keyed properties thru `iteratee`, with each invocation
13760      * potentially mutating the `accumulator` object. If `accumulator` is not
13761      * provided, a new object with the same `[[Prototype]]` will be used. The
13762      * iteratee is invoked with four arguments: (accumulator, value, key, object).
13763      * Iteratee functions may exit iteration early by explicitly returning `false`.
13764      *
13765      * @static
13766      * @memberOf _
13767      * @since 1.3.0
13768      * @category Object
13769      * @param {Object} object The object to iterate over.
13770      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13771      * @param {*} [accumulator] The custom accumulator value.
13772      * @returns {*} Returns the accumulated value.
13773      * @example
13774      *
13775      * _.transform([2, 3, 4], function(result, n) {
13776      *   result.push(n *= n);
13777      *   return n % 2 == 0;
13778      * }, []);
13779      * // => [4, 9]
13780      *
13781      * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
13782      *   (result[value] || (result[value] = [])).push(key);
13783      * }, {});
13784      * // => { '1': ['a', 'c'], '2': ['b'] }
13785      */
13786     function transform(object, iteratee, accumulator) {
13787       var isArr = isArray(object),
13788           isArrLike = isArr || isBuffer(object) || isTypedArray(object);
13789
13790       iteratee = getIteratee(iteratee, 4);
13791       if (accumulator == null) {
13792         var Ctor = object && object.constructor;
13793         if (isArrLike) {
13794           accumulator = isArr ? new Ctor : [];
13795         }
13796         else if (isObject(object)) {
13797           accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
13798         }
13799         else {
13800           accumulator = {};
13801         }
13802       }
13803       (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) {
13804         return iteratee(accumulator, value, index, object);
13805       });
13806       return accumulator;
13807     }
13808
13809     /**
13810      * Removes the property at `path` of `object`.
13811      *
13812      * **Note:** This method mutates `object`.
13813      *
13814      * @static
13815      * @memberOf _
13816      * @since 4.0.0
13817      * @category Object
13818      * @param {Object} object The object to modify.
13819      * @param {Array|string} path The path of the property to unset.
13820      * @returns {boolean} Returns `true` if the property is deleted, else `false`.
13821      * @example
13822      *
13823      * var object = { 'a': [{ 'b': { 'c': 7 } }] };
13824      * _.unset(object, 'a[0].b.c');
13825      * // => true
13826      *
13827      * console.log(object);
13828      * // => { 'a': [{ 'b': {} }] };
13829      *
13830      * _.unset(object, ['a', '0', 'b', 'c']);
13831      * // => true
13832      *
13833      * console.log(object);
13834      * // => { 'a': [{ 'b': {} }] };
13835      */
13836     function unset(object, path) {
13837       return object == null ? true : baseUnset(object, path);
13838     }
13839
13840     /**
13841      * This method is like `_.set` except that accepts `updater` to produce the
13842      * value to set. Use `_.updateWith` to customize `path` creation. The `updater`
13843      * is invoked with one argument: (value).
13844      *
13845      * **Note:** This method mutates `object`.
13846      *
13847      * @static
13848      * @memberOf _
13849      * @since 4.6.0
13850      * @category Object
13851      * @param {Object} object The object to modify.
13852      * @param {Array|string} path The path of the property to set.
13853      * @param {Function} updater The function to produce the updated value.
13854      * @returns {Object} Returns `object`.
13855      * @example
13856      *
13857      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13858      *
13859      * _.update(object, 'a[0].b.c', function(n) { return n * n; });
13860      * console.log(object.a[0].b.c);
13861      * // => 9
13862      *
13863      * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
13864      * console.log(object.x[0].y.z);
13865      * // => 0
13866      */
13867     function update(object, path, updater) {
13868       return object == null ? object : baseUpdate(object, path, castFunction(updater));
13869     }
13870
13871     /**
13872      * This method is like `_.update` except that it accepts `customizer` which is
13873      * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
13874      * path creation is handled by the method instead. The `customizer` is invoked
13875      * with three arguments: (nsValue, key, nsObject).
13876      *
13877      * **Note:** This method mutates `object`.
13878      *
13879      * @static
13880      * @memberOf _
13881      * @since 4.6.0
13882      * @category Object
13883      * @param {Object} object The object to modify.
13884      * @param {Array|string} path The path of the property to set.
13885      * @param {Function} updater The function to produce the updated value.
13886      * @param {Function} [customizer] The function to customize assigned values.
13887      * @returns {Object} Returns `object`.
13888      * @example
13889      *
13890      * var object = {};
13891      *
13892      * _.updateWith(object, '[0][1]', _.constant('a'), Object);
13893      * // => { '0': { '1': 'a' } }
13894      */
13895     function updateWith(object, path, updater, customizer) {
13896       customizer = typeof customizer == 'function' ? customizer : undefined;
13897       return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
13898     }
13899
13900     /**
13901      * Creates an array of the own enumerable string keyed property values of `object`.
13902      *
13903      * **Note:** Non-object values are coerced to objects.
13904      *
13905      * @static
13906      * @since 0.1.0
13907      * @memberOf _
13908      * @category Object
13909      * @param {Object} object The object to query.
13910      * @returns {Array} Returns the array of property values.
13911      * @example
13912      *
13913      * function Foo() {
13914      *   this.a = 1;
13915      *   this.b = 2;
13916      * }
13917      *
13918      * Foo.prototype.c = 3;
13919      *
13920      * _.values(new Foo);
13921      * // => [1, 2] (iteration order is not guaranteed)
13922      *
13923      * _.values('hi');
13924      * // => ['h', 'i']
13925      */
13926     function values(object) {
13927       return object == null ? [] : baseValues(object, keys(object));
13928     }
13929
13930     /**
13931      * Creates an array of the own and inherited enumerable string keyed property
13932      * values of `object`.
13933      *
13934      * **Note:** Non-object values are coerced to objects.
13935      *
13936      * @static
13937      * @memberOf _
13938      * @since 3.0.0
13939      * @category Object
13940      * @param {Object} object The object to query.
13941      * @returns {Array} Returns the array of property values.
13942      * @example
13943      *
13944      * function Foo() {
13945      *   this.a = 1;
13946      *   this.b = 2;
13947      * }
13948      *
13949      * Foo.prototype.c = 3;
13950      *
13951      * _.valuesIn(new Foo);
13952      * // => [1, 2, 3] (iteration order is not guaranteed)
13953      */
13954     function valuesIn(object) {
13955       return object == null ? [] : baseValues(object, keysIn(object));
13956     }
13957
13958     /*------------------------------------------------------------------------*/
13959
13960     /**
13961      * Clamps `number` within the inclusive `lower` and `upper` bounds.
13962      *
13963      * @static
13964      * @memberOf _
13965      * @since 4.0.0
13966      * @category Number
13967      * @param {number} number The number to clamp.
13968      * @param {number} [lower] The lower bound.
13969      * @param {number} upper The upper bound.
13970      * @returns {number} Returns the clamped number.
13971      * @example
13972      *
13973      * _.clamp(-10, -5, 5);
13974      * // => -5
13975      *
13976      * _.clamp(10, -5, 5);
13977      * // => 5
13978      */
13979     function clamp(number, lower, upper) {
13980       if (upper === undefined) {
13981         upper = lower;
13982         lower = undefined;
13983       }
13984       if (upper !== undefined) {
13985         upper = toNumber(upper);
13986         upper = upper === upper ? upper : 0;
13987       }
13988       if (lower !== undefined) {
13989         lower = toNumber(lower);
13990         lower = lower === lower ? lower : 0;
13991       }
13992       return baseClamp(toNumber(number), lower, upper);
13993     }
13994
13995     /**
13996      * Checks if `n` is between `start` and up to, but not including, `end`. If
13997      * `end` is not specified, it's set to `start` with `start` then set to `0`.
13998      * If `start` is greater than `end` the params are swapped to support
13999      * negative ranges.
14000      *
14001      * @static
14002      * @memberOf _
14003      * @since 3.3.0
14004      * @category Number
14005      * @param {number} number The number to check.
14006      * @param {number} [start=0] The start of the range.
14007      * @param {number} end The end of the range.
14008      * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
14009      * @see _.range, _.rangeRight
14010      * @example
14011      *
14012      * _.inRange(3, 2, 4);
14013      * // => true
14014      *
14015      * _.inRange(4, 8);
14016      * // => true
14017      *
14018      * _.inRange(4, 2);
14019      * // => false
14020      *
14021      * _.inRange(2, 2);
14022      * // => false
14023      *
14024      * _.inRange(1.2, 2);
14025      * // => true
14026      *
14027      * _.inRange(5.2, 4);
14028      * // => false
14029      *
14030      * _.inRange(-3, -2, -6);
14031      * // => true
14032      */
14033     function inRange(number, start, end) {
14034       start = toFinite(start);
14035       if (end === undefined) {
14036         end = start;
14037         start = 0;
14038       } else {
14039         end = toFinite(end);
14040       }
14041       number = toNumber(number);
14042       return baseInRange(number, start, end);
14043     }
14044
14045     /**
14046      * Produces a random number between the inclusive `lower` and `upper` bounds.
14047      * If only one argument is provided a number between `0` and the given number
14048      * is returned. If `floating` is `true`, or either `lower` or `upper` are
14049      * floats, a floating-point number is returned instead of an integer.
14050      *
14051      * **Note:** JavaScript follows the IEEE-754 standard for resolving
14052      * floating-point values which can produce unexpected results.
14053      *
14054      * @static
14055      * @memberOf _
14056      * @since 0.7.0
14057      * @category Number
14058      * @param {number} [lower=0] The lower bound.
14059      * @param {number} [upper=1] The upper bound.
14060      * @param {boolean} [floating] Specify returning a floating-point number.
14061      * @returns {number} Returns the random number.
14062      * @example
14063      *
14064      * _.random(0, 5);
14065      * // => an integer between 0 and 5
14066      *
14067      * _.random(5);
14068      * // => also an integer between 0 and 5
14069      *
14070      * _.random(5, true);
14071      * // => a floating-point number between 0 and 5
14072      *
14073      * _.random(1.2, 5.2);
14074      * // => a floating-point number between 1.2 and 5.2
14075      */
14076     function random(lower, upper, floating) {
14077       if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
14078         upper = floating = undefined;
14079       }
14080       if (floating === undefined) {
14081         if (typeof upper == 'boolean') {
14082           floating = upper;
14083           upper = undefined;
14084         }
14085         else if (typeof lower == 'boolean') {
14086           floating = lower;
14087           lower = undefined;
14088         }
14089       }
14090       if (lower === undefined && upper === undefined) {
14091         lower = 0;
14092         upper = 1;
14093       }
14094       else {
14095         lower = toFinite(lower);
14096         if (upper === undefined) {
14097           upper = lower;
14098           lower = 0;
14099         } else {
14100           upper = toFinite(upper);
14101         }
14102       }
14103       if (lower > upper) {
14104         var temp = lower;
14105         lower = upper;
14106         upper = temp;
14107       }
14108       if (floating || lower % 1 || upper % 1) {
14109         var rand = nativeRandom();
14110         return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);
14111       }
14112       return baseRandom(lower, upper);
14113     }
14114
14115     /*------------------------------------------------------------------------*/
14116
14117     /**
14118      * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
14119      *
14120      * @static
14121      * @memberOf _
14122      * @since 3.0.0
14123      * @category String
14124      * @param {string} [string=''] The string to convert.
14125      * @returns {string} Returns the camel cased string.
14126      * @example
14127      *
14128      * _.camelCase('Foo Bar');
14129      * // => 'fooBar'
14130      *
14131      * _.camelCase('--foo-bar--');
14132      * // => 'fooBar'
14133      *
14134      * _.camelCase('__FOO_BAR__');
14135      * // => 'fooBar'
14136      */
14137     var camelCase = createCompounder(function(result, word, index) {
14138       word = word.toLowerCase();
14139       return result + (index ? capitalize(word) : word);
14140     });
14141
14142     /**
14143      * Converts the first character of `string` to upper case and the remaining
14144      * to lower case.
14145      *
14146      * @static
14147      * @memberOf _
14148      * @since 3.0.0
14149      * @category String
14150      * @param {string} [string=''] The string to capitalize.
14151      * @returns {string} Returns the capitalized string.
14152      * @example
14153      *
14154      * _.capitalize('FRED');
14155      * // => 'Fred'
14156      */
14157     function capitalize(string) {
14158       return upperFirst(toString(string).toLowerCase());
14159     }
14160
14161     /**
14162      * Deburrs `string` by converting
14163      * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
14164      * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
14165      * letters to basic Latin letters and removing
14166      * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
14167      *
14168      * @static
14169      * @memberOf _
14170      * @since 3.0.0
14171      * @category String
14172      * @param {string} [string=''] The string to deburr.
14173      * @returns {string} Returns the deburred string.
14174      * @example
14175      *
14176      * _.deburr('déjà vu');
14177      * // => 'deja vu'
14178      */
14179     function deburr(string) {
14180       string = toString(string);
14181       return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
14182     }
14183
14184     /**
14185      * Checks if `string` ends with the given target string.
14186      *
14187      * @static
14188      * @memberOf _
14189      * @since 3.0.0
14190      * @category String
14191      * @param {string} [string=''] The string to inspect.
14192      * @param {string} [target] The string to search for.
14193      * @param {number} [position=string.length] The position to search up to.
14194      * @returns {boolean} Returns `true` if `string` ends with `target`,
14195      *  else `false`.
14196      * @example
14197      *
14198      * _.endsWith('abc', 'c');
14199      * // => true
14200      *
14201      * _.endsWith('abc', 'b');
14202      * // => false
14203      *
14204      * _.endsWith('abc', 'b', 2);
14205      * // => true
14206      */
14207     function endsWith(string, target, position) {
14208       string = toString(string);
14209       target = baseToString(target);
14210
14211       var length = string.length;
14212       position = position === undefined
14213         ? length
14214         : baseClamp(toInteger(position), 0, length);
14215
14216       var end = position;
14217       position -= target.length;
14218       return position >= 0 && string.slice(position, end) == target;
14219     }
14220
14221     /**
14222      * Converts the characters "&", "<", ">", '"', and "'" in `string` to their
14223      * corresponding HTML entities.
14224      *
14225      * **Note:** No other characters are escaped. To escape additional
14226      * characters use a third-party library like [_he_](https://mths.be/he).
14227      *
14228      * Though the ">" character is escaped for symmetry, characters like
14229      * ">" and "/" don't need escaping in HTML and have no special meaning
14230      * unless they're part of a tag or unquoted attribute value. See
14231      * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
14232      * (under "semi-related fun fact") for more details.
14233      *
14234      * When working with HTML you should always
14235      * [quote attribute values](http://wonko.com/post/html-escaping) to reduce
14236      * XSS vectors.
14237      *
14238      * @static
14239      * @since 0.1.0
14240      * @memberOf _
14241      * @category String
14242      * @param {string} [string=''] The string to escape.
14243      * @returns {string} Returns the escaped string.
14244      * @example
14245      *
14246      * _.escape('fred, barney, & pebbles');
14247      * // => 'fred, barney, &amp; pebbles'
14248      */
14249     function escape(string) {
14250       string = toString(string);
14251       return (string && reHasUnescapedHtml.test(string))
14252         ? string.replace(reUnescapedHtml, escapeHtmlChar)
14253         : string;
14254     }
14255
14256     /**
14257      * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
14258      * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
14259      *
14260      * @static
14261      * @memberOf _
14262      * @since 3.0.0
14263      * @category String
14264      * @param {string} [string=''] The string to escape.
14265      * @returns {string} Returns the escaped string.
14266      * @example
14267      *
14268      * _.escapeRegExp('[lodash](https://lodash.com/)');
14269      * // => '\[lodash\]\(https://lodash\.com/\)'
14270      */
14271     function escapeRegExp(string) {
14272       string = toString(string);
14273       return (string && reHasRegExpChar.test(string))
14274         ? string.replace(reRegExpChar, '\\$&')
14275         : string;
14276     }
14277
14278     /**
14279      * Converts `string` to
14280      * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
14281      *
14282      * @static
14283      * @memberOf _
14284      * @since 3.0.0
14285      * @category String
14286      * @param {string} [string=''] The string to convert.
14287      * @returns {string} Returns the kebab cased string.
14288      * @example
14289      *
14290      * _.kebabCase('Foo Bar');
14291      * // => 'foo-bar'
14292      *
14293      * _.kebabCase('fooBar');
14294      * // => 'foo-bar'
14295      *
14296      * _.kebabCase('__FOO_BAR__');
14297      * // => 'foo-bar'
14298      */
14299     var kebabCase = createCompounder(function(result, word, index) {
14300       return result + (index ? '-' : '') + word.toLowerCase();
14301     });
14302
14303     /**
14304      * Converts `string`, as space separated words, to lower case.
14305      *
14306      * @static
14307      * @memberOf _
14308      * @since 4.0.0
14309      * @category String
14310      * @param {string} [string=''] The string to convert.
14311      * @returns {string} Returns the lower cased string.
14312      * @example
14313      *
14314      * _.lowerCase('--Foo-Bar--');
14315      * // => 'foo bar'
14316      *
14317      * _.lowerCase('fooBar');
14318      * // => 'foo bar'
14319      *
14320      * _.lowerCase('__FOO_BAR__');
14321      * // => 'foo bar'
14322      */
14323     var lowerCase = createCompounder(function(result, word, index) {
14324       return result + (index ? ' ' : '') + word.toLowerCase();
14325     });
14326
14327     /**
14328      * Converts the first character of `string` to lower case.
14329      *
14330      * @static
14331      * @memberOf _
14332      * @since 4.0.0
14333      * @category String
14334      * @param {string} [string=''] The string to convert.
14335      * @returns {string} Returns the converted string.
14336      * @example
14337      *
14338      * _.lowerFirst('Fred');
14339      * // => 'fred'
14340      *
14341      * _.lowerFirst('FRED');
14342      * // => 'fRED'
14343      */
14344     var lowerFirst = createCaseFirst('toLowerCase');
14345
14346     /**
14347      * Pads `string` on the left and right sides if it's shorter than `length`.
14348      * Padding characters are truncated if they can't be evenly divided by `length`.
14349      *
14350      * @static
14351      * @memberOf _
14352      * @since 3.0.0
14353      * @category String
14354      * @param {string} [string=''] The string to pad.
14355      * @param {number} [length=0] The padding length.
14356      * @param {string} [chars=' '] The string used as padding.
14357      * @returns {string} Returns the padded string.
14358      * @example
14359      *
14360      * _.pad('abc', 8);
14361      * // => '  abc   '
14362      *
14363      * _.pad('abc', 8, '_-');
14364      * // => '_-abc_-_'
14365      *
14366      * _.pad('abc', 3);
14367      * // => 'abc'
14368      */
14369     function pad(string, length, chars) {
14370       string = toString(string);
14371       length = toInteger(length);
14372
14373       var strLength = length ? stringSize(string) : 0;
14374       if (!length || strLength >= length) {
14375         return string;
14376       }
14377       var mid = (length - strLength) / 2;
14378       return (
14379         createPadding(nativeFloor(mid), chars) +
14380         string +
14381         createPadding(nativeCeil(mid), chars)
14382       );
14383     }
14384
14385     /**
14386      * Pads `string` on the right side if it's shorter than `length`. Padding
14387      * characters are truncated if they exceed `length`.
14388      *
14389      * @static
14390      * @memberOf _
14391      * @since 4.0.0
14392      * @category String
14393      * @param {string} [string=''] The string to pad.
14394      * @param {number} [length=0] The padding length.
14395      * @param {string} [chars=' '] The string used as padding.
14396      * @returns {string} Returns the padded string.
14397      * @example
14398      *
14399      * _.padEnd('abc', 6);
14400      * // => 'abc   '
14401      *
14402      * _.padEnd('abc', 6, '_-');
14403      * // => 'abc_-_'
14404      *
14405      * _.padEnd('abc', 3);
14406      * // => 'abc'
14407      */
14408     function padEnd(string, length, chars) {
14409       string = toString(string);
14410       length = toInteger(length);
14411
14412       var strLength = length ? stringSize(string) : 0;
14413       return (length && strLength < length)
14414         ? (string + createPadding(length - strLength, chars))
14415         : string;
14416     }
14417
14418     /**
14419      * Pads `string` on the left side if it's shorter than `length`. Padding
14420      * characters are truncated if they exceed `length`.
14421      *
14422      * @static
14423      * @memberOf _
14424      * @since 4.0.0
14425      * @category String
14426      * @param {string} [string=''] The string to pad.
14427      * @param {number} [length=0] The padding length.
14428      * @param {string} [chars=' '] The string used as padding.
14429      * @returns {string} Returns the padded string.
14430      * @example
14431      *
14432      * _.padStart('abc', 6);
14433      * // => '   abc'
14434      *
14435      * _.padStart('abc', 6, '_-');
14436      * // => '_-_abc'
14437      *
14438      * _.padStart('abc', 3);
14439      * // => 'abc'
14440      */
14441     function padStart(string, length, chars) {
14442       string = toString(string);
14443       length = toInteger(length);
14444
14445       var strLength = length ? stringSize(string) : 0;
14446       return (length && strLength < length)
14447         ? (createPadding(length - strLength, chars) + string)
14448         : string;
14449     }
14450
14451     /**
14452      * Converts `string` to an integer of the specified radix. If `radix` is
14453      * `undefined` or `0`, a `radix` of `10` is used unless `value` is a
14454      * hexadecimal, in which case a `radix` of `16` is used.
14455      *
14456      * **Note:** This method aligns with the
14457      * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
14458      *
14459      * @static
14460      * @memberOf _
14461      * @since 1.1.0
14462      * @category String
14463      * @param {string} string The string to convert.
14464      * @param {number} [radix=10] The radix to interpret `value` by.
14465      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14466      * @returns {number} Returns the converted integer.
14467      * @example
14468      *
14469      * _.parseInt('08');
14470      * // => 8
14471      *
14472      * _.map(['6', '08', '10'], _.parseInt);
14473      * // => [6, 8, 10]
14474      */
14475     function parseInt(string, radix, guard) {
14476       if (guard || radix == null) {
14477         radix = 0;
14478       } else if (radix) {
14479         radix = +radix;
14480       }
14481       return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);
14482     }
14483
14484     /**
14485      * Repeats the given string `n` times.
14486      *
14487      * @static
14488      * @memberOf _
14489      * @since 3.0.0
14490      * @category String
14491      * @param {string} [string=''] The string to repeat.
14492      * @param {number} [n=1] The number of times to repeat the string.
14493      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14494      * @returns {string} Returns the repeated string.
14495      * @example
14496      *
14497      * _.repeat('*', 3);
14498      * // => '***'
14499      *
14500      * _.repeat('abc', 2);
14501      * // => 'abcabc'
14502      *
14503      * _.repeat('abc', 0);
14504      * // => ''
14505      */
14506     function repeat(string, n, guard) {
14507       if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {
14508         n = 1;
14509       } else {
14510         n = toInteger(n);
14511       }
14512       return baseRepeat(toString(string), n);
14513     }
14514
14515     /**
14516      * Replaces matches for `pattern` in `string` with `replacement`.
14517      *
14518      * **Note:** This method is based on
14519      * [`String#replace`](https://mdn.io/String/replace).
14520      *
14521      * @static
14522      * @memberOf _
14523      * @since 4.0.0
14524      * @category String
14525      * @param {string} [string=''] The string to modify.
14526      * @param {RegExp|string} pattern The pattern to replace.
14527      * @param {Function|string} replacement The match replacement.
14528      * @returns {string} Returns the modified string.
14529      * @example
14530      *
14531      * _.replace('Hi Fred', 'Fred', 'Barney');
14532      * // => 'Hi Barney'
14533      */
14534     function replace() {
14535       var args = arguments,
14536           string = toString(args[0]);
14537
14538       return args.length < 3 ? string : string.replace(args[1], args[2]);
14539     }
14540
14541     /**
14542      * Converts `string` to
14543      * [snake case](https://en.wikipedia.org/wiki/Snake_case).
14544      *
14545      * @static
14546      * @memberOf _
14547      * @since 3.0.0
14548      * @category String
14549      * @param {string} [string=''] The string to convert.
14550      * @returns {string} Returns the snake cased string.
14551      * @example
14552      *
14553      * _.snakeCase('Foo Bar');
14554      * // => 'foo_bar'
14555      *
14556      * _.snakeCase('fooBar');
14557      * // => 'foo_bar'
14558      *
14559      * _.snakeCase('--FOO-BAR--');
14560      * // => 'foo_bar'
14561      */
14562     var snakeCase = createCompounder(function(result, word, index) {
14563       return result + (index ? '_' : '') + word.toLowerCase();
14564     });
14565
14566     /**
14567      * Splits `string` by `separator`.
14568      *
14569      * **Note:** This method is based on
14570      * [`String#split`](https://mdn.io/String/split).
14571      *
14572      * @static
14573      * @memberOf _
14574      * @since 4.0.0
14575      * @category String
14576      * @param {string} [string=''] The string to split.
14577      * @param {RegExp|string} separator The separator pattern to split by.
14578      * @param {number} [limit] The length to truncate results to.
14579      * @returns {Array} Returns the string segments.
14580      * @example
14581      *
14582      * _.split('a-b-c', '-', 2);
14583      * // => ['a', 'b']
14584      */
14585     function split(string, separator, limit) {
14586       if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
14587         separator = limit = undefined;
14588       }
14589       limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
14590       if (!limit) {
14591         return [];
14592       }
14593       string = toString(string);
14594       if (string && (
14595             typeof separator == 'string' ||
14596             (separator != null && !isRegExp(separator))
14597           )) {
14598         separator = baseToString(separator);
14599         if (!separator && hasUnicode(string)) {
14600           return castSlice(stringToArray(string), 0, limit);
14601         }
14602       }
14603       return string.split(separator, limit);
14604     }
14605
14606     /**
14607      * Converts `string` to
14608      * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
14609      *
14610      * @static
14611      * @memberOf _
14612      * @since 3.1.0
14613      * @category String
14614      * @param {string} [string=''] The string to convert.
14615      * @returns {string} Returns the start cased string.
14616      * @example
14617      *
14618      * _.startCase('--foo-bar--');
14619      * // => 'Foo Bar'
14620      *
14621      * _.startCase('fooBar');
14622      * // => 'Foo Bar'
14623      *
14624      * _.startCase('__FOO_BAR__');
14625      * // => 'FOO BAR'
14626      */
14627     var startCase = createCompounder(function(result, word, index) {
14628       return result + (index ? ' ' : '') + upperFirst(word);
14629     });
14630
14631     /**
14632      * Checks if `string` starts with the given target string.
14633      *
14634      * @static
14635      * @memberOf _
14636      * @since 3.0.0
14637      * @category String
14638      * @param {string} [string=''] The string to inspect.
14639      * @param {string} [target] The string to search for.
14640      * @param {number} [position=0] The position to search from.
14641      * @returns {boolean} Returns `true` if `string` starts with `target`,
14642      *  else `false`.
14643      * @example
14644      *
14645      * _.startsWith('abc', 'a');
14646      * // => true
14647      *
14648      * _.startsWith('abc', 'b');
14649      * // => false
14650      *
14651      * _.startsWith('abc', 'b', 1);
14652      * // => true
14653      */
14654     function startsWith(string, target, position) {
14655       string = toString(string);
14656       position = position == null
14657         ? 0
14658         : baseClamp(toInteger(position), 0, string.length);
14659
14660       target = baseToString(target);
14661       return string.slice(position, position + target.length) == target;
14662     }
14663
14664     /**
14665      * Creates a compiled template function that can interpolate data properties
14666      * in "interpolate" delimiters, HTML-escape interpolated data properties in
14667      * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
14668      * properties may be accessed as free variables in the template. If a setting
14669      * object is given, it takes precedence over `_.templateSettings` values.
14670      *
14671      * **Note:** In the development build `_.template` utilizes
14672      * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
14673      * for easier debugging.
14674      *
14675      * For more information on precompiling templates see
14676      * [lodash's custom builds documentation](https://lodash.com/custom-builds).
14677      *
14678      * For more information on Chrome extension sandboxes see
14679      * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
14680      *
14681      * @static
14682      * @since 0.1.0
14683      * @memberOf _
14684      * @category String
14685      * @param {string} [string=''] The template string.
14686      * @param {Object} [options={}] The options object.
14687      * @param {RegExp} [options.escape=_.templateSettings.escape]
14688      *  The HTML "escape" delimiter.
14689      * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
14690      *  The "evaluate" delimiter.
14691      * @param {Object} [options.imports=_.templateSettings.imports]
14692      *  An object to import into the template as free variables.
14693      * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
14694      *  The "interpolate" delimiter.
14695      * @param {string} [options.sourceURL='lodash.templateSources[n]']
14696      *  The sourceURL of the compiled template.
14697      * @param {string} [options.variable='obj']
14698      *  The data object variable name.
14699      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14700      * @returns {Function} Returns the compiled template function.
14701      * @example
14702      *
14703      * // Use the "interpolate" delimiter to create a compiled template.
14704      * var compiled = _.template('hello <%= user %>!');
14705      * compiled({ 'user': 'fred' });
14706      * // => 'hello fred!'
14707      *
14708      * // Use the HTML "escape" delimiter to escape data property values.
14709      * var compiled = _.template('<b><%- value %></b>');
14710      * compiled({ 'value': '<script>' });
14711      * // => '<b>&lt;script&gt;</b>'
14712      *
14713      * // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
14714      * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
14715      * compiled({ 'users': ['fred', 'barney'] });
14716      * // => '<li>fred</li><li>barney</li>'
14717      *
14718      * // Use the internal `print` function in "evaluate" delimiters.
14719      * var compiled = _.template('<% print("hello " + user); %>!');
14720      * compiled({ 'user': 'barney' });
14721      * // => 'hello barney!'
14722      *
14723      * // Use the ES template literal delimiter as an "interpolate" delimiter.
14724      * // Disable support by replacing the "interpolate" delimiter.
14725      * var compiled = _.template('hello ${ user }!');
14726      * compiled({ 'user': 'pebbles' });
14727      * // => 'hello pebbles!'
14728      *
14729      * // Use backslashes to treat delimiters as plain text.
14730      * var compiled = _.template('<%= "\\<%- value %\\>" %>');
14731      * compiled({ 'value': 'ignored' });
14732      * // => '<%- value %>'
14733      *
14734      * // Use the `imports` option to import `jQuery` as `jq`.
14735      * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
14736      * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
14737      * compiled({ 'users': ['fred', 'barney'] });
14738      * // => '<li>fred</li><li>barney</li>'
14739      *
14740      * // Use the `sourceURL` option to specify a custom sourceURL for the template.
14741      * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
14742      * compiled(data);
14743      * // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
14744      *
14745      * // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
14746      * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
14747      * compiled.source;
14748      * // => function(data) {
14749      * //   var __t, __p = '';
14750      * //   __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
14751      * //   return __p;
14752      * // }
14753      *
14754      * // Use custom template delimiters.
14755      * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
14756      * var compiled = _.template('hello {{ user }}!');
14757      * compiled({ 'user': 'mustache' });
14758      * // => 'hello mustache!'
14759      *
14760      * // Use the `source` property to inline compiled templates for meaningful
14761      * // line numbers in error messages and stack traces.
14762      * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
14763      *   var JST = {\
14764      *     "main": ' + _.template(mainText).source + '\
14765      *   };\
14766      * ');
14767      */
14768     function template(string, options, guard) {
14769       // Based on John Resig's `tmpl` implementation
14770       // (http://ejohn.org/blog/javascript-micro-templating/)
14771       // and Laura Doktorova's doT.js (https://github.com/olado/doT).
14772       var settings = lodash.templateSettings;
14773
14774       if (guard && isIterateeCall(string, options, guard)) {
14775         options = undefined;
14776       }
14777       string = toString(string);
14778       options = assignInWith({}, options, settings, customDefaultsAssignIn);
14779
14780       var imports = assignInWith({}, options.imports, settings.imports, customDefaultsAssignIn),
14781           importsKeys = keys(imports),
14782           importsValues = baseValues(imports, importsKeys);
14783
14784       var isEscaping,
14785           isEvaluating,
14786           index = 0,
14787           interpolate = options.interpolate || reNoMatch,
14788           source = "__p += '";
14789
14790       // Compile the regexp to match each delimiter.
14791       var reDelimiters = RegExp(
14792         (options.escape || reNoMatch).source + '|' +
14793         interpolate.source + '|' +
14794         (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
14795         (options.evaluate || reNoMatch).source + '|$'
14796       , 'g');
14797
14798       // Use a sourceURL for easier debugging.
14799       var sourceURL = '//# sourceURL=' +
14800         ('sourceURL' in options
14801           ? options.sourceURL
14802           : ('lodash.templateSources[' + (++templateCounter) + ']')
14803         ) + '\n';
14804
14805       string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
14806         interpolateValue || (interpolateValue = esTemplateValue);
14807
14808         // Escape characters that can't be included in string literals.
14809         source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
14810
14811         // Replace delimiters with snippets.
14812         if (escapeValue) {
14813           isEscaping = true;
14814           source += "' +\n__e(" + escapeValue + ") +\n'";
14815         }
14816         if (evaluateValue) {
14817           isEvaluating = true;
14818           source += "';\n" + evaluateValue + ";\n__p += '";
14819         }
14820         if (interpolateValue) {
14821           source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
14822         }
14823         index = offset + match.length;
14824
14825         // The JS engine embedded in Adobe products needs `match` returned in
14826         // order to produce the correct `offset` value.
14827         return match;
14828       });
14829
14830       source += "';\n";
14831
14832       // If `variable` is not specified wrap a with-statement around the generated
14833       // code to add the data object to the top of the scope chain.
14834       var variable = options.variable;
14835       if (!variable) {
14836         source = 'with (obj) {\n' + source + '\n}\n';
14837       }
14838       // Cleanup code by stripping empty strings.
14839       source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
14840         .replace(reEmptyStringMiddle, '$1')
14841         .replace(reEmptyStringTrailing, '$1;');
14842
14843       // Frame code as the function body.
14844       source = 'function(' + (variable || 'obj') + ') {\n' +
14845         (variable
14846           ? ''
14847           : 'obj || (obj = {});\n'
14848         ) +
14849         "var __t, __p = ''" +
14850         (isEscaping
14851            ? ', __e = _.escape'
14852            : ''
14853         ) +
14854         (isEvaluating
14855           ? ', __j = Array.prototype.join;\n' +
14856             "function print() { __p += __j.call(arguments, '') }\n"
14857           : ';\n'
14858         ) +
14859         source +
14860         'return __p\n}';
14861
14862       var result = attempt(function() {
14863         return Function(importsKeys, sourceURL + 'return ' + source)
14864           .apply(undefined, importsValues);
14865       });
14866
14867       // Provide the compiled function's source by its `toString` method or
14868       // the `source` property as a convenience for inlining compiled templates.
14869       result.source = source;
14870       if (isError(result)) {
14871         throw result;
14872       }
14873       return result;
14874     }
14875
14876     /**
14877      * Converts `string`, as a whole, to lower case just like
14878      * [String#toLowerCase](https://mdn.io/toLowerCase).
14879      *
14880      * @static
14881      * @memberOf _
14882      * @since 4.0.0
14883      * @category String
14884      * @param {string} [string=''] The string to convert.
14885      * @returns {string} Returns the lower cased string.
14886      * @example
14887      *
14888      * _.toLower('--Foo-Bar--');
14889      * // => '--foo-bar--'
14890      *
14891      * _.toLower('fooBar');
14892      * // => 'foobar'
14893      *
14894      * _.toLower('__FOO_BAR__');
14895      * // => '__foo_bar__'
14896      */
14897     function toLower(value) {
14898       return toString(value).toLowerCase();
14899     }
14900
14901     /**
14902      * Converts `string`, as a whole, to upper case just like
14903      * [String#toUpperCase](https://mdn.io/toUpperCase).
14904      *
14905      * @static
14906      * @memberOf _
14907      * @since 4.0.0
14908      * @category String
14909      * @param {string} [string=''] The string to convert.
14910      * @returns {string} Returns the upper cased string.
14911      * @example
14912      *
14913      * _.toUpper('--foo-bar--');
14914      * // => '--FOO-BAR--'
14915      *
14916      * _.toUpper('fooBar');
14917      * // => 'FOOBAR'
14918      *
14919      * _.toUpper('__foo_bar__');
14920      * // => '__FOO_BAR__'
14921      */
14922     function toUpper(value) {
14923       return toString(value).toUpperCase();
14924     }
14925
14926     /**
14927      * Removes leading and trailing whitespace or specified characters from `string`.
14928      *
14929      * @static
14930      * @memberOf _
14931      * @since 3.0.0
14932      * @category String
14933      * @param {string} [string=''] The string to trim.
14934      * @param {string} [chars=whitespace] The characters to trim.
14935      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14936      * @returns {string} Returns the trimmed string.
14937      * @example
14938      *
14939      * _.trim('  abc  ');
14940      * // => 'abc'
14941      *
14942      * _.trim('-_-abc-_-', '_-');
14943      * // => 'abc'
14944      *
14945      * _.map(['  foo  ', '  bar  '], _.trim);
14946      * // => ['foo', 'bar']
14947      */
14948     function trim(string, chars, guard) {
14949       string = toString(string);
14950       if (string && (guard || chars === undefined)) {
14951         return string.replace(reTrim, '');
14952       }
14953       if (!string || !(chars = baseToString(chars))) {
14954         return string;
14955       }
14956       var strSymbols = stringToArray(string),
14957           chrSymbols = stringToArray(chars),
14958           start = charsStartIndex(strSymbols, chrSymbols),
14959           end = charsEndIndex(strSymbols, chrSymbols) + 1;
14960
14961       return castSlice(strSymbols, start, end).join('');
14962     }
14963
14964     /**
14965      * Removes trailing whitespace or specified characters from `string`.
14966      *
14967      * @static
14968      * @memberOf _
14969      * @since 4.0.0
14970      * @category String
14971      * @param {string} [string=''] The string to trim.
14972      * @param {string} [chars=whitespace] The characters to trim.
14973      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14974      * @returns {string} Returns the trimmed string.
14975      * @example
14976      *
14977      * _.trimEnd('  abc  ');
14978      * // => '  abc'
14979      *
14980      * _.trimEnd('-_-abc-_-', '_-');
14981      * // => '-_-abc'
14982      */
14983     function trimEnd(string, chars, guard) {
14984       string = toString(string);
14985       if (string && (guard || chars === undefined)) {
14986         return string.replace(reTrimEnd, '');
14987       }
14988       if (!string || !(chars = baseToString(chars))) {
14989         return string;
14990       }
14991       var strSymbols = stringToArray(string),
14992           end = charsEndIndex(strSymbols, stringToArray(chars)) + 1;
14993
14994       return castSlice(strSymbols, 0, end).join('');
14995     }
14996
14997     /**
14998      * Removes leading whitespace or specified characters from `string`.
14999      *
15000      * @static
15001      * @memberOf _
15002      * @since 4.0.0
15003      * @category String
15004      * @param {string} [string=''] The string to trim.
15005      * @param {string} [chars=whitespace] The characters to trim.
15006      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
15007      * @returns {string} Returns the trimmed string.
15008      * @example
15009      *
15010      * _.trimStart('  abc  ');
15011      * // => 'abc  '
15012      *
15013      * _.trimStart('-_-abc-_-', '_-');
15014      * // => 'abc-_-'
15015      */
15016     function trimStart(string, chars, guard) {
15017       string = toString(string);
15018       if (string && (guard || chars === undefined)) {
15019         return string.replace(reTrimStart, '');
15020       }
15021       if (!string || !(chars = baseToString(chars))) {
15022         return string;
15023       }
15024       var strSymbols = stringToArray(string),
15025           start = charsStartIndex(strSymbols, stringToArray(chars));
15026
15027       return castSlice(strSymbols, start).join('');
15028     }
15029
15030     /**
15031      * Truncates `string` if it's longer than the given maximum string length.
15032      * The last characters of the truncated string are replaced with the omission
15033      * string which defaults to "...".
15034      *
15035      * @static
15036      * @memberOf _
15037      * @since 4.0.0
15038      * @category String
15039      * @param {string} [string=''] The string to truncate.
15040      * @param {Object} [options={}] The options object.
15041      * @param {number} [options.length=30] The maximum string length.
15042      * @param {string} [options.omission='...'] The string to indicate text is omitted.
15043      * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
15044      * @returns {string} Returns the truncated string.
15045      * @example
15046      *
15047      * _.truncate('hi-diddly-ho there, neighborino');
15048      * // => 'hi-diddly-ho there, neighbo...'
15049      *
15050      * _.truncate('hi-diddly-ho there, neighborino', {
15051      *   'length': 24,
15052      *   'separator': ' '
15053      * });
15054      * // => 'hi-diddly-ho there,...'
15055      *
15056      * _.truncate('hi-diddly-ho there, neighborino', {
15057      *   'length': 24,
15058      *   'separator': /,? +/
15059      * });
15060      * // => 'hi-diddly-ho there...'
15061      *
15062      * _.truncate('hi-diddly-ho there, neighborino', {
15063      *   'omission': ' [...]'
15064      * });
15065      * // => 'hi-diddly-ho there, neig [...]'
15066      */
15067     function truncate(string, options) {
15068       var length = DEFAULT_TRUNC_LENGTH,
15069           omission = DEFAULT_TRUNC_OMISSION;
15070
15071       if (isObject(options)) {
15072         var separator = 'separator' in options ? options.separator : separator;
15073         length = 'length' in options ? toInteger(options.length) : length;
15074         omission = 'omission' in options ? baseToString(options.omission) : omission;
15075       }
15076       string = toString(string);
15077
15078       var strLength = string.length;
15079       if (hasUnicode(string)) {
15080         var strSymbols = stringToArray(string);
15081         strLength = strSymbols.length;
15082       }
15083       if (length >= strLength) {
15084         return string;
15085       }
15086       var end = length - stringSize(omission);
15087       if (end < 1) {
15088         return omission;
15089       }
15090       var result = strSymbols
15091         ? castSlice(strSymbols, 0, end).join('')
15092         : string.slice(0, end);
15093
15094       if (separator === undefined) {
15095         return result + omission;
15096       }
15097       if (strSymbols) {
15098         end += (result.length - end);
15099       }
15100       if (isRegExp(separator)) {
15101         if (string.slice(end).search(separator)) {
15102           var match,
15103               substring = result;
15104
15105           if (!separator.global) {
15106             separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
15107           }
15108           separator.lastIndex = 0;
15109           while ((match = separator.exec(substring))) {
15110             var newEnd = match.index;
15111           }
15112           result = result.slice(0, newEnd === undefined ? end : newEnd);
15113         }
15114       } else if (string.indexOf(baseToString(separator), end) != end) {
15115         var index = result.lastIndexOf(separator);
15116         if (index > -1) {
15117           result = result.slice(0, index);
15118         }
15119       }
15120       return result + omission;
15121     }
15122
15123     /**
15124      * The inverse of `_.escape`; this method converts the HTML entities
15125      * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to
15126      * their corresponding characters.
15127      *
15128      * **Note:** No other HTML entities are unescaped. To unescape additional
15129      * HTML entities use a third-party library like [_he_](https://mths.be/he).
15130      *
15131      * @static
15132      * @memberOf _
15133      * @since 0.6.0
15134      * @category String
15135      * @param {string} [string=''] The string to unescape.
15136      * @returns {string} Returns the unescaped string.
15137      * @example
15138      *
15139      * _.unescape('fred, barney, &amp; pebbles');
15140      * // => 'fred, barney, & pebbles'
15141      */
15142     function unescape(string) {
15143       string = toString(string);
15144       return (string && reHasEscapedHtml.test(string))
15145         ? string.replace(reEscapedHtml, unescapeHtmlChar)
15146         : string;
15147     }
15148
15149     /**
15150      * Converts `string`, as space separated words, to upper case.
15151      *
15152      * @static
15153      * @memberOf _
15154      * @since 4.0.0
15155      * @category String
15156      * @param {string} [string=''] The string to convert.
15157      * @returns {string} Returns the upper cased string.
15158      * @example
15159      *
15160      * _.upperCase('--foo-bar');
15161      * // => 'FOO BAR'
15162      *
15163      * _.upperCase('fooBar');
15164      * // => 'FOO BAR'
15165      *
15166      * _.upperCase('__foo_bar__');
15167      * // => 'FOO BAR'
15168      */
15169     var upperCase = createCompounder(function(result, word, index) {
15170       return result + (index ? ' ' : '') + word.toUpperCase();
15171     });
15172
15173     /**
15174      * Converts the first character of `string` to upper case.
15175      *
15176      * @static
15177      * @memberOf _
15178      * @since 4.0.0
15179      * @category String
15180      * @param {string} [string=''] The string to convert.
15181      * @returns {string} Returns the converted string.
15182      * @example
15183      *
15184      * _.upperFirst('fred');
15185      * // => 'Fred'
15186      *
15187      * _.upperFirst('FRED');
15188      * // => 'FRED'
15189      */
15190     var upperFirst = createCaseFirst('toUpperCase');
15191
15192     /**
15193      * Splits `string` into an array of its words.
15194      *
15195      * @static
15196      * @memberOf _
15197      * @since 3.0.0
15198      * @category String
15199      * @param {string} [string=''] The string to inspect.
15200      * @param {RegExp|string} [pattern] The pattern to match words.
15201      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
15202      * @returns {Array} Returns the words of `string`.
15203      * @example
15204      *
15205      * _.words('fred, barney, & pebbles');
15206      * // => ['fred', 'barney', 'pebbles']
15207      *
15208      * _.words('fred, barney, & pebbles', /[^, ]+/g);
15209      * // => ['fred', 'barney', '&', 'pebbles']
15210      */
15211     function words(string, pattern, guard) {
15212       string = toString(string);
15213       pattern = guard ? undefined : pattern;
15214
15215       if (pattern === undefined) {
15216         return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
15217       }
15218       return string.match(pattern) || [];
15219     }
15220
15221     /*------------------------------------------------------------------------*/
15222
15223     /**
15224      * Attempts to invoke `func`, returning either the result or the caught error
15225      * object. Any additional arguments are provided to `func` when it's invoked.
15226      *
15227      * @static
15228      * @memberOf _
15229      * @since 3.0.0
15230      * @category Util
15231      * @param {Function} func The function to attempt.
15232      * @param {...*} [args] The arguments to invoke `func` with.
15233      * @returns {*} Returns the `func` result or error object.
15234      * @example
15235      *
15236      * // Avoid throwing errors for invalid selectors.
15237      * var elements = _.attempt(function(selector) {
15238      *   return document.querySelectorAll(selector);
15239      * }, '>_>');
15240      *
15241      * if (_.isError(elements)) {
15242      *   elements = [];
15243      * }
15244      */
15245     var attempt = baseRest(function(func, args) {
15246       try {
15247         return apply(func, undefined, args);
15248       } catch (e) {
15249         return isError(e) ? e : new Error(e);
15250       }
15251     });
15252
15253     /**
15254      * Binds methods of an object to the object itself, overwriting the existing
15255      * method.
15256      *
15257      * **Note:** This method doesn't set the "length" property of bound functions.
15258      *
15259      * @static
15260      * @since 0.1.0
15261      * @memberOf _
15262      * @category Util
15263      * @param {Object} object The object to bind and assign the bound methods to.
15264      * @param {...(string|string[])} methodNames The object method names to bind.
15265      * @returns {Object} Returns `object`.
15266      * @example
15267      *
15268      * var view = {
15269      *   'label': 'docs',
15270      *   'click': function() {
15271      *     console.log('clicked ' + this.label);
15272      *   }
15273      * };
15274      *
15275      * _.bindAll(view, ['click']);
15276      * jQuery(element).on('click', view.click);
15277      * // => Logs 'clicked docs' when clicked.
15278      */
15279     var bindAll = flatRest(function(object, methodNames) {
15280       arrayEach(methodNames, function(key) {
15281         key = toKey(key);
15282         baseAssignValue(object, key, bind(object[key], object));
15283       });
15284       return object;
15285     });
15286
15287     /**
15288      * Creates a function that iterates over `pairs` and invokes the corresponding
15289      * function of the first predicate to return truthy. The predicate-function
15290      * pairs are invoked with the `this` binding and arguments of the created
15291      * function.
15292      *
15293      * @static
15294      * @memberOf _
15295      * @since 4.0.0
15296      * @category Util
15297      * @param {Array} pairs The predicate-function pairs.
15298      * @returns {Function} Returns the new composite function.
15299      * @example
15300      *
15301      * var func = _.cond([
15302      *   [_.matches({ 'a': 1 }),           _.constant('matches A')],
15303      *   [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
15304      *   [_.stubTrue,                      _.constant('no match')]
15305      * ]);
15306      *
15307      * func({ 'a': 1, 'b': 2 });
15308      * // => 'matches A'
15309      *
15310      * func({ 'a': 0, 'b': 1 });
15311      * // => 'matches B'
15312      *
15313      * func({ 'a': '1', 'b': '2' });
15314      * // => 'no match'
15315      */
15316     function cond(pairs) {
15317       var length = pairs == null ? 0 : pairs.length,
15318           toIteratee = getIteratee();
15319
15320       pairs = !length ? [] : arrayMap(pairs, function(pair) {
15321         if (typeof pair[1] != 'function') {
15322           throw new TypeError(FUNC_ERROR_TEXT);
15323         }
15324         return [toIteratee(pair[0]), pair[1]];
15325       });
15326
15327       return baseRest(function(args) {
15328         var index = -1;
15329         while (++index < length) {
15330           var pair = pairs[index];
15331           if (apply(pair[0], this, args)) {
15332             return apply(pair[1], this, args);
15333           }
15334         }
15335       });
15336     }
15337
15338     /**
15339      * Creates a function that invokes the predicate properties of `source` with
15340      * the corresponding property values of a given object, returning `true` if
15341      * all predicates return truthy, else `false`.
15342      *
15343      * **Note:** The created function is equivalent to `_.conformsTo` with
15344      * `source` partially applied.
15345      *
15346      * @static
15347      * @memberOf _
15348      * @since 4.0.0
15349      * @category Util
15350      * @param {Object} source The object of property predicates to conform to.
15351      * @returns {Function} Returns the new spec function.
15352      * @example
15353      *
15354      * var objects = [
15355      *   { 'a': 2, 'b': 1 },
15356      *   { 'a': 1, 'b': 2 }
15357      * ];
15358      *
15359      * _.filter(objects, _.conforms({ 'b': function(n) { return n > 1; } }));
15360      * // => [{ 'a': 1, 'b': 2 }]
15361      */
15362     function conforms(source) {
15363       return baseConforms(baseClone(source, CLONE_DEEP_FLAG));
15364     }
15365
15366     /**
15367      * Creates a function that returns `value`.
15368      *
15369      * @static
15370      * @memberOf _
15371      * @since 2.4.0
15372      * @category Util
15373      * @param {*} value The value to return from the new function.
15374      * @returns {Function} Returns the new constant function.
15375      * @example
15376      *
15377      * var objects = _.times(2, _.constant({ 'a': 1 }));
15378      *
15379      * console.log(objects);
15380      * // => [{ 'a': 1 }, { 'a': 1 }]
15381      *
15382      * console.log(objects[0] === objects[1]);
15383      * // => true
15384      */
15385     function constant(value) {
15386       return function() {
15387         return value;
15388       };
15389     }
15390
15391     /**
15392      * Checks `value` to determine whether a default value should be returned in
15393      * its place. The `defaultValue` is returned if `value` is `NaN`, `null`,
15394      * or `undefined`.
15395      *
15396      * @static
15397      * @memberOf _
15398      * @since 4.14.0
15399      * @category Util
15400      * @param {*} value The value to check.
15401      * @param {*} defaultValue The default value.
15402      * @returns {*} Returns the resolved value.
15403      * @example
15404      *
15405      * _.defaultTo(1, 10);
15406      * // => 1
15407      *
15408      * _.defaultTo(undefined, 10);
15409      * // => 10
15410      */
15411     function defaultTo(value, defaultValue) {
15412       return (value == null || value !== value) ? defaultValue : value;
15413     }
15414
15415     /**
15416      * Creates a function that returns the result of invoking the given functions
15417      * with the `this` binding of the created function, where each successive
15418      * invocation is supplied the return value of the previous.
15419      *
15420      * @static
15421      * @memberOf _
15422      * @since 3.0.0
15423      * @category Util
15424      * @param {...(Function|Function[])} [funcs] The functions to invoke.
15425      * @returns {Function} Returns the new composite function.
15426      * @see _.flowRight
15427      * @example
15428      *
15429      * function square(n) {
15430      *   return n * n;
15431      * }
15432      *
15433      * var addSquare = _.flow([_.add, square]);
15434      * addSquare(1, 2);
15435      * // => 9
15436      */
15437     var flow = createFlow();
15438
15439     /**
15440      * This method is like `_.flow` except that it creates a function that
15441      * invokes the given functions from right to left.
15442      *
15443      * @static
15444      * @since 3.0.0
15445      * @memberOf _
15446      * @category Util
15447      * @param {...(Function|Function[])} [funcs] The functions to invoke.
15448      * @returns {Function} Returns the new composite function.
15449      * @see _.flow
15450      * @example
15451      *
15452      * function square(n) {
15453      *   return n * n;
15454      * }
15455      *
15456      * var addSquare = _.flowRight([square, _.add]);
15457      * addSquare(1, 2);
15458      * // => 9
15459      */
15460     var flowRight = createFlow(true);
15461
15462     /**
15463      * This method returns the first argument it receives.
15464      *
15465      * @static
15466      * @since 0.1.0
15467      * @memberOf _
15468      * @category Util
15469      * @param {*} value Any value.
15470      * @returns {*} Returns `value`.
15471      * @example
15472      *
15473      * var object = { 'a': 1 };
15474      *
15475      * console.log(_.identity(object) === object);
15476      * // => true
15477      */
15478     function identity(value) {
15479       return value;
15480     }
15481
15482     /**
15483      * Creates a function that invokes `func` with the arguments of the created
15484      * function. If `func` is a property name, the created function returns the
15485      * property value for a given element. If `func` is an array or object, the
15486      * created function returns `true` for elements that contain the equivalent
15487      * source properties, otherwise it returns `false`.
15488      *
15489      * @static
15490      * @since 4.0.0
15491      * @memberOf _
15492      * @category Util
15493      * @param {*} [func=_.identity] The value to convert to a callback.
15494      * @returns {Function} Returns the callback.
15495      * @example
15496      *
15497      * var users = [
15498      *   { 'user': 'barney', 'age': 36, 'active': true },
15499      *   { 'user': 'fred',   'age': 40, 'active': false }
15500      * ];
15501      *
15502      * // The `_.matches` iteratee shorthand.
15503      * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
15504      * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
15505      *
15506      * // The `_.matchesProperty` iteratee shorthand.
15507      * _.filter(users, _.iteratee(['user', 'fred']));
15508      * // => [{ 'user': 'fred', 'age': 40 }]
15509      *
15510      * // The `_.property` iteratee shorthand.
15511      * _.map(users, _.iteratee('user'));
15512      * // => ['barney', 'fred']
15513      *
15514      * // Create custom iteratee shorthands.
15515      * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
15516      *   return !_.isRegExp(func) ? iteratee(func) : function(string) {
15517      *     return func.test(string);
15518      *   };
15519      * });
15520      *
15521      * _.filter(['abc', 'def'], /ef/);
15522      * // => ['def']
15523      */
15524     function iteratee(func) {
15525       return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG));
15526     }
15527
15528     /**
15529      * Creates a function that performs a partial deep comparison between a given
15530      * object and `source`, returning `true` if the given object has equivalent
15531      * property values, else `false`.
15532      *
15533      * **Note:** The created function is equivalent to `_.isMatch` with `source`
15534      * partially applied.
15535      *
15536      * Partial comparisons will match empty array and empty object `source`
15537      * values against any array or object value, respectively. See `_.isEqual`
15538      * for a list of supported value comparisons.
15539      *
15540      * @static
15541      * @memberOf _
15542      * @since 3.0.0
15543      * @category Util
15544      * @param {Object} source The object of property values to match.
15545      * @returns {Function} Returns the new spec function.
15546      * @example
15547      *
15548      * var objects = [
15549      *   { 'a': 1, 'b': 2, 'c': 3 },
15550      *   { 'a': 4, 'b': 5, 'c': 6 }
15551      * ];
15552      *
15553      * _.filter(objects, _.matches({ 'a': 4, 'c': 6 }));
15554      * // => [{ 'a': 4, 'b': 5, 'c': 6 }]
15555      */
15556     function matches(source) {
15557       return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
15558     }
15559
15560     /**
15561      * Creates a function that performs a partial deep comparison between the
15562      * value at `path` of a given object to `srcValue`, returning `true` if the
15563      * object value is equivalent, else `false`.
15564      *
15565      * **Note:** Partial comparisons will match empty array and empty object
15566      * `srcValue` values against any array or object value, respectively. See
15567      * `_.isEqual` for a list of supported value comparisons.
15568      *
15569      * @static
15570      * @memberOf _
15571      * @since 3.2.0
15572      * @category Util
15573      * @param {Array|string} path The path of the property to get.
15574      * @param {*} srcValue The value to match.
15575      * @returns {Function} Returns the new spec function.
15576      * @example
15577      *
15578      * var objects = [
15579      *   { 'a': 1, 'b': 2, 'c': 3 },
15580      *   { 'a': 4, 'b': 5, 'c': 6 }
15581      * ];
15582      *
15583      * _.find(objects, _.matchesProperty('a', 4));
15584      * // => { 'a': 4, 'b': 5, 'c': 6 }
15585      */
15586     function matchesProperty(path, srcValue) {
15587       return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG));
15588     }
15589
15590     /**
15591      * Creates a function that invokes the method at `path` of a given object.
15592      * Any additional arguments are provided to the invoked method.
15593      *
15594      * @static
15595      * @memberOf _
15596      * @since 3.7.0
15597      * @category Util
15598      * @param {Array|string} path The path of the method to invoke.
15599      * @param {...*} [args] The arguments to invoke the method with.
15600      * @returns {Function} Returns the new invoker function.
15601      * @example
15602      *
15603      * var objects = [
15604      *   { 'a': { 'b': _.constant(2) } },
15605      *   { 'a': { 'b': _.constant(1) } }
15606      * ];
15607      *
15608      * _.map(objects, _.method('a.b'));
15609      * // => [2, 1]
15610      *
15611      * _.map(objects, _.method(['a', 'b']));
15612      * // => [2, 1]
15613      */
15614     var method = baseRest(function(path, args) {
15615       return function(object) {
15616         return baseInvoke(object, path, args);
15617       };
15618     });
15619
15620     /**
15621      * The opposite of `_.method`; this method creates a function that invokes
15622      * the method at a given path of `object`. Any additional arguments are
15623      * provided to the invoked method.
15624      *
15625      * @static
15626      * @memberOf _
15627      * @since 3.7.0
15628      * @category Util
15629      * @param {Object} object The object to query.
15630      * @param {...*} [args] The arguments to invoke the method with.
15631      * @returns {Function} Returns the new invoker function.
15632      * @example
15633      *
15634      * var array = _.times(3, _.constant),
15635      *     object = { 'a': array, 'b': array, 'c': array };
15636      *
15637      * _.map(['a[2]', 'c[0]'], _.methodOf(object));
15638      * // => [2, 0]
15639      *
15640      * _.map([['a', '2'], ['c', '0']], _.methodOf(object));
15641      * // => [2, 0]
15642      */
15643     var methodOf = baseRest(function(object, args) {
15644       return function(path) {
15645         return baseInvoke(object, path, args);
15646       };
15647     });
15648
15649     /**
15650      * Adds all own enumerable string keyed function properties of a source
15651      * object to the destination object. If `object` is a function, then methods
15652      * are added to its prototype as well.
15653      *
15654      * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
15655      * avoid conflicts caused by modifying the original.
15656      *
15657      * @static
15658      * @since 0.1.0
15659      * @memberOf _
15660      * @category Util
15661      * @param {Function|Object} [object=lodash] The destination object.
15662      * @param {Object} source The object of functions to add.
15663      * @param {Object} [options={}] The options object.
15664      * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
15665      * @returns {Function|Object} Returns `object`.
15666      * @example
15667      *
15668      * function vowels(string) {
15669      *   return _.filter(string, function(v) {
15670      *     return /[aeiou]/i.test(v);
15671      *   });
15672      * }
15673      *
15674      * _.mixin({ 'vowels': vowels });
15675      * _.vowels('fred');
15676      * // => ['e']
15677      *
15678      * _('fred').vowels().value();
15679      * // => ['e']
15680      *
15681      * _.mixin({ 'vowels': vowels }, { 'chain': false });
15682      * _('fred').vowels();
15683      * // => ['e']
15684      */
15685     function mixin(object, source, options) {
15686       var props = keys(source),
15687           methodNames = baseFunctions(source, props);
15688
15689       if (options == null &&
15690           !(isObject(source) && (methodNames.length || !props.length))) {
15691         options = source;
15692         source = object;
15693         object = this;
15694         methodNames = baseFunctions(source, keys(source));
15695       }
15696       var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
15697           isFunc = isFunction(object);
15698
15699       arrayEach(methodNames, function(methodName) {
15700         var func = source[methodName];
15701         object[methodName] = func;
15702         if (isFunc) {
15703           object.prototype[methodName] = function() {
15704             var chainAll = this.__chain__;
15705             if (chain || chainAll) {
15706               var result = object(this.__wrapped__),
15707                   actions = result.__actions__ = copyArray(this.__actions__);
15708
15709               actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
15710               result.__chain__ = chainAll;
15711               return result;
15712             }
15713             return func.apply(object, arrayPush([this.value()], arguments));
15714           };
15715         }
15716       });
15717
15718       return object;
15719     }
15720
15721     /**
15722      * Reverts the `_` variable to its previous value and returns a reference to
15723      * the `lodash` function.
15724      *
15725      * @static
15726      * @since 0.1.0
15727      * @memberOf _
15728      * @category Util
15729      * @returns {Function} Returns the `lodash` function.
15730      * @example
15731      *
15732      * var lodash = _.noConflict();
15733      */
15734     function noConflict() {
15735       if (root._ === this) {
15736         root._ = oldDash;
15737       }
15738       return this;
15739     }
15740
15741     /**
15742      * This method returns `undefined`.
15743      *
15744      * @static
15745      * @memberOf _
15746      * @since 2.3.0
15747      * @category Util
15748      * @example
15749      *
15750      * _.times(2, _.noop);
15751      * // => [undefined, undefined]
15752      */
15753     function noop() {
15754       // No operation performed.
15755     }
15756
15757     /**
15758      * Creates a function that gets the argument at index `n`. If `n` is negative,
15759      * the nth argument from the end is returned.
15760      *
15761      * @static
15762      * @memberOf _
15763      * @since 4.0.0
15764      * @category Util
15765      * @param {number} [n=0] The index of the argument to return.
15766      * @returns {Function} Returns the new pass-thru function.
15767      * @example
15768      *
15769      * var func = _.nthArg(1);
15770      * func('a', 'b', 'c', 'd');
15771      * // => 'b'
15772      *
15773      * var func = _.nthArg(-2);
15774      * func('a', 'b', 'c', 'd');
15775      * // => 'c'
15776      */
15777     function nthArg(n) {
15778       n = toInteger(n);
15779       return baseRest(function(args) {
15780         return baseNth(args, n);
15781       });
15782     }
15783
15784     /**
15785      * Creates a function that invokes `iteratees` with the arguments it receives
15786      * and returns their results.
15787      *
15788      * @static
15789      * @memberOf _
15790      * @since 4.0.0
15791      * @category Util
15792      * @param {...(Function|Function[])} [iteratees=[_.identity]]
15793      *  The iteratees to invoke.
15794      * @returns {Function} Returns the new function.
15795      * @example
15796      *
15797      * var func = _.over([Math.max, Math.min]);
15798      *
15799      * func(1, 2, 3, 4);
15800      * // => [4, 1]
15801      */
15802     var over = createOver(arrayMap);
15803
15804     /**
15805      * Creates a function that checks if **all** of the `predicates` return
15806      * truthy when invoked with the arguments it receives.
15807      *
15808      * @static
15809      * @memberOf _
15810      * @since 4.0.0
15811      * @category Util
15812      * @param {...(Function|Function[])} [predicates=[_.identity]]
15813      *  The predicates to check.
15814      * @returns {Function} Returns the new function.
15815      * @example
15816      *
15817      * var func = _.overEvery([Boolean, isFinite]);
15818      *
15819      * func('1');
15820      * // => true
15821      *
15822      * func(null);
15823      * // => false
15824      *
15825      * func(NaN);
15826      * // => false
15827      */
15828     var overEvery = createOver(arrayEvery);
15829
15830     /**
15831      * Creates a function that checks if **any** of the `predicates` return
15832      * truthy when invoked with the arguments it receives.
15833      *
15834      * @static
15835      * @memberOf _
15836      * @since 4.0.0
15837      * @category Util
15838      * @param {...(Function|Function[])} [predicates=[_.identity]]
15839      *  The predicates to check.
15840      * @returns {Function} Returns the new function.
15841      * @example
15842      *
15843      * var func = _.overSome([Boolean, isFinite]);
15844      *
15845      * func('1');
15846      * // => true
15847      *
15848      * func(null);
15849      * // => true
15850      *
15851      * func(NaN);
15852      * // => false
15853      */
15854     var overSome = createOver(arraySome);
15855
15856     /**
15857      * Creates a function that returns the value at `path` of a given object.
15858      *
15859      * @static
15860      * @memberOf _
15861      * @since 2.4.0
15862      * @category Util
15863      * @param {Array|string} path The path of the property to get.
15864      * @returns {Function} Returns the new accessor function.
15865      * @example
15866      *
15867      * var objects = [
15868      *   { 'a': { 'b': 2 } },
15869      *   { 'a': { 'b': 1 } }
15870      * ];
15871      *
15872      * _.map(objects, _.property('a.b'));
15873      * // => [2, 1]
15874      *
15875      * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
15876      * // => [1, 2]
15877      */
15878     function property(path) {
15879       return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
15880     }
15881
15882     /**
15883      * The opposite of `_.property`; this method creates a function that returns
15884      * the value at a given path of `object`.
15885      *
15886      * @static
15887      * @memberOf _
15888      * @since 3.0.0
15889      * @category Util
15890      * @param {Object} object The object to query.
15891      * @returns {Function} Returns the new accessor function.
15892      * @example
15893      *
15894      * var array = [0, 1, 2],
15895      *     object = { 'a': array, 'b': array, 'c': array };
15896      *
15897      * _.map(['a[2]', 'c[0]'], _.propertyOf(object));
15898      * // => [2, 0]
15899      *
15900      * _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
15901      * // => [2, 0]
15902      */
15903     function propertyOf(object) {
15904       return function(path) {
15905         return object == null ? undefined : baseGet(object, path);
15906       };
15907     }
15908
15909     /**
15910      * Creates an array of numbers (positive and/or negative) progressing from
15911      * `start` up to, but not including, `end`. A step of `-1` is used if a negative
15912      * `start` is specified without an `end` or `step`. If `end` is not specified,
15913      * it's set to `start` with `start` then set to `0`.
15914      *
15915      * **Note:** JavaScript follows the IEEE-754 standard for resolving
15916      * floating-point values which can produce unexpected results.
15917      *
15918      * @static
15919      * @since 0.1.0
15920      * @memberOf _
15921      * @category Util
15922      * @param {number} [start=0] The start of the range.
15923      * @param {number} end The end of the range.
15924      * @param {number} [step=1] The value to increment or decrement by.
15925      * @returns {Array} Returns the range of numbers.
15926      * @see _.inRange, _.rangeRight
15927      * @example
15928      *
15929      * _.range(4);
15930      * // => [0, 1, 2, 3]
15931      *
15932      * _.range(-4);
15933      * // => [0, -1, -2, -3]
15934      *
15935      * _.range(1, 5);
15936      * // => [1, 2, 3, 4]
15937      *
15938      * _.range(0, 20, 5);
15939      * // => [0, 5, 10, 15]
15940      *
15941      * _.range(0, -4, -1);
15942      * // => [0, -1, -2, -3]
15943      *
15944      * _.range(1, 4, 0);
15945      * // => [1, 1, 1]
15946      *
15947      * _.range(0);
15948      * // => []
15949      */
15950     var range = createRange();
15951
15952     /**
15953      * This method is like `_.range` except that it populates values in
15954      * descending order.
15955      *
15956      * @static
15957      * @memberOf _
15958      * @since 4.0.0
15959      * @category Util
15960      * @param {number} [start=0] The start of the range.
15961      * @param {number} end The end of the range.
15962      * @param {number} [step=1] The value to increment or decrement by.
15963      * @returns {Array} Returns the range of numbers.
15964      * @see _.inRange, _.range
15965      * @example
15966      *
15967      * _.rangeRight(4);
15968      * // => [3, 2, 1, 0]
15969      *
15970      * _.rangeRight(-4);
15971      * // => [-3, -2, -1, 0]
15972      *
15973      * _.rangeRight(1, 5);
15974      * // => [4, 3, 2, 1]
15975      *
15976      * _.rangeRight(0, 20, 5);
15977      * // => [15, 10, 5, 0]
15978      *
15979      * _.rangeRight(0, -4, -1);
15980      * // => [-3, -2, -1, 0]
15981      *
15982      * _.rangeRight(1, 4, 0);
15983      * // => [1, 1, 1]
15984      *
15985      * _.rangeRight(0);
15986      * // => []
15987      */
15988     var rangeRight = createRange(true);
15989
15990     /**
15991      * This method returns a new empty array.
15992      *
15993      * @static
15994      * @memberOf _
15995      * @since 4.13.0
15996      * @category Util
15997      * @returns {Array} Returns the new empty array.
15998      * @example
15999      *
16000      * var arrays = _.times(2, _.stubArray);
16001      *
16002      * console.log(arrays);
16003      * // => [[], []]
16004      *
16005      * console.log(arrays[0] === arrays[1]);
16006      * // => false
16007      */
16008     function stubArray() {
16009       return [];
16010     }
16011
16012     /**
16013      * This method returns `false`.
16014      *
16015      * @static
16016      * @memberOf _
16017      * @since 4.13.0
16018      * @category Util
16019      * @returns {boolean} Returns `false`.
16020      * @example
16021      *
16022      * _.times(2, _.stubFalse);
16023      * // => [false, false]
16024      */
16025     function stubFalse() {
16026       return false;
16027     }
16028
16029     /**
16030      * This method returns a new empty object.
16031      *
16032      * @static
16033      * @memberOf _
16034      * @since 4.13.0
16035      * @category Util
16036      * @returns {Object} Returns the new empty object.
16037      * @example
16038      *
16039      * var objects = _.times(2, _.stubObject);
16040      *
16041      * console.log(objects);
16042      * // => [{}, {}]
16043      *
16044      * console.log(objects[0] === objects[1]);
16045      * // => false
16046      */
16047     function stubObject() {
16048       return {};
16049     }
16050
16051     /**
16052      * This method returns an empty string.
16053      *
16054      * @static
16055      * @memberOf _
16056      * @since 4.13.0
16057      * @category Util
16058      * @returns {string} Returns the empty string.
16059      * @example
16060      *
16061      * _.times(2, _.stubString);
16062      * // => ['', '']
16063      */
16064     function stubString() {
16065       return '';
16066     }
16067
16068     /**
16069      * This method returns `true`.
16070      *
16071      * @static
16072      * @memberOf _
16073      * @since 4.13.0
16074      * @category Util
16075      * @returns {boolean} Returns `true`.
16076      * @example
16077      *
16078      * _.times(2, _.stubTrue);
16079      * // => [true, true]
16080      */
16081     function stubTrue() {
16082       return true;
16083     }
16084
16085     /**
16086      * Invokes the iteratee `n` times, returning an array of the results of
16087      * each invocation. The iteratee is invoked with one argument; (index).
16088      *
16089      * @static
16090      * @since 0.1.0
16091      * @memberOf _
16092      * @category Util
16093      * @param {number} n The number of times to invoke `iteratee`.
16094      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
16095      * @returns {Array} Returns the array of results.
16096      * @example
16097      *
16098      * _.times(3, String);
16099      * // => ['0', '1', '2']
16100      *
16101      *  _.times(4, _.constant(0));
16102      * // => [0, 0, 0, 0]
16103      */
16104     function times(n, iteratee) {
16105       n = toInteger(n);
16106       if (n < 1 || n > MAX_SAFE_INTEGER) {
16107         return [];
16108       }
16109       var index = MAX_ARRAY_LENGTH,
16110           length = nativeMin(n, MAX_ARRAY_LENGTH);
16111
16112       iteratee = getIteratee(iteratee);
16113       n -= MAX_ARRAY_LENGTH;
16114
16115       var result = baseTimes(length, iteratee);
16116       while (++index < n) {
16117         iteratee(index);
16118       }
16119       return result;
16120     }
16121
16122     /**
16123      * Converts `value` to a property path array.
16124      *
16125      * @static
16126      * @memberOf _
16127      * @since 4.0.0
16128      * @category Util
16129      * @param {*} value The value to convert.
16130      * @returns {Array} Returns the new property path array.
16131      * @example
16132      *
16133      * _.toPath('a.b.c');
16134      * // => ['a', 'b', 'c']
16135      *
16136      * _.toPath('a[0].b.c');
16137      * // => ['a', '0', 'b', 'c']
16138      */
16139     function toPath(value) {
16140       if (isArray(value)) {
16141         return arrayMap(value, toKey);
16142       }
16143       return isSymbol(value) ? [value] : copyArray(stringToPath(toString(value)));
16144     }
16145
16146     /**
16147      * Generates a unique ID. If `prefix` is given, the ID is appended to it.
16148      *
16149      * @static
16150      * @since 0.1.0
16151      * @memberOf _
16152      * @category Util
16153      * @param {string} [prefix=''] The value to prefix the ID with.
16154      * @returns {string} Returns the unique ID.
16155      * @example
16156      *
16157      * _.uniqueId('contact_');
16158      * // => 'contact_104'
16159      *
16160      * _.uniqueId();
16161      * // => '105'
16162      */
16163     function uniqueId(prefix) {
16164       var id = ++idCounter;
16165       return toString(prefix) + id;
16166     }
16167
16168     /*------------------------------------------------------------------------*/
16169
16170     /**
16171      * Adds two numbers.
16172      *
16173      * @static
16174      * @memberOf _
16175      * @since 3.4.0
16176      * @category Math
16177      * @param {number} augend The first number in an addition.
16178      * @param {number} addend The second number in an addition.
16179      * @returns {number} Returns the total.
16180      * @example
16181      *
16182      * _.add(6, 4);
16183      * // => 10
16184      */
16185     var add = createMathOperation(function(augend, addend) {
16186       return augend + addend;
16187     }, 0);
16188
16189     /**
16190      * Computes `number` rounded up to `precision`.
16191      *
16192      * @static
16193      * @memberOf _
16194      * @since 3.10.0
16195      * @category Math
16196      * @param {number} number The number to round up.
16197      * @param {number} [precision=0] The precision to round up to.
16198      * @returns {number} Returns the rounded up number.
16199      * @example
16200      *
16201      * _.ceil(4.006);
16202      * // => 5
16203      *
16204      * _.ceil(6.004, 2);
16205      * // => 6.01
16206      *
16207      * _.ceil(6040, -2);
16208      * // => 6100
16209      */
16210     var ceil = createRound('ceil');
16211
16212     /**
16213      * Divide two numbers.
16214      *
16215      * @static
16216      * @memberOf _
16217      * @since 4.7.0
16218      * @category Math
16219      * @param {number} dividend The first number in a division.
16220      * @param {number} divisor The second number in a division.
16221      * @returns {number} Returns the quotient.
16222      * @example
16223      *
16224      * _.divide(6, 4);
16225      * // => 1.5
16226      */
16227     var divide = createMathOperation(function(dividend, divisor) {
16228       return dividend / divisor;
16229     }, 1);
16230
16231     /**
16232      * Computes `number` rounded down to `precision`.
16233      *
16234      * @static
16235      * @memberOf _
16236      * @since 3.10.0
16237      * @category Math
16238      * @param {number} number The number to round down.
16239      * @param {number} [precision=0] The precision to round down to.
16240      * @returns {number} Returns the rounded down number.
16241      * @example
16242      *
16243      * _.floor(4.006);
16244      * // => 4
16245      *
16246      * _.floor(0.046, 2);
16247      * // => 0.04
16248      *
16249      * _.floor(4060, -2);
16250      * // => 4000
16251      */
16252     var floor = createRound('floor');
16253
16254     /**
16255      * Computes the maximum value of `array`. If `array` is empty or falsey,
16256      * `undefined` is returned.
16257      *
16258      * @static
16259      * @since 0.1.0
16260      * @memberOf _
16261      * @category Math
16262      * @param {Array} array The array to iterate over.
16263      * @returns {*} Returns the maximum value.
16264      * @example
16265      *
16266      * _.max([4, 2, 8, 6]);
16267      * // => 8
16268      *
16269      * _.max([]);
16270      * // => undefined
16271      */
16272     function max(array) {
16273       return (array && array.length)
16274         ? baseExtremum(array, identity, baseGt)
16275         : undefined;
16276     }
16277
16278     /**
16279      * This method is like `_.max` except that it accepts `iteratee` which is
16280      * invoked for each element in `array` to generate the criterion by which
16281      * the value is ranked. The iteratee is invoked with one argument: (value).
16282      *
16283      * @static
16284      * @memberOf _
16285      * @since 4.0.0
16286      * @category Math
16287      * @param {Array} array The array to iterate over.
16288      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16289      * @returns {*} Returns the maximum value.
16290      * @example
16291      *
16292      * var objects = [{ 'n': 1 }, { 'n': 2 }];
16293      *
16294      * _.maxBy(objects, function(o) { return o.n; });
16295      * // => { 'n': 2 }
16296      *
16297      * // The `_.property` iteratee shorthand.
16298      * _.maxBy(objects, 'n');
16299      * // => { 'n': 2 }
16300      */
16301     function maxBy(array, iteratee) {
16302       return (array && array.length)
16303         ? baseExtremum(array, getIteratee(iteratee, 2), baseGt)
16304         : undefined;
16305     }
16306
16307     /**
16308      * Computes the mean of the values in `array`.
16309      *
16310      * @static
16311      * @memberOf _
16312      * @since 4.0.0
16313      * @category Math
16314      * @param {Array} array The array to iterate over.
16315      * @returns {number} Returns the mean.
16316      * @example
16317      *
16318      * _.mean([4, 2, 8, 6]);
16319      * // => 5
16320      */
16321     function mean(array) {
16322       return baseMean(array, identity);
16323     }
16324
16325     /**
16326      * This method is like `_.mean` except that it accepts `iteratee` which is
16327      * invoked for each element in `array` to generate the value to be averaged.
16328      * The iteratee is invoked with one argument: (value).
16329      *
16330      * @static
16331      * @memberOf _
16332      * @since 4.7.0
16333      * @category Math
16334      * @param {Array} array The array to iterate over.
16335      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16336      * @returns {number} Returns the mean.
16337      * @example
16338      *
16339      * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
16340      *
16341      * _.meanBy(objects, function(o) { return o.n; });
16342      * // => 5
16343      *
16344      * // The `_.property` iteratee shorthand.
16345      * _.meanBy(objects, 'n');
16346      * // => 5
16347      */
16348     function meanBy(array, iteratee) {
16349       return baseMean(array, getIteratee(iteratee, 2));
16350     }
16351
16352     /**
16353      * Computes the minimum value of `array`. If `array` is empty or falsey,
16354      * `undefined` is returned.
16355      *
16356      * @static
16357      * @since 0.1.0
16358      * @memberOf _
16359      * @category Math
16360      * @param {Array} array The array to iterate over.
16361      * @returns {*} Returns the minimum value.
16362      * @example
16363      *
16364      * _.min([4, 2, 8, 6]);
16365      * // => 2
16366      *
16367      * _.min([]);
16368      * // => undefined
16369      */
16370     function min(array) {
16371       return (array && array.length)
16372         ? baseExtremum(array, identity, baseLt)
16373         : undefined;
16374     }
16375
16376     /**
16377      * This method is like `_.min` except that it accepts `iteratee` which is
16378      * invoked for each element in `array` to generate the criterion by which
16379      * the value is ranked. The iteratee is invoked with one argument: (value).
16380      *
16381      * @static
16382      * @memberOf _
16383      * @since 4.0.0
16384      * @category Math
16385      * @param {Array} array The array to iterate over.
16386      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16387      * @returns {*} Returns the minimum value.
16388      * @example
16389      *
16390      * var objects = [{ 'n': 1 }, { 'n': 2 }];
16391      *
16392      * _.minBy(objects, function(o) { return o.n; });
16393      * // => { 'n': 1 }
16394      *
16395      * // The `_.property` iteratee shorthand.
16396      * _.minBy(objects, 'n');
16397      * // => { 'n': 1 }
16398      */
16399     function minBy(array, iteratee) {
16400       return (array && array.length)
16401         ? baseExtremum(array, getIteratee(iteratee, 2), baseLt)
16402         : undefined;
16403     }
16404
16405     /**
16406      * Multiply two numbers.
16407      *
16408      * @static
16409      * @memberOf _
16410      * @since 4.7.0
16411      * @category Math
16412      * @param {number} multiplier The first number in a multiplication.
16413      * @param {number} multiplicand The second number in a multiplication.
16414      * @returns {number} Returns the product.
16415      * @example
16416      *
16417      * _.multiply(6, 4);
16418      * // => 24
16419      */
16420     var multiply = createMathOperation(function(multiplier, multiplicand) {
16421       return multiplier * multiplicand;
16422     }, 1);
16423
16424     /**
16425      * Computes `number` rounded to `precision`.
16426      *
16427      * @static
16428      * @memberOf _
16429      * @since 3.10.0
16430      * @category Math
16431      * @param {number} number The number to round.
16432      * @param {number} [precision=0] The precision to round to.
16433      * @returns {number} Returns the rounded number.
16434      * @example
16435      *
16436      * _.round(4.006);
16437      * // => 4
16438      *
16439      * _.round(4.006, 2);
16440      * // => 4.01
16441      *
16442      * _.round(4060, -2);
16443      * // => 4100
16444      */
16445     var round = createRound('round');
16446
16447     /**
16448      * Subtract two numbers.
16449      *
16450      * @static
16451      * @memberOf _
16452      * @since 4.0.0
16453      * @category Math
16454      * @param {number} minuend The first number in a subtraction.
16455      * @param {number} subtrahend The second number in a subtraction.
16456      * @returns {number} Returns the difference.
16457      * @example
16458      *
16459      * _.subtract(6, 4);
16460      * // => 2
16461      */
16462     var subtract = createMathOperation(function(minuend, subtrahend) {
16463       return minuend - subtrahend;
16464     }, 0);
16465
16466     /**
16467      * Computes the sum of the values in `array`.
16468      *
16469      * @static
16470      * @memberOf _
16471      * @since 3.4.0
16472      * @category Math
16473      * @param {Array} array The array to iterate over.
16474      * @returns {number} Returns the sum.
16475      * @example
16476      *
16477      * _.sum([4, 2, 8, 6]);
16478      * // => 20
16479      */
16480     function sum(array) {
16481       return (array && array.length)
16482         ? baseSum(array, identity)
16483         : 0;
16484     }
16485
16486     /**
16487      * This method is like `_.sum` except that it accepts `iteratee` which is
16488      * invoked for each element in `array` to generate the value to be summed.
16489      * The iteratee is invoked with one argument: (value).
16490      *
16491      * @static
16492      * @memberOf _
16493      * @since 4.0.0
16494      * @category Math
16495      * @param {Array} array The array to iterate over.
16496      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16497      * @returns {number} Returns the sum.
16498      * @example
16499      *
16500      * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
16501      *
16502      * _.sumBy(objects, function(o) { return o.n; });
16503      * // => 20
16504      *
16505      * // The `_.property` iteratee shorthand.
16506      * _.sumBy(objects, 'n');
16507      * // => 20
16508      */
16509     function sumBy(array, iteratee) {
16510       return (array && array.length)
16511         ? baseSum(array, getIteratee(iteratee, 2))
16512         : 0;
16513     }
16514
16515     /*------------------------------------------------------------------------*/
16516
16517     // Add methods that return wrapped values in chain sequences.
16518     lodash.after = after;
16519     lodash.ary = ary;
16520     lodash.assign = assign;
16521     lodash.assignIn = assignIn;
16522     lodash.assignInWith = assignInWith;
16523     lodash.assignWith = assignWith;
16524     lodash.at = at;
16525     lodash.before = before;
16526     lodash.bind = bind;
16527     lodash.bindAll = bindAll;
16528     lodash.bindKey = bindKey;
16529     lodash.castArray = castArray;
16530     lodash.chain = chain;
16531     lodash.chunk = chunk;
16532     lodash.compact = compact;
16533     lodash.concat = concat;
16534     lodash.cond = cond;
16535     lodash.conforms = conforms;
16536     lodash.constant = constant;
16537     lodash.countBy = countBy;
16538     lodash.create = create;
16539     lodash.curry = curry;
16540     lodash.curryRight = curryRight;
16541     lodash.debounce = debounce;
16542     lodash.defaults = defaults;
16543     lodash.defaultsDeep = defaultsDeep;
16544     lodash.defer = defer;
16545     lodash.delay = delay;
16546     lodash.difference = difference;
16547     lodash.differenceBy = differenceBy;
16548     lodash.differenceWith = differenceWith;
16549     lodash.drop = drop;
16550     lodash.dropRight = dropRight;
16551     lodash.dropRightWhile = dropRightWhile;
16552     lodash.dropWhile = dropWhile;
16553     lodash.fill = fill;
16554     lodash.filter = filter;
16555     lodash.flatMap = flatMap;
16556     lodash.flatMapDeep = flatMapDeep;
16557     lodash.flatMapDepth = flatMapDepth;
16558     lodash.flatten = flatten;
16559     lodash.flattenDeep = flattenDeep;
16560     lodash.flattenDepth = flattenDepth;
16561     lodash.flip = flip;
16562     lodash.flow = flow;
16563     lodash.flowRight = flowRight;
16564     lodash.fromPairs = fromPairs;
16565     lodash.functions = functions;
16566     lodash.functionsIn = functionsIn;
16567     lodash.groupBy = groupBy;
16568     lodash.initial = initial;
16569     lodash.intersection = intersection;
16570     lodash.intersectionBy = intersectionBy;
16571     lodash.intersectionWith = intersectionWith;
16572     lodash.invert = invert;
16573     lodash.invertBy = invertBy;
16574     lodash.invokeMap = invokeMap;
16575     lodash.iteratee = iteratee;
16576     lodash.keyBy = keyBy;
16577     lodash.keys = keys;
16578     lodash.keysIn = keysIn;
16579     lodash.map = map;
16580     lodash.mapKeys = mapKeys;
16581     lodash.mapValues = mapValues;
16582     lodash.matches = matches;
16583     lodash.matchesProperty = matchesProperty;
16584     lodash.memoize = memoize;
16585     lodash.merge = merge;
16586     lodash.mergeWith = mergeWith;
16587     lodash.method = method;
16588     lodash.methodOf = methodOf;
16589     lodash.mixin = mixin;
16590     lodash.negate = negate;
16591     lodash.nthArg = nthArg;
16592     lodash.omit = omit;
16593     lodash.omitBy = omitBy;
16594     lodash.once = once;
16595     lodash.orderBy = orderBy;
16596     lodash.over = over;
16597     lodash.overArgs = overArgs;
16598     lodash.overEvery = overEvery;
16599     lodash.overSome = overSome;
16600     lodash.partial = partial;
16601     lodash.partialRight = partialRight;
16602     lodash.partition = partition;
16603     lodash.pick = pick;
16604     lodash.pickBy = pickBy;
16605     lodash.property = property;
16606     lodash.propertyOf = propertyOf;
16607     lodash.pull = pull;
16608     lodash.pullAll = pullAll;
16609     lodash.pullAllBy = pullAllBy;
16610     lodash.pullAllWith = pullAllWith;
16611     lodash.pullAt = pullAt;
16612     lodash.range = range;
16613     lodash.rangeRight = rangeRight;
16614     lodash.rearg = rearg;
16615     lodash.reject = reject;
16616     lodash.remove = remove;
16617     lodash.rest = rest;
16618     lodash.reverse = reverse;
16619     lodash.sampleSize = sampleSize;
16620     lodash.set = set;
16621     lodash.setWith = setWith;
16622     lodash.shuffle = shuffle;
16623     lodash.slice = slice;
16624     lodash.sortBy = sortBy;
16625     lodash.sortedUniq = sortedUniq;
16626     lodash.sortedUniqBy = sortedUniqBy;
16627     lodash.split = split;
16628     lodash.spread = spread;
16629     lodash.tail = tail;
16630     lodash.take = take;
16631     lodash.takeRight = takeRight;
16632     lodash.takeRightWhile = takeRightWhile;
16633     lodash.takeWhile = takeWhile;
16634     lodash.tap = tap;
16635     lodash.throttle = throttle;
16636     lodash.thru = thru;
16637     lodash.toArray = toArray;
16638     lodash.toPairs = toPairs;
16639     lodash.toPairsIn = toPairsIn;
16640     lodash.toPath = toPath;
16641     lodash.toPlainObject = toPlainObject;
16642     lodash.transform = transform;
16643     lodash.unary = unary;
16644     lodash.union = union;
16645     lodash.unionBy = unionBy;
16646     lodash.unionWith = unionWith;
16647     lodash.uniq = uniq;
16648     lodash.uniqBy = uniqBy;
16649     lodash.uniqWith = uniqWith;
16650     lodash.unset = unset;
16651     lodash.unzip = unzip;
16652     lodash.unzipWith = unzipWith;
16653     lodash.update = update;
16654     lodash.updateWith = updateWith;
16655     lodash.values = values;
16656     lodash.valuesIn = valuesIn;
16657     lodash.without = without;
16658     lodash.words = words;
16659     lodash.wrap = wrap;
16660     lodash.xor = xor;
16661     lodash.xorBy = xorBy;
16662     lodash.xorWith = xorWith;
16663     lodash.zip = zip;
16664     lodash.zipObject = zipObject;
16665     lodash.zipObjectDeep = zipObjectDeep;
16666     lodash.zipWith = zipWith;
16667
16668     // Add aliases.
16669     lodash.entries = toPairs;
16670     lodash.entriesIn = toPairsIn;
16671     lodash.extend = assignIn;
16672     lodash.extendWith = assignInWith;
16673
16674     // Add methods to `lodash.prototype`.
16675     mixin(lodash, lodash);
16676
16677     /*------------------------------------------------------------------------*/
16678
16679     // Add methods that return unwrapped values in chain sequences.
16680     lodash.add = add;
16681     lodash.attempt = attempt;
16682     lodash.camelCase = camelCase;
16683     lodash.capitalize = capitalize;
16684     lodash.ceil = ceil;
16685     lodash.clamp = clamp;
16686     lodash.clone = clone;
16687     lodash.cloneDeep = cloneDeep;
16688     lodash.cloneDeepWith = cloneDeepWith;
16689     lodash.cloneWith = cloneWith;
16690     lodash.conformsTo = conformsTo;
16691     lodash.deburr = deburr;
16692     lodash.defaultTo = defaultTo;
16693     lodash.divide = divide;
16694     lodash.endsWith = endsWith;
16695     lodash.eq = eq;
16696     lodash.escape = escape;
16697     lodash.escapeRegExp = escapeRegExp;
16698     lodash.every = every;
16699     lodash.find = find;
16700     lodash.findIndex = findIndex;
16701     lodash.findKey = findKey;
16702     lodash.findLast = findLast;
16703     lodash.findLastIndex = findLastIndex;
16704     lodash.findLastKey = findLastKey;
16705     lodash.floor = floor;
16706     lodash.forEach = forEach;
16707     lodash.forEachRight = forEachRight;
16708     lodash.forIn = forIn;
16709     lodash.forInRight = forInRight;
16710     lodash.forOwn = forOwn;
16711     lodash.forOwnRight = forOwnRight;
16712     lodash.get = get;
16713     lodash.gt = gt;
16714     lodash.gte = gte;
16715     lodash.has = has;
16716     lodash.hasIn = hasIn;
16717     lodash.head = head;
16718     lodash.identity = identity;
16719     lodash.includes = includes;
16720     lodash.indexOf = indexOf;
16721     lodash.inRange = inRange;
16722     lodash.invoke = invoke;
16723     lodash.isArguments = isArguments;
16724     lodash.isArray = isArray;
16725     lodash.isArrayBuffer = isArrayBuffer;
16726     lodash.isArrayLike = isArrayLike;
16727     lodash.isArrayLikeObject = isArrayLikeObject;
16728     lodash.isBoolean = isBoolean;
16729     lodash.isBuffer = isBuffer;
16730     lodash.isDate = isDate;
16731     lodash.isElement = isElement;
16732     lodash.isEmpty = isEmpty;
16733     lodash.isEqual = isEqual;
16734     lodash.isEqualWith = isEqualWith;
16735     lodash.isError = isError;
16736     lodash.isFinite = isFinite;
16737     lodash.isFunction = isFunction;
16738     lodash.isInteger = isInteger;
16739     lodash.isLength = isLength;
16740     lodash.isMap = isMap;
16741     lodash.isMatch = isMatch;
16742     lodash.isMatchWith = isMatchWith;
16743     lodash.isNaN = isNaN;
16744     lodash.isNative = isNative;
16745     lodash.isNil = isNil;
16746     lodash.isNull = isNull;
16747     lodash.isNumber = isNumber;
16748     lodash.isObject = isObject;
16749     lodash.isObjectLike = isObjectLike;
16750     lodash.isPlainObject = isPlainObject;
16751     lodash.isRegExp = isRegExp;
16752     lodash.isSafeInteger = isSafeInteger;
16753     lodash.isSet = isSet;
16754     lodash.isString = isString;
16755     lodash.isSymbol = isSymbol;
16756     lodash.isTypedArray = isTypedArray;
16757     lodash.isUndefined = isUndefined;
16758     lodash.isWeakMap = isWeakMap;
16759     lodash.isWeakSet = isWeakSet;
16760     lodash.join = join;
16761     lodash.kebabCase = kebabCase;
16762     lodash.last = last;
16763     lodash.lastIndexOf = lastIndexOf;
16764     lodash.lowerCase = lowerCase;
16765     lodash.lowerFirst = lowerFirst;
16766     lodash.lt = lt;
16767     lodash.lte = lte;
16768     lodash.max = max;
16769     lodash.maxBy = maxBy;
16770     lodash.mean = mean;
16771     lodash.meanBy = meanBy;
16772     lodash.min = min;
16773     lodash.minBy = minBy;
16774     lodash.stubArray = stubArray;
16775     lodash.stubFalse = stubFalse;
16776     lodash.stubObject = stubObject;
16777     lodash.stubString = stubString;
16778     lodash.stubTrue = stubTrue;
16779     lodash.multiply = multiply;
16780     lodash.nth = nth;
16781     lodash.noConflict = noConflict;
16782     lodash.noop = noop;
16783     lodash.now = now;
16784     lodash.pad = pad;
16785     lodash.padEnd = padEnd;
16786     lodash.padStart = padStart;
16787     lodash.parseInt = parseInt;
16788     lodash.random = random;
16789     lodash.reduce = reduce;
16790     lodash.reduceRight = reduceRight;
16791     lodash.repeat = repeat;
16792     lodash.replace = replace;
16793     lodash.result = result;
16794     lodash.round = round;
16795     lodash.runInContext = runInContext;
16796     lodash.sample = sample;
16797     lodash.size = size;
16798     lodash.snakeCase = snakeCase;
16799     lodash.some = some;
16800     lodash.sortedIndex = sortedIndex;
16801     lodash.sortedIndexBy = sortedIndexBy;
16802     lodash.sortedIndexOf = sortedIndexOf;
16803     lodash.sortedLastIndex = sortedLastIndex;
16804     lodash.sortedLastIndexBy = sortedLastIndexBy;
16805     lodash.sortedLastIndexOf = sortedLastIndexOf;
16806     lodash.startCase = startCase;
16807     lodash.startsWith = startsWith;
16808     lodash.subtract = subtract;
16809     lodash.sum = sum;
16810     lodash.sumBy = sumBy;
16811     lodash.template = template;
16812     lodash.times = times;
16813     lodash.toFinite = toFinite;
16814     lodash.toInteger = toInteger;
16815     lodash.toLength = toLength;
16816     lodash.toLower = toLower;
16817     lodash.toNumber = toNumber;
16818     lodash.toSafeInteger = toSafeInteger;
16819     lodash.toString = toString;
16820     lodash.toUpper = toUpper;
16821     lodash.trim = trim;
16822     lodash.trimEnd = trimEnd;
16823     lodash.trimStart = trimStart;
16824     lodash.truncate = truncate;
16825     lodash.unescape = unescape;
16826     lodash.uniqueId = uniqueId;
16827     lodash.upperCase = upperCase;
16828     lodash.upperFirst = upperFirst;
16829
16830     // Add aliases.
16831     lodash.each = forEach;
16832     lodash.eachRight = forEachRight;
16833     lodash.first = head;
16834
16835     mixin(lodash, (function() {
16836       var source = {};
16837       baseForOwn(lodash, function(func, methodName) {
16838         if (!hasOwnProperty.call(lodash.prototype, methodName)) {
16839           source[methodName] = func;
16840         }
16841       });
16842       return source;
16843     }()), { 'chain': false });
16844
16845     /*------------------------------------------------------------------------*/
16846
16847     /**
16848      * The semantic version number.
16849      *
16850      * @static
16851      * @memberOf _
16852      * @type {string}
16853      */
16854     lodash.VERSION = VERSION;
16855
16856     // Assign default placeholders.
16857     arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
16858       lodash[methodName].placeholder = lodash;
16859     });
16860
16861     // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
16862     arrayEach(['drop', 'take'], function(methodName, index) {
16863       LazyWrapper.prototype[methodName] = function(n) {
16864         n = n === undefined ? 1 : nativeMax(toInteger(n), 0);
16865
16866         var result = (this.__filtered__ && !index)
16867           ? new LazyWrapper(this)
16868           : this.clone();
16869
16870         if (result.__filtered__) {
16871           result.__takeCount__ = nativeMin(n, result.__takeCount__);
16872         } else {
16873           result.__views__.push({
16874             'size': nativeMin(n, MAX_ARRAY_LENGTH),
16875             'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
16876           });
16877         }
16878         return result;
16879       };
16880
16881       LazyWrapper.prototype[methodName + 'Right'] = function(n) {
16882         return this.reverse()[methodName](n).reverse();
16883       };
16884     });
16885
16886     // Add `LazyWrapper` methods that accept an `iteratee` value.
16887     arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
16888       var type = index + 1,
16889           isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;
16890
16891       LazyWrapper.prototype[methodName] = function(iteratee) {
16892         var result = this.clone();
16893         result.__iteratees__.push({
16894           'iteratee': getIteratee(iteratee, 3),
16895           'type': type
16896         });
16897         result.__filtered__ = result.__filtered__ || isFilter;
16898         return result;
16899       };
16900     });
16901
16902     // Add `LazyWrapper` methods for `_.head` and `_.last`.
16903     arrayEach(['head', 'last'], function(methodName, index) {
16904       var takeName = 'take' + (index ? 'Right' : '');
16905
16906       LazyWrapper.prototype[methodName] = function() {
16907         return this[takeName](1).value()[0];
16908       };
16909     });
16910
16911     // Add `LazyWrapper` methods for `_.initial` and `_.tail`.
16912     arrayEach(['initial', 'tail'], function(methodName, index) {
16913       var dropName = 'drop' + (index ? '' : 'Right');
16914
16915       LazyWrapper.prototype[methodName] = function() {
16916         return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
16917       };
16918     });
16919
16920     LazyWrapper.prototype.compact = function() {
16921       return this.filter(identity);
16922     };
16923
16924     LazyWrapper.prototype.find = function(predicate) {
16925       return this.filter(predicate).head();
16926     };
16927
16928     LazyWrapper.prototype.findLast = function(predicate) {
16929       return this.reverse().find(predicate);
16930     };
16931
16932     LazyWrapper.prototype.invokeMap = baseRest(function(path, args) {
16933       if (typeof path == 'function') {
16934         return new LazyWrapper(this);
16935       }
16936       return this.map(function(value) {
16937         return baseInvoke(value, path, args);
16938       });
16939     });
16940
16941     LazyWrapper.prototype.reject = function(predicate) {
16942       return this.filter(negate(getIteratee(predicate)));
16943     };
16944
16945     LazyWrapper.prototype.slice = function(start, end) {
16946       start = toInteger(start);
16947
16948       var result = this;
16949       if (result.__filtered__ && (start > 0 || end < 0)) {
16950         return new LazyWrapper(result);
16951       }
16952       if (start < 0) {
16953         result = result.takeRight(-start);
16954       } else if (start) {
16955         result = result.drop(start);
16956       }
16957       if (end !== undefined) {
16958         end = toInteger(end);
16959         result = end < 0 ? result.dropRight(-end) : result.take(end - start);
16960       }
16961       return result;
16962     };
16963
16964     LazyWrapper.prototype.takeRightWhile = function(predicate) {
16965       return this.reverse().takeWhile(predicate).reverse();
16966     };
16967
16968     LazyWrapper.prototype.toArray = function() {
16969       return this.take(MAX_ARRAY_LENGTH);
16970     };
16971
16972     // Add `LazyWrapper` methods to `lodash.prototype`.
16973     baseForOwn(LazyWrapper.prototype, function(func, methodName) {
16974       var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
16975           isTaker = /^(?:head|last)$/.test(methodName),
16976           lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
16977           retUnwrapped = isTaker || /^find/.test(methodName);
16978
16979       if (!lodashFunc) {
16980         return;
16981       }
16982       lodash.prototype[methodName] = function() {
16983         var value = this.__wrapped__,
16984             args = isTaker ? [1] : arguments,
16985             isLazy = value instanceof LazyWrapper,
16986             iteratee = args[0],
16987             useLazy = isLazy || isArray(value);
16988
16989         var interceptor = function(value) {
16990           var result = lodashFunc.apply(lodash, arrayPush([value], args));
16991           return (isTaker && chainAll) ? result[0] : result;
16992         };
16993
16994         if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
16995           // Avoid lazy use if the iteratee has a "length" value other than `1`.
16996           isLazy = useLazy = false;
16997         }
16998         var chainAll = this.__chain__,
16999             isHybrid = !!this.__actions__.length,
17000             isUnwrapped = retUnwrapped && !chainAll,
17001             onlyLazy = isLazy && !isHybrid;
17002
17003         if (!retUnwrapped && useLazy) {
17004           value = onlyLazy ? value : new LazyWrapper(this);
17005           var result = func.apply(value, args);
17006           result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
17007           return new LodashWrapper(result, chainAll);
17008         }
17009         if (isUnwrapped && onlyLazy) {
17010           return func.apply(this, args);
17011         }
17012         result = this.thru(interceptor);
17013         return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
17014       };
17015     });
17016
17017     // Add `Array` methods to `lodash.prototype`.
17018     arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
17019       var func = arrayProto[methodName],
17020           chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
17021           retUnwrapped = /^(?:pop|shift)$/.test(methodName);
17022
17023       lodash.prototype[methodName] = function() {
17024         var args = arguments;
17025         if (retUnwrapped && !this.__chain__) {
17026           var value = this.value();
17027           return func.apply(isArray(value) ? value : [], args);
17028         }
17029         return this[chainName](function(value) {
17030           return func.apply(isArray(value) ? value : [], args);
17031         });
17032       };
17033     });
17034
17035     // Map minified method names to their real names.
17036     baseForOwn(LazyWrapper.prototype, function(func, methodName) {
17037       var lodashFunc = lodash[methodName];
17038       if (lodashFunc) {
17039         var key = (lodashFunc.name + ''),
17040             names = realNames[key] || (realNames[key] = []);
17041
17042         names.push({ 'name': methodName, 'func': lodashFunc });
17043       }
17044     });
17045
17046     realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{
17047       'name': 'wrapper',
17048       'func': undefined
17049     }];
17050
17051     // Add methods to `LazyWrapper`.
17052     LazyWrapper.prototype.clone = lazyClone;
17053     LazyWrapper.prototype.reverse = lazyReverse;
17054     LazyWrapper.prototype.value = lazyValue;
17055
17056     // Add chain sequence methods to the `lodash` wrapper.
17057     lodash.prototype.at = wrapperAt;
17058     lodash.prototype.chain = wrapperChain;
17059     lodash.prototype.commit = wrapperCommit;
17060     lodash.prototype.next = wrapperNext;
17061     lodash.prototype.plant = wrapperPlant;
17062     lodash.prototype.reverse = wrapperReverse;
17063     lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
17064
17065     // Add lazy aliases.
17066     lodash.prototype.first = lodash.prototype.head;
17067
17068     if (symIterator) {
17069       lodash.prototype[symIterator] = wrapperToIterator;
17070     }
17071     return lodash;
17072   });
17073
17074   /*--------------------------------------------------------------------------*/
17075
17076   // Export lodash.
17077   var _ = runInContext();
17078
17079   // Some AMD build optimizers, like r.js, check for condition patterns like:
17080   if (typeof undefined == 'function' && typeof undefined.amd == 'object' && undefined.amd) {
17081     // Expose Lodash on the global object to prevent errors when Lodash is
17082     // loaded by a script tag in the presence of an AMD loader.
17083     // See http://requirejs.org/docs/errors.html#mismatch for more details.
17084     // Use `_.noConflict` to remove Lodash from the global object.
17085     root._ = _;
17086
17087     // Define as an anonymous module so, through path mapping, it can be
17088     // referenced as the "underscore" module.
17089     undefined(function() {
17090       return _;
17091     });
17092   }
17093   // Check for `exports` after `define` in case a build optimizer adds it.
17094   else if (freeModule) {
17095     // Export for Node.js.
17096     (freeModule.exports = _)._ = _;
17097     // Export for CommonJS support.
17098     freeExports._ = _;
17099   }
17100   else {
17101     // Export to the global object.
17102     root._ = _;
17103   }
17104 }.call(commonjsGlobal));
17105 });
17106
17107
17108
17109 var lodash$1 = Object.freeze({
17110         default: lodash,
17111         __moduleExports: lodash
17112 });
17113
17114 function osmIsInterestingTag(key) {
17115     return key !== 'attribution' &&
17116         key !== 'created_by' &&
17117         key !== 'source' &&
17118         key !== 'odbl' &&
17119         key.indexOf('tiger:') !== 0;
17120
17121 }
17122
17123
17124 var osmOneWayTags = {
17125     'aerialway': {
17126         'chair_lift': true,
17127         'mixed_lift': true,
17128         't-bar': true,
17129         'j-bar': true,
17130         'platter': true,
17131         'rope_tow': true,
17132         'magic_carpet': true,
17133         'yes': true
17134     },
17135     'highway': {
17136         'motorway': true,
17137         'motorway_link': true
17138     },
17139     'junction': {
17140         'roundabout': true
17141     },
17142     'man_made': {
17143         'piste:halfpipe': true
17144     },
17145     'piste:type': {
17146         'downhill': true,
17147         'sled': true,
17148         'yes': true
17149     },
17150     'waterway': {
17151         'canal': true,
17152         'ditch': true,
17153         'drain': true,
17154         'river': true,
17155         'stream': true
17156     }
17157 };
17158
17159
17160 var osmPavedTags = {
17161     'surface': {
17162         'paved': true,
17163         'asphalt': true,
17164         'concrete': true
17165     },
17166     'tracktype': {
17167         'grade1': true
17168     }
17169 };
17170
17171 var dataWikipedia = [
17172     [
17173         "Abkhazian",
17174         "Аҧсшәа",
17175         "ab"
17176     ],
17177     [
17178         "Achinese",
17179         "Acèh",
17180         "ace"
17181     ],
17182     [
17183         "Adyghe",
17184         "адыгабзэ",
17185         "ady"
17186     ],
17187     [
17188         "Afrikaans",
17189         "Afrikaans",
17190         "af"
17191     ],
17192     [
17193         "Akan",
17194         "Akan",
17195         "ak"
17196     ],
17197     [
17198         "Alemannisch",
17199         "Alemannisch",
17200         "als"
17201     ],
17202     [
17203         "Amharic",
17204         "አማርኛ",
17205         "am"
17206     ],
17207     [
17208         "Aragonese",
17209         "aragonés",
17210         "an"
17211     ],
17212     [
17213         "Old English",
17214         "Ænglisc",
17215         "ang"
17216     ],
17217     [
17218         "Arabic",
17219         "العربية",
17220         "ar"
17221     ],
17222     [
17223         "Aramaic",
17224         "ܐܪܡܝܐ",
17225         "arc"
17226     ],
17227     [
17228         "Egyptian Arabic",
17229         "مصرى",
17230         "arz"
17231     ],
17232     [
17233         "Assamese",
17234         "অসমীয়া",
17235         "as"
17236     ],
17237     [
17238         "Asturian",
17239         "asturianu",
17240         "ast"
17241     ],
17242     [
17243         "Avaric",
17244         "авар",
17245         "av"
17246     ],
17247     [
17248         "Aymara",
17249         "Aymar aru",
17250         "ay"
17251     ],
17252     [
17253         "Azerbaijani",
17254         "azərbaycanca",
17255         "az"
17256     ],
17257     [
17258         "تۆرکجه",
17259         "تۆرکجه",
17260         "azb"
17261     ],
17262     [
17263         "Bashkir",
17264         "башҡортса",
17265         "ba"
17266     ],
17267     [
17268         "Bavarian",
17269         "Boarisch",
17270         "bar"
17271     ],
17272     [
17273         "Samogitian",
17274         "žemaitėška",
17275         "bat-smg"
17276     ],
17277     [
17278         "Bikol Central",
17279         "Bikol Central",
17280         "bcl"
17281     ],
17282     [
17283         "Belarusian",
17284         "беларуская",
17285         "be"
17286     ],
17287     [
17288         "беларуская (тарашкевіца)‎",
17289         "беларуская (тарашкевіца)‎",
17290         "be-x-old"
17291     ],
17292     [
17293         "Bulgarian",
17294         "български",
17295         "bg"
17296     ],
17297     [
17298         "भोजपुरी",
17299         "भोजपुरी",
17300         "bh"
17301     ],
17302     [
17303         "Bislama",
17304         "Bislama",
17305         "bi"
17306     ],
17307     [
17308         "Banjar",
17309         "Bahasa Banjar",
17310         "bjn"
17311     ],
17312     [
17313         "Bambara",
17314         "bamanankan",
17315         "bm"
17316     ],
17317     [
17318         "Bangla",
17319         "বাংলা",
17320         "bn"
17321     ],
17322     [
17323         "Tibetan",
17324         "བོད་ཡིག",
17325         "bo"
17326     ],
17327     [
17328         "Bishnupriya",
17329         "বিষ্ণুপ্রিয়া মণিপুরী",
17330         "bpy"
17331     ],
17332     [
17333         "Breton",
17334         "brezhoneg",
17335         "br"
17336     ],
17337     [
17338         "Bosnian",
17339         "bosanski",
17340         "bs"
17341     ],
17342     [
17343         "Buginese",
17344         "ᨅᨔ ᨕᨘᨁᨗ",
17345         "bug"
17346     ],
17347     [
17348         "буряад",
17349         "буряад",
17350         "bxr"
17351     ],
17352     [
17353         "Catalan",
17354         "català",
17355         "ca"
17356     ],
17357     [
17358         "Chavacano de Zamboanga",
17359         "Chavacano de Zamboanga",
17360         "cbk-zam"
17361     ],
17362     [
17363         "Min Dong Chinese",
17364         "Mìng-dĕ̤ng-ngṳ̄",
17365         "cdo"
17366     ],
17367     [
17368         "Chechen",
17369         "нохчийн",
17370         "ce"
17371     ],
17372     [
17373         "Cebuano",
17374         "Cebuano",
17375         "ceb"
17376     ],
17377     [
17378         "Chamorro",
17379         "Chamoru",
17380         "ch"
17381     ],
17382     [
17383         "Cherokee",
17384         "ᏣᎳᎩ",
17385         "chr"
17386     ],
17387     [
17388         "Cheyenne",
17389         "Tsetsêhestâhese",
17390         "chy"
17391     ],
17392     [
17393         "Central Kurdish",
17394         "کوردیی ناوەندی",
17395         "ckb"
17396     ],
17397     [
17398         "Corsican",
17399         "corsu",
17400         "co"
17401     ],
17402     [
17403         "Cree",
17404         "Nēhiyawēwin / ᓀᐦᐃᔭᐍᐏᐣ",
17405         "cr"
17406     ],
17407     [
17408         "Crimean Turkish",
17409         "qırımtatarca",
17410         "crh"
17411     ],
17412     [
17413         "Czech",
17414         "čeština",
17415         "cs"
17416     ],
17417     [
17418         "Kashubian",
17419         "kaszëbsczi",
17420         "csb"
17421     ],
17422     [
17423         "Church Slavic",
17424         "словѣньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ",
17425         "cu"
17426     ],
17427     [
17428         "Chuvash",
17429         "Чӑвашла",
17430         "cv"
17431     ],
17432     [
17433         "Welsh",
17434         "Cymraeg",
17435         "cy"
17436     ],
17437     [
17438         "Danish",
17439         "dansk",
17440         "da"
17441     ],
17442     [
17443         "German",
17444         "Deutsch",
17445         "de"
17446     ],
17447     [
17448         "Zazaki",
17449         "Zazaki",
17450         "diq"
17451     ],
17452     [
17453         "Lower Sorbian",
17454         "dolnoserbski",
17455         "dsb"
17456     ],
17457     [
17458         "Divehi",
17459         "ދިވެހިބަސް",
17460         "dv"
17461     ],
17462     [
17463         "Dzongkha",
17464         "ཇོང་ཁ",
17465         "dz"
17466     ],
17467     [
17468         "Ewe",
17469         "eʋegbe",
17470         "ee"
17471     ],
17472     [
17473         "Greek",
17474         "Ελληνικά",
17475         "el"
17476     ],
17477     [
17478         "Emiliano-Romagnolo",
17479         "emiliàn e rumagnòl",
17480         "eml"
17481     ],
17482     [
17483         "English",
17484         "English",
17485         "en"
17486     ],
17487     [
17488         "Esperanto",
17489         "Esperanto",
17490         "eo"
17491     ],
17492     [
17493         "Spanish",
17494         "español",
17495         "es"
17496     ],
17497     [
17498         "Estonian",
17499         "eesti",
17500         "et"
17501     ],
17502     [
17503         "Basque",
17504         "euskara",
17505         "eu"
17506     ],
17507     [
17508         "Extremaduran",
17509         "estremeñu",
17510         "ext"
17511     ],
17512     [
17513         "Persian",
17514         "فارسی",
17515         "fa"
17516     ],
17517     [
17518         "Fulah",
17519         "Fulfulde",
17520         "ff"
17521     ],
17522     [
17523         "Finnish",
17524         "suomi",
17525         "fi"
17526     ],
17527     [
17528         "Võro",
17529         "Võro",
17530         "fiu-vro"
17531     ],
17532     [
17533         "Fijian",
17534         "Na Vosa Vakaviti",
17535         "fj"
17536     ],
17537     [
17538         "Faroese",
17539         "føroyskt",
17540         "fo"
17541     ],
17542     [
17543         "French",
17544         "français",
17545         "fr"
17546     ],
17547     [
17548         "Arpitan",
17549         "arpetan",
17550         "frp"
17551     ],
17552     [
17553         "Northern Frisian",
17554         "Nordfriisk",
17555         "frr"
17556     ],
17557     [
17558         "Friulian",
17559         "furlan",
17560         "fur"
17561     ],
17562     [
17563         "Western Frisian",
17564         "Frysk",
17565         "fy"
17566     ],
17567     [
17568         "Irish",
17569         "Gaeilge",
17570         "ga"
17571     ],
17572     [
17573         "Gagauz",
17574         "Gagauz",
17575         "gag"
17576     ],
17577     [
17578         "Gan Chinese",
17579         "贛語",
17580         "gan"
17581     ],
17582     [
17583         "Scottish Gaelic",
17584         "Gàidhlig",
17585         "gd"
17586     ],
17587     [
17588         "Galician",
17589         "galego",
17590         "gl"
17591     ],
17592     [
17593         "Gilaki",
17594         "گیلکی",
17595         "glk"
17596     ],
17597     [
17598         "Guarani",
17599         "Avañe'ẽ",
17600         "gn"
17601     ],
17602     [
17603         "Goan Konkani",
17604         "गोंयची कोंकणी / Gõychi Konknni",
17605         "gom"
17606     ],
17607     [
17608         "Gothic",
17609         "𐌲𐌿𐍄𐌹𐍃𐌺",
17610         "got"
17611     ],
17612     [
17613         "Gujarati",
17614         "ગુજરાતી",
17615         "gu"
17616     ],
17617     [
17618         "Manx",
17619         "Gaelg",
17620         "gv"
17621     ],
17622     [
17623         "Hausa",
17624         "Hausa",
17625         "ha"
17626     ],
17627     [
17628         "Hakka Chinese",
17629         "客家語/Hak-kâ-ngî",
17630         "hak"
17631     ],
17632     [
17633         "Hawaiian",
17634         "Hawaiʻi",
17635         "haw"
17636     ],
17637     [
17638         "Hebrew",
17639         "עברית",
17640         "he"
17641     ],
17642     [
17643         "Hindi",
17644         "हिन्दी",
17645         "hi"
17646     ],
17647     [
17648         "Fiji Hindi",
17649         "Fiji Hindi",
17650         "hif"
17651     ],
17652     [
17653         "Croatian",
17654         "hrvatski",
17655         "hr"
17656     ],
17657     [
17658         "Upper Sorbian",
17659         "hornjoserbsce",
17660         "hsb"
17661     ],
17662     [
17663         "Haitian Creole",
17664         "Kreyòl ayisyen",
17665         "ht"
17666     ],
17667     [
17668         "Hungarian",
17669         "magyar",
17670         "hu"
17671     ],
17672     [
17673         "Armenian",
17674         "Հայերեն",
17675         "hy"
17676     ],
17677     [
17678         "Interlingua",
17679         "interlingua",
17680         "ia"
17681     ],
17682     [
17683         "Indonesian",
17684         "Bahasa Indonesia",
17685         "id"
17686     ],
17687     [
17688         "Interlingue",
17689         "Interlingue",
17690         "ie"
17691     ],
17692     [
17693         "Igbo",
17694         "Igbo",
17695         "ig"
17696     ],
17697     [
17698         "Inupiaq",
17699         "Iñupiak",
17700         "ik"
17701     ],
17702     [
17703         "Iloko",
17704         "Ilokano",
17705         "ilo"
17706     ],
17707     [
17708         "Ido",
17709         "Ido",
17710         "io"
17711     ],
17712     [
17713         "Icelandic",
17714         "íslenska",
17715         "is"
17716     ],
17717     [
17718         "Italian",
17719         "italiano",
17720         "it"
17721     ],
17722     [
17723         "Inuktitut",
17724         "ᐃᓄᒃᑎᑐᑦ/inuktitut",
17725         "iu"
17726     ],
17727     [
17728         "Japanese",
17729         "日本語",
17730         "ja"
17731     ],
17732     [
17733         "Jamaican Creole English",
17734         "Patois",
17735         "jam"
17736     ],
17737     [
17738         "Lojban",
17739         "la .lojban.",
17740         "jbo"
17741     ],
17742     [
17743         "Javanese",
17744         "Basa Jawa",
17745         "jv"
17746     ],
17747     [
17748         "Georgian",
17749         "ქართული",
17750         "ka"
17751     ],
17752     [
17753         "Kara-Kalpak",
17754         "Qaraqalpaqsha",
17755         "kaa"
17756     ],
17757     [
17758         "Kabyle",
17759         "Taqbaylit",
17760         "kab"
17761     ],
17762     [
17763         "Kabardian",
17764         "Адыгэбзэ",
17765         "kbd"
17766     ],
17767     [
17768         "Kongo",
17769         "Kongo",
17770         "kg"
17771     ],
17772     [
17773         "Kikuyu",
17774         "Gĩkũyũ",
17775         "ki"
17776     ],
17777     [
17778         "Kazakh",
17779         "қазақша",
17780         "kk"
17781     ],
17782     [
17783         "Kalaallisut",
17784         "kalaallisut",
17785         "kl"
17786     ],
17787     [
17788         "Khmer",
17789         "ភាសាខ្មែរ",
17790         "km"
17791     ],
17792     [
17793         "Kannada",
17794         "ಕನ್ನಡ",
17795         "kn"
17796     ],
17797     [
17798         "Korean",
17799         "한국어",
17800         "ko"
17801     ],
17802     [
17803         "Komi-Permyak",
17804         "Перем Коми",
17805         "koi"
17806     ],
17807     [
17808         "Karachay-Balkar",
17809         "къарачай-малкъар",
17810         "krc"
17811     ],
17812     [
17813         "Kashmiri",
17814         "कॉशुर / کٲشُر",
17815         "ks"
17816     ],
17817     [
17818         "Colognian",
17819         "Ripoarisch",
17820         "ksh"
17821     ],
17822     [
17823         "Kurdish",
17824         "Kurdî",
17825         "ku"
17826     ],
17827     [
17828         "Komi",
17829         "коми",
17830         "kv"
17831     ],
17832     [
17833         "Cornish",
17834         "kernowek",
17835         "kw"
17836     ],
17837     [
17838         "Kyrgyz",
17839         "Кыргызча",
17840         "ky"
17841     ],
17842     [
17843         "Latin",
17844         "Latina",
17845         "la"
17846     ],
17847     [
17848         "Ladino",
17849         "Ladino",
17850         "lad"
17851     ],
17852     [
17853         "Luxembourgish",
17854         "Lëtzebuergesch",
17855         "lb"
17856     ],
17857     [
17858         "лакку",
17859         "лакку",
17860         "lbe"
17861     ],
17862     [
17863         "Lezghian",
17864         "лезги",
17865         "lez"
17866     ],
17867     [
17868         "Ganda",
17869         "Luganda",
17870         "lg"
17871     ],
17872     [
17873         "Limburgish",
17874         "Limburgs",
17875         "li"
17876     ],
17877     [
17878         "Ligurian",
17879         "Ligure",
17880         "lij"
17881     ],
17882     [
17883         "Lombard",
17884         "lumbaart",
17885         "lmo"
17886     ],
17887     [
17888         "Lingala",
17889         "lingála",
17890         "ln"
17891     ],
17892     [
17893         "Lao",
17894         "ລາວ",
17895         "lo"
17896     ],
17897     [
17898         "Northern Luri",
17899         "لۊری شومالی",
17900         "lrc"
17901     ],
17902     [
17903         "Lithuanian",
17904         "lietuvių",
17905         "lt"
17906     ],
17907     [
17908         "Latgalian",
17909         "latgaļu",
17910         "ltg"
17911     ],
17912     [
17913         "Latvian",
17914         "latviešu",
17915         "lv"
17916     ],
17917     [
17918         "Maithili",
17919         "मैथिली",
17920         "mai"
17921     ],
17922     [
17923         "Basa Banyumasan",
17924         "Basa Banyumasan",
17925         "map-bms"
17926     ],
17927     [
17928         "Moksha",
17929         "мокшень",
17930         "mdf"
17931     ],
17932     [
17933         "Malagasy",
17934         "Malagasy",
17935         "mg"
17936     ],
17937     [
17938         "Eastern Mari",
17939         "олык марий",
17940         "mhr"
17941     ],
17942     [
17943         "Maori",
17944         "Māori",
17945         "mi"
17946     ],
17947     [
17948         "Minangkabau",
17949         "Baso Minangkabau",
17950         "min"
17951     ],
17952     [
17953         "Macedonian",
17954         "македонски",
17955         "mk"
17956     ],
17957     [
17958         "Malayalam",
17959         "മലയാളം",
17960         "ml"
17961     ],
17962     [
17963         "Mongolian",
17964         "монгол",
17965         "mn"
17966     ],
17967     [
17968         "Marathi",
17969         "मराठी",
17970         "mr"
17971     ],
17972     [
17973         "Western Mari",
17974         "кырык мары",
17975         "mrj"
17976     ],
17977     [
17978         "Malay",
17979         "Bahasa Melayu",
17980         "ms"
17981     ],
17982     [
17983         "Maltese",
17984         "Malti",
17985         "mt"
17986     ],
17987     [
17988         "Mirandese",
17989         "Mirandés",
17990         "mwl"
17991     ],
17992     [
17993         "Burmese",
17994         "မြန်မာဘာသာ",
17995         "my"
17996     ],
17997     [
17998         "Erzya",
17999         "эрзянь",
18000         "myv"
18001     ],
18002     [
18003         "Mazanderani",
18004         "مازِرونی",
18005         "mzn"
18006     ],
18007     [
18008         "Nauru",
18009         "Dorerin Naoero",
18010         "na"
18011     ],
18012     [
18013         "Nāhuatl",
18014         "Nāhuatl",
18015         "nah"
18016     ],
18017     [
18018         "Neapolitan",
18019         "Napulitano",
18020         "nap"
18021     ],
18022     [
18023         "Low German",
18024         "Plattdüütsch",
18025         "nds"
18026     ],
18027     [
18028         "Low Saxon",
18029         "Nedersaksies",
18030         "nds-nl"
18031     ],
18032     [
18033         "Nepali",
18034         "नेपाली",
18035         "ne"
18036     ],
18037     [
18038         "Newari",
18039         "नेपाल भाषा",
18040         "new"
18041     ],
18042     [
18043         "Dutch",
18044         "Nederlands",
18045         "nl"
18046     ],
18047     [
18048         "Norwegian Nynorsk",
18049         "norsk nynorsk",
18050         "nn"
18051     ],
18052     [
18053         "Norwegian",
18054         "norsk bokmål",
18055         "no"
18056     ],
18057     [
18058         "Novial",
18059         "Novial",
18060         "nov"
18061     ],
18062     [
18063         "Nouormand",
18064         "Nouormand",
18065         "nrm"
18066     ],
18067     [
18068         "Northern Sotho",
18069         "Sesotho sa Leboa",
18070         "nso"
18071     ],
18072     [
18073         "Navajo",
18074         "Diné bizaad",
18075         "nv"
18076     ],
18077     [
18078         "Nyanja",
18079         "Chi-Chewa",
18080         "ny"
18081     ],
18082     [
18083         "Occitan",
18084         "occitan",
18085         "oc"
18086     ],
18087     [
18088         "Livvi-Karelian",
18089         "Livvinkarjala",
18090         "olo"
18091     ],
18092     [
18093         "Oromo",
18094         "Oromoo",
18095         "om"
18096     ],
18097     [
18098         "Odia",
18099         "ଓଡ଼ିଆ",
18100         "or"
18101     ],
18102     [
18103         "Ossetic",
18104         "Ирон",
18105         "os"
18106     ],
18107     [
18108         "Punjabi",
18109         "ਪੰਜਾਬੀ",
18110         "pa"
18111     ],
18112     [
18113         "Pangasinan",
18114         "Pangasinan",
18115         "pag"
18116     ],
18117     [
18118         "Pampanga",
18119         "Kapampangan",
18120         "pam"
18121     ],
18122     [
18123         "Papiamento",
18124         "Papiamentu",
18125         "pap"
18126     ],
18127     [
18128         "Picard",
18129         "Picard",
18130         "pcd"
18131     ],
18132     [
18133         "Pennsylvania German",
18134         "Deitsch",
18135         "pdc"
18136     ],
18137     [
18138         "Palatine German",
18139         "Pälzisch",
18140         "pfl"
18141     ],
18142     [
18143         "Pali",
18144         "पालि",
18145         "pi"
18146     ],
18147     [
18148         "Norfuk / Pitkern",
18149         "Norfuk / Pitkern",
18150         "pih"
18151     ],
18152     [
18153         "Polish",
18154         "polski",
18155         "pl"
18156     ],
18157     [
18158         "Piedmontese",
18159         "Piemontèis",
18160         "pms"
18161     ],
18162     [
18163         "Western Punjabi",
18164         "پنجابی",
18165         "pnb"
18166     ],
18167     [
18168         "Pontic",
18169         "Ποντιακά",
18170         "pnt"
18171     ],
18172     [
18173         "Pashto",
18174         "پښتو",
18175         "ps"
18176     ],
18177     [
18178         "Portuguese",
18179         "português",
18180         "pt"
18181     ],
18182     [
18183         "Quechua",
18184         "Runa Simi",
18185         "qu"
18186     ],
18187     [
18188         "Romansh",
18189         "rumantsch",
18190         "rm"
18191     ],
18192     [
18193         "Romani",
18194         "Romani",
18195         "rmy"
18196     ],
18197     [
18198         "Rundi",
18199         "Kirundi",
18200         "rn"
18201     ],
18202     [
18203         "Romanian",
18204         "română",
18205         "ro"
18206     ],
18207     [
18208         "Aromanian",
18209         "armãneashti",
18210         "roa-rup"
18211     ],
18212     [
18213         "tarandíne",
18214         "tarandíne",
18215         "roa-tara"
18216     ],
18217     [
18218         "Russian",
18219         "русский",
18220         "ru"
18221     ],
18222     [
18223         "Rusyn",
18224         "русиньскый",
18225         "rue"
18226     ],
18227     [
18228         "Kinyarwanda",
18229         "Kinyarwanda",
18230         "rw"
18231     ],
18232     [
18233         "Sanskrit",
18234         "संस्कृतम्",
18235         "sa"
18236     ],
18237     [
18238         "Sakha",
18239         "саха тыла",
18240         "sah"
18241     ],
18242     [
18243         "Sardinian",
18244         "sardu",
18245         "sc"
18246     ],
18247     [
18248         "Sicilian",
18249         "sicilianu",
18250         "scn"
18251     ],
18252     [
18253         "Scots",
18254         "Scots",
18255         "sco"
18256     ],
18257     [
18258         "Sindhi",
18259         "سنڌي",
18260         "sd"
18261     ],
18262     [
18263         "Northern Sami",
18264         "sámegiella",
18265         "se"
18266     ],
18267     [
18268         "Sango",
18269         "Sängö",
18270         "sg"
18271     ],
18272     [
18273         "Serbo-Croatian",
18274         "srpskohrvatski / српскохрватски",
18275         "sh"
18276     ],
18277     [
18278         "Sinhala",
18279         "සිංහල",
18280         "si"
18281     ],
18282     [
18283         "Simple English",
18284         "Simple English",
18285         "simple"
18286     ],
18287     [
18288         "Slovak",
18289         "slovenčina",
18290         "sk"
18291     ],
18292     [
18293         "Slovenian",
18294         "slovenščina",
18295         "sl"
18296     ],
18297     [
18298         "Samoan",
18299         "Gagana Samoa",
18300         "sm"
18301     ],
18302     [
18303         "Shona",
18304         "chiShona",
18305         "sn"
18306     ],
18307     [
18308         "Somali",
18309         "Soomaaliga",
18310         "so"
18311     ],
18312     [
18313         "Albanian",
18314         "shqip",
18315         "sq"
18316     ],
18317     [
18318         "Serbian",
18319         "српски / srpski",
18320         "sr"
18321     ],
18322     [
18323         "Sranan Tongo",
18324         "Sranantongo",
18325         "srn"
18326     ],
18327     [
18328         "Swati",
18329         "SiSwati",
18330         "ss"
18331     ],
18332     [
18333         "Southern Sotho",
18334         "Sesotho",
18335         "st"
18336     ],
18337     [
18338         "Saterland Frisian",
18339         "Seeltersk",
18340         "stq"
18341     ],
18342     [
18343         "Sundanese",
18344         "Basa Sunda",
18345         "su"
18346     ],
18347     [
18348         "Swedish",
18349         "svenska",
18350         "sv"
18351     ],
18352     [
18353         "Swahili",
18354         "Kiswahili",
18355         "sw"
18356     ],
18357     [
18358         "Silesian",
18359         "ślůnski",
18360         "szl"
18361     ],
18362     [
18363         "Tamil",
18364         "தமிழ்",
18365         "ta"
18366     ],
18367     [
18368         "Tulu",
18369         "ತುಳು",
18370         "tcy"
18371     ],
18372     [
18373         "Telugu",
18374         "తెలుగు",
18375         "te"
18376     ],
18377     [
18378         "Tetum",
18379         "tetun",
18380         "tet"
18381     ],
18382     [
18383         "Tajik",
18384         "тоҷикӣ",
18385         "tg"
18386     ],
18387     [
18388         "Thai",
18389         "ไทย",
18390         "th"
18391     ],
18392     [
18393         "Tigrinya",
18394         "ትግርኛ",
18395         "ti"
18396     ],
18397     [
18398         "Turkmen",
18399         "Türkmençe",
18400         "tk"
18401     ],
18402     [
18403         "Tagalog",
18404         "Tagalog",
18405         "tl"
18406     ],
18407     [
18408         "Tswana",
18409         "Setswana",
18410         "tn"
18411     ],
18412     [
18413         "Tongan",
18414         "lea faka-Tonga",
18415         "to"
18416     ],
18417     [
18418         "Tok Pisin",
18419         "Tok Pisin",
18420         "tpi"
18421     ],
18422     [
18423         "Turkish",
18424         "Türkçe",
18425         "tr"
18426     ],
18427     [
18428         "Tsonga",
18429         "Xitsonga",
18430         "ts"
18431     ],
18432     [
18433         "Tatar",
18434         "татарча/tatarça",
18435         "tt"
18436     ],
18437     [
18438         "Tumbuka",
18439         "chiTumbuka",
18440         "tum"
18441     ],
18442     [
18443         "Twi",
18444         "Twi",
18445         "tw"
18446     ],
18447     [
18448         "Tahitian",
18449         "reo tahiti",
18450         "ty"
18451     ],
18452     [
18453         "Tuvinian",
18454         "тыва дыл",
18455         "tyv"
18456     ],
18457     [
18458         "Udmurt",
18459         "удмурт",
18460         "udm"
18461     ],
18462     [
18463         "Uyghur",
18464         "ئۇيغۇرچە / Uyghurche",
18465         "ug"
18466     ],
18467     [
18468         "Ukrainian",
18469         "українська",
18470         "uk"
18471     ],
18472     [
18473         "Urdu",
18474         "اردو",
18475         "ur"
18476     ],
18477     [
18478         "Uzbek",
18479         "oʻzbekcha/ўзбекча",
18480         "uz"
18481     ],
18482     [
18483         "Venda",
18484         "Tshivenda",
18485         "ve"
18486     ],
18487     [
18488         "Venetian",
18489         "vèneto",
18490         "vec"
18491     ],
18492     [
18493         "Veps",
18494         "vepsän kel’",
18495         "vep"
18496     ],
18497     [
18498         "Vietnamese",
18499         "Tiếng Việt",
18500         "vi"
18501     ],
18502     [
18503         "West Flemish",
18504         "West-Vlams",
18505         "vls"
18506     ],
18507     [
18508         "Volapük",
18509         "Volapük",
18510         "vo"
18511     ],
18512     [
18513         "Walloon",
18514         "walon",
18515         "wa"
18516     ],
18517     [
18518         "Waray",
18519         "Winaray",
18520         "war"
18521     ],
18522     [
18523         "Wolof",
18524         "Wolof",
18525         "wo"
18526     ],
18527     [
18528         "Wu Chinese",
18529         "吴语",
18530         "wuu"
18531     ],
18532     [
18533         "Kalmyk",
18534         "хальмг",
18535         "xal"
18536     ],
18537     [
18538         "Xhosa",
18539         "isiXhosa",
18540         "xh"
18541     ],
18542     [
18543         "Mingrelian",
18544         "მარგალური",
18545         "xmf"
18546     ],
18547     [
18548         "Yiddish",
18549         "ייִדיש",
18550         "yi"
18551     ],
18552     [
18553         "Yoruba",
18554         "Yorùbá",
18555         "yo"
18556     ],
18557     [
18558         "Zhuang",
18559         "Vahcuengh",
18560         "za"
18561     ],
18562     [
18563         "Zeelandic",
18564         "Zeêuws",
18565         "zea"
18566     ],
18567     [
18568         "Chinese",
18569         "中文",
18570         "zh"
18571     ],
18572     [
18573         "Classical Chinese",
18574         "文言",
18575         "zh-classical"
18576     ],
18577     [
18578         "Chinese (Min Nan)",
18579         "Bân-lâm-gú",
18580         "zh-min-nan"
18581     ],
18582     [
18583         "Cantonese",
18584         "粵語",
18585         "zh-yue"
18586     ],
18587     [
18588         "Zulu",
18589         "isiZulu",
18590         "zu"
18591     ]
18592 ];
18593
18594 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}}};
18595 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}}};
18596 var dataSuggestions = {
18597         amenity: amenity,
18598         shop: shop
18599 };
18600
18601 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"]]}];
18602
18603 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"}}];
18604
18605 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"];
18606
18607 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}};
18608
18609 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"};
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\nA list of available keyboard shortcuts can be found [here](http://wiki.openstreetmap.org/wiki/ID/Shortcuts).\n","roads":"# Roads\n\nYou can create, fix, and delete roads with this editor. Roads can be all\nkinds: paths, highways, trails, cycleways, and more - any often-crossed\nsegment should be mappable.\n\n### Selecting\n\nClick on a road to select it. An outline should become visible, along\nwith a small tools menu on the map and a sidebar showing more information\nabout the road.\n\n### Modifying\n\nOften you'll see roads that aren't aligned to the imagery behind them\nor to a GPS track. You can adjust these roads so they are in the correct\nplace.\n\nFirst click on the road you want to change. This will highlight it and show\ncontrol points along it that you can drag to better locations. If\nyou want to add new control points for more detail, double-click a part\nof the road without a node, and one will be added.\n\nIf the road connects to another road, but doesn't properly connect on\nthe map, you can drag one of its control points onto the other road in\norder to join them. Having roads connect is important for the map\nand essential for providing driving directions.\n\nYou can also click the 'Move' tool or press the `M` shortcut key to move the entire road at\none time, and then click again to save that movement.\n\n### Deleting\n\nIf a road is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.\n\nYou can delete a road by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n\n### Creating\n\nFound somewhere there should be a road but there isn't? Click the 'Line'\nicon in the top-left of the editor or press the shortcut key `2` to start drawing\na line.\n\nClick on the start of the road on the map to start drawing. If the road\nbranches off from an existing road, start by clicking on the place where they connect.\n\nThen click on points along the road so that it follows the right path, according\nto satellite imagery or GPS. If the road you are drawing crosses another road, connect\nit by clicking on the intersection point. When you're done drawing, double-click\nor press 'Return' or 'Enter' on your keyboard.\n","gps":"# GPS\n\nCollected GPS traces are one valuable source of data for OpenStreetMap. This editor\nsupports local traces - `.gpx` files on your local computer. You can collect\nthis kind of GPS trace with a number of smartphone applications as well as\npersonal GPS hardware.\n\nFor information on how to perform a GPS survey, read\n[Mapping with a smartphone, GPS, or paper](http://learnosm.org/en/mobile-mapping/).\n\nTo use a GPX track for mapping, drag and drop the GPX file onto the map\neditor. If it's recognized, it will be added to the map as a bright purple\nline. Click on the 'Map Data' menu on the right side to enable,\ndisable, or zoom to this new GPX-powered layer.\n\nThe GPX track isn't directly uploaded to OpenStreetMap - the best way to\nuse it is to draw on the map, using it as a guide for the new features that\nyou add, and also to [upload it to OpenStreetMap](http://www.openstreetmap.org/trace/create)\nfor other users to use.\n","imagery":"# Imagery\n\nAerial imagery is an important resource for mapping. A combination of\nairplane flyovers, satellite views, and freely-compiled sources are available\nin the editor under the 'Background Settings' menu on the right.\n\nBy default a [Bing Maps](http://www.bing.com/maps/) satellite layer is\npresented in the editor, but as you pan and zoom the map to new geographical\nareas, new sources will become available. Some countries, like the United\nStates, France, and Denmark have very high-quality imagery available for some areas.\n\nImagery is sometimes offset from the map data because of a mistake on the\nimagery provider's side. If you see a lot of roads shifted from the background,\ndon't immediately move them all to match the background. Instead you can adjust\nthe imagery so that it matches the existing data by clicking 'Fix alignment' at\nthe bottom of the Background Settings UI.\n","addresses":"# Addresses\n\nAddresses are some of the most useful information for the map.\n\nAlthough addresses are often represented as parts of streets, in OpenStreetMap\nthey're recorded as attributes of buildings and places along streets.\n\nYou can add address information to places mapped as building outlines\nas well as those mapped as single points. The optimal source of address\ndata is from an on-the-ground survey or personal knowledge - as with any\nother feature, copying from commercial sources like Google Maps is strictly\nforbidden.\n","inspector":"# Using the Inspector\n\nThe inspector is the section on the left side of the page that allows you to\nedit the details of the selected feature.\n\n### Selecting a Feature Type\n\nAfter you add a point, line, or area, you can choose what type of feature it\nis, like whether it's a highway or residential road, supermarket or cafe.\nThe inspector will display buttons for common feature types, and you can\nfind others by typing what you're looking for in the search box.\n\nClick the 'i' in the bottom-right-hand corner of a feature type button to\nlearn more about it. Click a button to choose that type.\n\n### Using Forms and Editing Tags\n\nAfter you choose a feature type, or when you select a feature that already\nhas a type assigned, the inspector will display fields with details about\nthe feature like its name and address.\n\nBelow the fields you see, you can click the 'Add field' dropdown to add\nother details, like a Wikipedia link, wheelchair access, and more.\n\nAt the bottom of the inspector, click 'Additional tags' to add arbitrary\nother tags to the element. [Taginfo](http://taginfo.openstreetmap.org/) is a\ngreat resource for learn more about popular tag combinations.\n\nChanges you make in the inspector are automatically applied to the map.\nYou can undo them at any time by clicking the 'Undo' button.\n","buildings":"# Buildings\n\nOpenStreetMap is the world's largest database of buildings. You can create\nand improve this database.\n\n### Selecting\n\nYou can select a building by clicking on its border. This will highlight the\nbuilding and open a small tools menu and a sidebar showing more information\nabout the building.\n\n### Modifying\n\nSometimes buildings are incorrectly placed or have incorrect tags.\n\nTo move an entire building, select it, then click the 'Move' tool. Move your\nmouse to shift the building, and click when it's correctly placed.\n\nTo fix the specific shape of a building, click and drag the nodes that form\nits border into better places.\n\n### Creating\n\nOne of the main questions around adding buildings to the map is that\nOpenStreetMap records buildings both as shapes and points. The rule of thumb\nis to _map a building as a shape whenever possible_, and map companies, homes,\namenities, and other things that operate out of buildings as points placed\nwithin the building shape.\n\nStart drawing a building as a shape by clicking the 'Area' button in the top\nleft of the interface, and end it either by pressing 'Return' on your keyboard\nor clicking on the first node drawn to close the shape.\n\n### Deleting\n\nIf a building is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the building could simply be newly built.\n\nYou can delete a building by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n","relations":"# Relations\n\nA relation is a special type of feature in OpenStreetMap that groups together\nother features. For example, two common types of relations are *route relations*,\nwhich group together sections of road that belong to a specific freeway or\nhighway, and *multipolygons*, which group together several lines that define\na complex area (one with several pieces or holes in it like a donut).\n\nThe group of features in a relation are called *members*. In the sidebar, you can\nsee which relations a feature is a member of, and click on a relation there\nto select the it. When the relation is selected, you can see all of its\nmembers listed in the sidebar and highlighted on the map.\n\nFor the most part, iD will take care of maintaining relations automatically\nwhile you edit. The main thing you should be aware of is that if you delete a\nsection of road to redraw it more accurately, you should make sure that the\nnew section is a member of the same relations as the original.\n\n## Editing Relations\n\nIf you want to edit relations, here are the basics.\n\nTo add a feature to a relation, select the feature, click the \"+\" button in the\n\"All relations\" section of the sidebar, and select or type the name of the relation.\n\nTo create a new relation, select the first feature that should be a member,\nclick the \"+\" button in the \"All relations\" section, and select \"New relation...\".\n\nTo remove a feature from a relation, select the feature and click the trash\nbutton next to the relation you want to remove it from.\n\nYou can create multipolygons with holes using the \"Merge\" tool. Draw two areas (inner\nand outer), hold the Shift key and click on each of them to select them both, and then\nclick the \"Merge\" (+) button.\n"},"intro":{"done":"done","ok":"OK","graph":{"block_number":"<value for addr:block_number>","city":"Three Rivers","county":"<value for addr:county>","district":"<value for addr:district>","hamlet":"<value for addr:hamlet>","neighbourhood":"<value for addr:neighbourhood>","postcode":"49093","province":"<value for addr:province>","quarter":"<value for addr:quarter>","state":"MI","subdistrict":"<value for addr:subdistrict>","suburb":"<value for addr:suburb>","countrycode":"us","name":{"1st-avenue":"1st Avenue","2nd-avenue":"2nd Avenue","4th-avenue":"4th Avenue","5th-avenue":"5th Avenue","6th-avenue":"6th Avenue","6th-street":"6th Street","7th-avenue":"7th Avenue","8th-avenue":"8th Avenue","9th-avenue":"9th Avenue","10th-avenue":"10th Avenue","11th-avenue":"11th Avenue","12th-avenue":"12th Avenue","access-point-employment":"Access Point Employment","adams-street":"Adams Street","andrews-elementary-school":"Andrews Elementary School","andrews-street":"Andrews Street","armitage-street":"Armitage Street","barrows-school":"Barrows School","battle-street":"Battle Street","bennett-street":"Bennett Street","bowman-park":"Bowman Park","collins-drive":"Collins Drive","conrail-railroad":"Conrail Railroad","conservation-park":"Conservation Park","constantine-street":"Constantine Street","cushman-street":"Cushman Street","dollar-tree":"Dollar Tree","douglas-avenue":"Douglas Avenue","east-street":"East Street","elm-street":"Elm Street","flower-street":"Flower Street","foster-street":"Foster Street","french-street":"French Street","garden-street":"Garden Street","gem-pawnbroker":"Gem Pawnbroker","golden-finch-framing":"Golden Finch Framing","grant-avenue":"Grant Avenue","hoffman-pond":"Hoffman Pond","hoffman-street":"Hoffman Street","hook-avenue":"Hook Avenue","jefferson-street":"Jefferson Street","kelsey-street":"Kelsey Street","lafayette-park":"LaFayette Park","las-coffee-cafe":"L.A.'s Coffee Cafe","lincoln-avenue":"Lincoln Avenue","lowrys-books":"Lowry's Books","lynns-garage":"Lynn's Garage","main-street-barbell":"Main Street Barbell","main-street-cafe":"Main Street Cafe","main-street-fitness":"Main Street Fitness","main-street":"Main Street","maple-street":"Maple Street","marina-park":"Marina Park","market-street":"Market Street","memory-isle-park":"Memory Isle Park","memory-isle":"Memory Isle","michigan-avenue":"Michigan Avenue","middle-street":"Middle Street","millard-street":"Millard Street","moore-street":"Moore Street","morris-avenue":"Morris Avenue","mural-mall":"Mural Mall","paisanos-bar-and-grill":"Paisano's Bar and Grill","paisley-emporium":"Paisley Emporium","paparazzi-tattoo":"Paparazzi Tattoo","pealer-street":"Pealer Street","pine-street":"Pine Street","pizza-hut":"Pizza Hut","portage-avenue":"Portage Avenue","portage-river":"Portage River","preferred-insurance-services":"Preferred Insurance Services","railroad-drive":"Railroad Drive","river-city-appliance":"River City Appliance","river-drive":"River Drive","river-road":"River Road","river-street":"River Street","riverside-cemetery":"Riverside Cemetery","riverwalk-trail":"Riverwalk Trail","riviera-theatre":"Riviera Theatre","rocky-river":"Rocky River","saint-joseph-river":"Saint Joseph River","scidmore-park-petting-zoo":"Scidmore Park Petting Zoo","scidmore-park":"Scidmore Park","scouter-park":"Scouter Park","sherwin-williams":"Sherwin-Williams","south-street":"South Street","southern-michigan-bank":"Southern Michigan Bank","spring-street":"Spring Street","sturgeon-river-road":"Sturgeon River Road","three-rivers-city-hall":"Three Rivers City Hall","three-rivers-elementary-school":"Three Rivers Elementary School","three-rivers-fire-department":"Three Rivers Fire Department","three-rivers-high-school":"Three Rivers High School","three-rivers-middle-school":"Three Rivers Middle School","three-rivers-municipal-airport":"Three Rivers Municipal Airport","three-rivers-post-office":"Three Rivers Post Office","three-rivers-public-library":"Three Rivers Public Library","three-rivers":"Three Rivers","unique-jewelry":"Unique Jewelry","walnut-street":"Walnut Street","washington-street":"Washington Street","water-street":"Water Street","west-street":"West Street","wheeler-street":"Wheeler Street","william-towing":"William Towing","willow-drive":"Willow Drive","wood-street":"Wood Street","world-fare":"World Fare"}},"welcome":{"title":"Welcome","welcome":"Welcome! This walkthrough will teach you the basics of editing on OpenStreetMap.","practice":"All of the data in this walkthrough is just for practicing, and any edits that you make in the walkthrough will not be saved.","words":"This walkthrough will introduce some new words and concepts. When we introduce a new word, we'll use *italics*.","mouse":"You can use any input device to edit the map, but this walkthrough assumes you have a mouse with left and right buttons. **If you want to attach a mouse, do so now, then click OK.**","leftclick":"When this tutorial asks you to click or double-click, we mean with the left button. On a trackpad it might be a single-click or single-finger tap. **Left-click {num} times.**","rightclick":"Sometimes we'll also ask you to right-click. This might be the same as control-click, or two-finger tap on a trackpad. Your keyboard might even have a 'menu' key that works like right-click. **Right-click {num} times.**","chapters":"So far, so good! You can use the buttons below to skip chapters at any time or to restart a chapter if you get stuck. Let's begin! **Click '{next}' to continue.**"},"navigation":{"title":"Navigation","drag":"The main map area shows OpenStreetMap data on top of a background.{br}You can drag the map by pressing and holding the left mouse button while moving the mouse around. You can also use the arrow keys on your keyboard. **Drag the map!**","zoom":"You can zoom in or out by scrolling with the mouse wheel or trackpad, or by clicking the {plus} / {minus} buttons. **Zoom the map!**","features":"We use the word *features* to describe the things that appear on the map. Anything in the real world can be mapped as a feature on OpenStreetMap.","points_lines_areas":"Map features are represented using *points, lines, or areas.*","nodes_ways":"In OpenStreetMap, points are sometimes called *nodes*, and lines and areas are sometimes called *ways*.","click_townhall":"All features on the map can be selected by clicking on them. **Click on the point to select it.**","selected_townhall":"Great! The point is now selected. Selected features are drawn with a pulsing glow.","editor_townhall":"When a feature is selected, the *feature editor* is displayed alongside the map.","preset_townhall":"The top part of the feature editor shows the feature's type. This point is a {preset}.","fields_townhall":"The middle part of the feature editor contains *fields* showing the feature's attributes, such as its name and address.","close_townhall":"**Close the feature editor by hitting escape or pressing the {button} button in the upper corner.**","search_street":"You can also search for features in the current view, or worldwide. **Search for '{name}'.**","choose_street":"**Choose {name} from the list to select it.**","selected_street":"Great! {name} is now selected.","editor_street":"The fields shown for a street are different than the fields that were shown for the town hall.{br}For this selected street, the feature editor shows fields like '{field1}' and '{field2}'. **Close the feature editor by hitting escape or pressing the {button} button.**","play":"Try moving the map and clicking on some other features to see what kinds of things can be added to OpenStreetMap. **When you are ready to continue to the next chapter, click '{next}'.**"},"points":{"title":"Points","add_point":"*Points* can be used to represent features such as shops, restaurants, and monuments.{br}They mark a specific location, and describe what's there. **Click the {button} Point button to add a new point.**","place_point":"To place the new point on the map, position your mouse cursor where the point should go, then left-click or press the spacebar. **Move the mouse pointer over this building, then left-click or press the spacebar.**","search_cafe":"There are many different features that can be represented by points. The point you just added is a cafe. **Search for '{preset}'.**","choose_cafe":"**Choose {preset} from the list.**","feature_editor":"The point is now marked as a cafe. Using the feature editor, we can add more information about the cafe.","add_name":"In OpenStreetMap, all of the fields are optional, and it's OK to leave a field blank if you are unsure.{br}Let's pretend that you have local knowledge of this cafe, and you know its name. **Add a name for the cafe.**","add_close":"The feature editor will remember all of your changes automatically. **When you are finished adding the name, hit escape, return, 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, return, 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 return, 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, return, 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 return, 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 return, or clicking again on either the first or last node. **Finish tracing the tank.**","search_tank":"**Search for '{preset}'.**","choose_tank":"**Choose {preset} from the list.**","rightclick_tank":"**Right-click to select the storage tank you created and show the edit menu.**","circle_tank":"**Click on the {button} button to make the tank a circle.**","retry_circle":"You didn't click the Circularize button. Try again.","play":"Great Job! Practice tracing a few more buildings, and try some of the other commands on the edit menu. **When you are ready to continue to the next chapter, click '{next}'.**"},"startediting":{"title":"Start Editing","help":"You're now ready to edit OpenStreetMap!{br}You can replay this walkthrough anytime or view more documentation by clicking the {button} Help button.","save":"Don't forget to regularly save your changes!","start":"Start mapping!"}},"presets":{"categories":{"category-barrier":{"name":"Barrier Features"},"category-building":{"name":"Building Features"},"category-golf":{"name":"Golf Features"},"category-landuse":{"name":"Land Use Features"},"category-natural-area":{"name":"Natural Features"},"category-natural-line":{"name":"Natural Features"},"category-natural-point":{"name":"Natural Features"},"category-path":{"name":"Path Features"},"category-rail":{"name":"Rail Features"},"category-restriction":{"name":"Restriction Features"},"category-road":{"name":"Road Features"},"category-route":{"name":"Route Features"},"category-water-area":{"name":"Water Features"},"category-water-line":{"name":"Water Features"}},"fields":{"access_simple":{"label":"Allowed Access"},"access_toilets":{"label":"Access"},"access":{"label":"Allowed Access","placeholder":"Not Specified","types":{"access":"All","foot":"Foot","motor_vehicle":"Motor Vehicles","bicycle":"Bicycles","horse":"Horses"},"options":{"yes":{"title":"Allowed","description":"Access permitted by law; a right of way"},"no":{"title":"Prohibited","description":"Access not permitted to the general public"},"permissive":{"title":"Permissive","description":"Access permitted until such time as the owner revokes the permission"},"private":{"title":"Private","description":"Access permitted only with permission of the owner on an individual basis"},"designated":{"title":"Designated","description":"Access permitted according to signs or specific local laws"},"destination":{"title":"Destination","description":"Access permitted only to reach a destination"},"dismount":{"title":"Dismount","description":"Access permitted but rider must dismount"}}},"address":{"label":"Address","placeholders":{"block_number":"Block Number","block_number!jp":"Block No.","city":"City","city!jp":"City/Town/Village/Tokyo Special Ward","city!vn":"City/Town","conscriptionnumber":"123","country":"Country","county":"County","county!jp":"District","district":"District","district!vn":"Arrondissement/Town/District","floor":"Floor","hamlet":"Hamlet","housename":"Housename","housenumber":"123","housenumber!jp":"Building No./Lot No.","neighbourhood":"Neighbourhood","neighbourhood!jp":"Chōme/Aza/Koaza","place":"Place","postcode":"Postcode","province":"Province","province!jp":"Prefecture","quarter":"Quarter","quarter!jp":"Ōaza/Machi","state":"State","street":"Street","subdistrict":"Subdistrict","subdistrict!vn":"Ward/Commune/Townlet","suburb":"Suburb","suburb!jp":"Ward"}},"admin_level":{"label":"Admin Level"},"aerialway":{"label":"Type"},"aerialway/access":{"label":"Access","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aerialway/bubble":{"label":"Bubble"},"aerialway/capacity":{"label":"Capacity (per hour)","placeholder":"500, 2500, 5000..."},"aerialway/duration":{"label":"Duration (minutes)","placeholder":"1, 2, 3..."},"aerialway/heating":{"label":"Heated"},"aerialway/occupancy":{"label":"Occupancy","placeholder":"2, 4, 8..."},"aerialway/summer/access":{"label":"Access (summer)","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aeroway":{"label":"Type"},"amenity":{"label":"Type"},"animal_boarding":{"label":"For Animals"},"animal_breeding":{"label":"For Animals"},"animal_shelter":{"label":"For Animals"},"area/highway":{"label":"Type"},"artist":{"label":"Artist"},"artwork_type":{"label":"Type"},"atm":{"label":"ATM"},"backrest":{"label":"Backrest"},"barrier":{"label":"Type"},"bath/open_air":{"label":"Open Air"},"bath/sand_bath":{"label":"Sand Bath"},"bath/type":{"label":"Specialty","options":{"onsen":"Japanese Onsen","foot_bath":"Foot Bath","hot_spring":"Hot Spring"}},"beauty":{"label":"Shop Type"},"bench":{"label":"Bench"},"bicycle_parking":{"label":"Type"},"bin":{"label":"Waste Bin"},"blood_components":{"label":"Blood Components","options":{"whole":"whole blood","plasma":"plasma","platelets":"platelets","stemcells":"stem cell samples"}},"board_type":{"label":"Type"},"boundary":{"label":"Type"},"brand":{"label":"Brand"},"building_area":{"label":"Building"},"building":{"label":"Building"},"bunker_type":{"label":"Type"},"camera/direction":{"label":"Direction (Degrees Clockwise)","placeholder":"45, 90, 180, 270"},"camera/mount":{"label":"Camera Mount"},"camera/type":{"label":"Camera Type","options":{"fixed":"Fixed","panning":"Panning","dome":"Dome"}},"capacity":{"label":"Capacity","placeholder":"50, 100, 200..."},"cardinal_direction":{"label":"Direction","options":{"N":"North","E":"East","S":"South","W":"West","NE":"Northeast","SE":"Southeast","SW":"Southwest","NW":"Northwest","NNE":"North-northeast","ENE":"East-northeast","ESE":"East-southeast","SSE":"South-southeast","SSW":"South-southwest","WSW":"West-southwest","WNW":"West-northwest","NNW":"North-northwest"}},"castle_type":{"label":"Type"},"clock_direction":{"label":"Direction","options":{"clockwise":"Clockwise","anticlockwise":"Counterclockwise"}},"club":{"label":"Type"},"collection_times":{"label":"Collection Times"},"communication_multi":{"label":"Communication Types"},"construction":{"label":"Type"},"contact/webcam":{"label":"Webcam URL","placeholder":"http://example.com/"},"content":{"label":"Contents"},"country":{"label":"Country"},"covered":{"label":"Covered"},"craft":{"label":"Type"},"crop":{"label":"Crops"},"crossing":{"label":"Type"},"cuisine":{"label":"Cuisines"},"currency_multi":{"label":"Currency Types"},"cycle_network":{"label":"Network"},"cycleway":{"label":"Bike Lanes","placeholder":"none","types":{"cycleway:left":"Left side","cycleway:right":"Right side"},"options":{"none":{"title":"None","description":"No bike lane"},"lane":{"title":"Standard bike lane","description":"A bike lane separated from auto traffic by a painted line"},"shared_lane":{"title":"Shared bike lane","description":"A bike lane with no separation from auto traffic"},"track":{"title":"Bike track","description":"A bike lane separated from traffic by a physical barrier"},"share_busway":{"title":"Bike lane shared with bus","description":"A bike lane shared with a bus lane"},"opposite_lane":{"title":"Opposite bike lane","description":"A bike lane that travels in the opposite direction of traffic"},"opposite":{"title":"Contraflow bike lane","description":"A bike lane that travels in both directions on a one-way street"}}},"date":{"label":"Date"},"delivery":{"label":"Delivery"},"denomination":{"label":"Denomination"},"denotation":{"label":"Denotation"},"description":{"label":"Description"},"diaper":{"label":"Diaper Changing Available"},"display":{"label":"Display"},"dock":{"label":"Type"},"drive_through":{"label":"Drive-Through"},"electrified":{"label":"Electrification","placeholder":"Contact Line, Electrified Rail...","options":{"contact_line":"Contact Line","rail":"Electrified Rail","yes":"Yes (unspecified)","no":"No"}},"elevation":{"label":"Elevation"},"email":{"label":"Email","placeholder":"example@example.com"},"emergency":{"label":"Emergency"},"entrance":{"label":"Type"},"except":{"label":"Exceptions"},"fax":{"label":"Fax","placeholder":"+31 42 123 4567"},"fee":{"label":"Fee"},"fence_type":{"label":"Type"},"fire_hydrant/position":{"label":"Position","options":{"lane":"Lane","parking_lot":"Parking Lot","sidewalk":"Sidewalk","green":"Green"}},"fire_hydrant/type":{"label":"Type","options":{"pillar":"Pillar/Aboveground","underground":"Underground","wall":"Wall","pond":"Pond"}},"fixme":{"label":"Fix Me"},"fuel_multi":{"label":"Fuel Types"},"fuel":{"label":"Fuel"},"gauge":{"label":"Gauge"},"gender":{"label":"Gender","placeholder":"Unknown","options":{"male":"Male","female":"Female","unisex":"Unisex"}},"generator/method":{"label":"Method"},"generator/source":{"label":"Source"},"generator/type":{"label":"Type"},"golf_hole":{"label":"Reference","placeholder":"Hole number (1-18)"},"grape_variety":{"label":"Grape Varieties"},"handicap":{"label":"Handicap","placeholder":"1-18"},"handrail":{"label":"Handrail"},"height":{"label":"Height (Meters)"},"highway":{"label":"Type"},"historic":{"label":"Type"},"historic/civilization":{"label":"Historic Civilization"},"hoops":{"label":"Hoops","placeholder":"1, 2, 4..."},"iata":{"label":"IATA"},"icao":{"label":"ICAO"},"incline_steps":{"label":"Incline","options":{"up":"Up","down":"Down"}},"incline":{"label":"Incline"},"indoor":{"label":"Indoor"},"information":{"label":"Type"},"inscription":{"label":"Inscription"},"internet_access":{"label":"Internet Access","options":{"yes":"Yes","no":"No","wlan":"Wifi","wired":"Wired","terminal":"Terminal"}},"internet_access/fee":{"label":"Internet Access Fee"},"internet_access/ssid":{"label":"SSID (Network Name)"},"kerb":{"label":"Curb Ramp"},"lamp_type":{"label":"Type"},"landuse":{"label":"Type"},"lanes":{"label":"Lanes","placeholder":"1, 2, 3..."},"layer":{"label":"Layer"},"leaf_cycle_singular":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous"}},"leaf_cycle":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous","mixed":"Mixed"}},"leaf_type_singular":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","leafless":"Leafless"}},"leaf_type":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","mixed":"Mixed","leafless":"Leafless"}},"leisure":{"label":"Type"},"length":{"label":"Length (Meters)"},"level":{"label":"Level"},"levels":{"label":"Levels","placeholder":"2, 4, 6..."},"lit":{"label":"Lit"},"location":{"label":"Location"},"man_made":{"label":"Type"},"map_size":{"label":"Coverage"},"map_type":{"label":"Type"},"maxheight":{"label":"Max Height","placeholder":"4, 4.5, 5, 14'0\", 14'6\", 15'0\""},"maxspeed":{"label":"Speed Limit","placeholder":"40, 50, 60..."},"maxstay":{"label":"Max Stay"},"mtb/scale":{"label":"Mountain Biking Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Solid gravel/packed earth, no obstacles, wide curves","1":"1: Some loose surface, small obstacles, wide curves","2":"2: Much loose surface, large obstacles, easy hairpins","3":"3: Slippery surface, large obstacles, tight hairpins","4":"4: Loose surface or boulders, dangerous hairpins","5":"5: Maximum difficulty, boulder fields, landslides","6":"6: Not rideable except by the very best mountain bikers"}},"mtb/scale/imba":{"label":"IMBA Trail Difficulty","placeholder":"Easy, Medium, Difficult...","options":{"0":"Easiest (white circle)","1":"Easy (green circle)","2":"Medium (blue square)","3":"Difficult (black diamond)","4":"Extremely Difficult (double black diamond)"}},"mtb/scale/uphill":{"label":"Mountain Biking Uphill Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Avg. incline <10%, gravel/packed earth, no obstacles","1":"1: Avg. incline <15%, gravel/packed earth, few small objects","2":"2: Avg. incline <20%, stable surface, fistsize rocks/roots","3":"3: Avg. incline <25%, variable surface, fistsize rocks/branches","4":"4: Avg. incline <30%, poor condition, big rocks/branches","5":"5: Very steep, bike generally needs to be pushed or carried"}},"name":{"label":"Name","placeholder":"Common name (if any)"},"natural":{"label":"Natural"},"network_bicycle":{"label":"Network Type","placeholder":"Local, Regional, National, International","options":{"lcn":"Local","rcn":"Regional","ncn":"National","icn":"International"}},"network_foot":{"label":"Network Type","placeholder":"Local, Regional, National, International","options":{"lwn":"Local","rwn":"Regional","nwn":"National","iwn":"International"}},"network_horse":{"label":"Network Type","placeholder":"Local, Regional, National, International","options":{"lhn":"Local","rhn":"Regional","nhn":"National","ihn":"International"}},"network_road":{"label":"Network"},"network":{"label":"Network"},"note":{"label":"Note"},"office":{"label":"Type"},"oneway_yes":{"label":"One Way","options":{"undefined":"Assumed to be Yes","yes":"Yes","no":"No"}},"oneway":{"label":"One Way","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"opening_hours":{"label":"Hours"},"operator":{"label":"Operator"},"outdoor_seating":{"label":"Outdoor Seating"},"par":{"label":"Par","placeholder":"3, 4, 5..."},"parallel_direction":{"label":"Direction","options":{"forward":"Forward","backward":"Backward"}},"park_ride":{"label":"Park and Ride"},"parking":{"label":"Type","options":{"surface":"Surface","multi-storey":"Multilevel","underground":"Underground","sheds":"Sheds","carports":"Carports","garage_boxes":"Garage Boxes","lane":"Roadside Lane"}},"payment_multi":{"label":"Payment Types"},"phone":{"label":"Phone","placeholder":"+31 42 123 4567"},"piste/difficulty":{"label":"Difficulty","placeholder":"Easy, Intermediate, Advanced...","options":{"novice":"Novice (instructional)","easy":"Easy (green circle)","intermediate":"Intermediate (blue square)","advanced":"Advanced (black diamond)","expert":"Expert (double black diamond)","freeride":"Freeride (off-piste)","extreme":"Extreme (climbing equipment required)"}},"piste/grooming":{"label":"Grooming","options":{"classic":"Classic","mogul":"Mogul","backcountry":"Backcountry","classic+skating":"Classic and Skating","scooter":"Scooter/Snowmobile","skating":"Skating"}},"piste/type":{"label":"Type","options":{"downhill":"Downhill","nordic":"Nordic","skitour":"Skitour","sled":"Sled","hike":"Hike","sleigh":"Sleigh","ice_skate":"Ice Skate","snow_park":"Snow Park","playground":"Playground"}},"place":{"label":"Type"},"plant":{"label":"Plant"},"population":{"label":"Population"},"power_supply":{"label":"Power Supply"},"power":{"label":"Type"},"produce":{"label":"Produce"},"product":{"label":"Products"},"railway":{"label":"Type"},"recycling_accepts":{"label":"Accepts"},"recycling_type":{"label":"Recycling Type","options":{"container":"Container","centre":"Recycling Center"}},"ref":{"label":"Reference"},"relation":{"label":"Type"},"religion":{"label":"Religion"},"restriction":{"label":"Type"},"restrictions":{"label":"Turn Restrictions"},"rooms":{"label":"Rooms"},"route_master":{"label":"Type"},"route":{"label":"Type"},"sac_scale":{"label":"Hiking Difficulty","placeholder":"Mountain Hiking, Alpine Hiking...","options":{"hiking":"T1: Hiking","mountain_hiking":"T2: Mountain Hiking","demanding_mountain_hiking":"T3: Demanding Mountain Hiking","alpine_hiking":"T4: Alpine Hiking","demanding_alpine_hiking":"T5: Demanding Alpine Hiking","difficult_alpine_hiking":"T6: Difficult Alpine Hiking"}},"sanitary_dump_station":{"label":"Toilet Disposal"},"seasonal":{"label":"Seasonal"},"second_hand":{"label":"Sells Used","placeholder":"Yes, No, Only","options":{"yes":"Yes","no":"No","only":"Only"}},"service_rail":{"label":"Service Type","options":{"spur":"Spur","yard":"Yard","siding":"Siding","crossover":"Crossover"}},"service_times":{"label":"Service Times"},"service":{"label":"Type"},"service/bicycle":{"label":"Services"},"service/vehicle":{"label":"Services"},"shelter_type":{"label":"Type"},"shelter":{"label":"Shelter"},"shop":{"label":"Type"},"site":{"label":"Type"},"smoking":{"label":"Smoking","placeholder":"No, Separated, Yes...","options":{"no":"No smoking anywhere","separated":"In smoking areas, not physically isolated","isolated":"In smoking areas, physically isolated","outside":"Allowed outside","yes":"Allowed everywhere","dedicated":"Dedicated to smokers (e.g. smokers' club)"}},"smoothness":{"label":"Smoothness","placeholder":"Thin Rollers, Wheels, Off-Road...","options":{"excellent":"Thin Rollers: rollerblade, skateboard","good":"Thin Wheels: racing bike","intermediate":"Wheels: city bike, wheelchair, scooter","bad":"Robust Wheels: trekking bike, car, rickshaw","very_bad":"High Clearance: light duty off-road vehicle","horrible":"Off-Road: heavy duty off-road vehicle","very_horrible":"Specialized off-road: tractor, ATV","impassable":"Impassable / No wheeled vehicle"}},"social_facility_for":{"label":"People Served"},"social_facility":{"label":"Type"},"source":{"label":"Source"},"sport_ice":{"label":"Sports"},"sport_racing_motor":{"label":"Sports"},"sport_racing_nonmotor":{"label":"Sports"},"sport":{"label":"Sports"},"stars":{"label":"Stars"},"start_date":{"label":"Start Date"},"step_count":{"label":"Number of Steps"},"stop":{"label":"Stop Type","options":{"all":"All Ways","minor":"Minor Road"}},"structure":{"label":"Structure","placeholder":"Unknown","options":{"bridge":"Bridge","tunnel":"Tunnel","embankment":"Embankment","cutting":"Cutting","ford":"Ford"}},"studio":{"label":"Type"},"substation":{"label":"Type"},"supervised":{"label":"Supervised"},"support":{"label":"Support"},"surface":{"label":"Surface"},"surveillance":{"label":"Surveillance Kind"},"surveillance/type":{"label":"Surveillance Type","options":{"camera":"Camera","guard":"Guard","ALPR":"Automatic License Plate Reader"}},"surveillance/zone":{"label":"Surveillance Zone"},"tactile_paving":{"label":"Tactile Paving"},"takeaway":{"label":"Takeaway","placeholder":"Yes, No, Takeaway Only...","options":{"yes":"Yes","no":"No","only":"Takeaway Only"}},"toilets/disposal":{"label":"Disposal","options":{"flush":"Flush","pitlatrine":"Pit/Latrine","chemical":"Chemical","bucket":"Bucket"}},"toll":{"label":"Toll"},"tomb":{"label":"Type"},"tourism":{"label":"Type"},"tower/construction":{"label":"Construction","placeholder":"Guyed, Lattice, Concealed, ..."},"tower/type":{"label":"Type"},"tracktype":{"label":"Track Type","placeholder":"Solid, Mostly Solid, Soft...","options":{"grade1":"Solid: paved or heavily compacted hardcore surface","grade2":"Mostly Solid: gravel/rock with some soft material mixed in","grade3":"Even mixture of hard and soft materials","grade4":"Mostly Soft: soil/sand/grass with some hard material mixed in","grade5":"Soft: soil/sand/grass"}},"traffic_calming":{"label":"Type"},"traffic_signals":{"label":"Type"},"trail_visibility":{"label":"Trail Visibility","placeholder":"Excellent, Good, Bad...","options":{"excellent":"Excellent: unambiguous path or markers everywhere","good":"Good: markers visible, sometimes require searching","intermediate":"Intermediate: few markers, path mostly visible","bad":"Bad: no markers, path sometimes invisible/pathless","horrible":"Horrible: often pathless, some orientation skills required","no":"No: pathless, excellent orientation skills required"}},"trees":{"label":"Trees"},"tunnel":{"label":"Tunnel"},"vending":{"label":"Type of Goods"},"visibility":{"label":"Visibility","options":{"house":"Up to 5m (16ft)","street":"5 to 20m (16 to 65ft)","area":"Over 20m (65ft)"}},"wall":{"label":"Type"},"water_point":{"label":"Water Point"},"water":{"label":"Type"},"waterway":{"label":"Type"},"website":{"label":"Website","placeholder":"http://example.com/"},"wetland":{"label":"Type"},"wheelchair":{"label":"Wheelchair Access"},"width":{"label":"Width (Meters)"},"wikipedia":{"label":"Wikipedia"}},"presets":{"aerialway":{"name":"Aerialway","terms":"ski lift,funifor,funitel"},"aeroway":{"name":"Aeroway","terms":""},"amenity":{"name":"Amenity","terms":""},"highway":{"name":"Highway","terms":""},"place":{"name":"Place","terms":""},"power":{"name":"Power","terms":""},"railway":{"name":"Railway","terms":""},"roundabout":{"name":"Roundabout","terms":""},"waterway":{"name":"Waterway","terms":""},"address":{"name":"Address","terms":""},"advertising/billboard":{"name":"Billboard","terms":""},"aerialway/cable_car":{"name":"Cable Car","terms":"tramway,ropeway"},"aerialway/chair_lift":{"name":"Chair Lift","terms":""},"aerialway/drag_lift":{"name":"Drag Lift","terms":""},"aerialway/gondola":{"name":"Gondola","terms":""},"aerialway/goods":{"name":"Goods Aerialway","terms":""},"aerialway/magic_carpet":{"name":"Magic Carpet Lift","terms":""},"aerialway/mixed_lift":{"name":"Mixed Lift","terms":""},"aerialway/platter":{"name":"Platter Lift","terms":"button lift,poma lift"},"aerialway/pylon":{"name":"Aerialway Pylon","terms":""},"aerialway/rope_tow":{"name":"Rope Tow Lift","terms":"handle tow,bugel lift"},"aerialway/station":{"name":"Aerialway Station","terms":""},"aerialway/t-bar":{"name":"T-bar Lift","terms":""},"aeroway/aerodrome":{"name":"Airport","terms":"airplane,airport,aerodrome"},"aeroway/apron":{"name":"Apron","terms":"ramp"},"aeroway/gate":{"name":"Airport Gate","terms":""},"aeroway/hangar":{"name":"Hangar","terms":""},"aeroway/helipad":{"name":"Helipad","terms":"helicopter,helipad,heliport"},"aeroway/runway":{"name":"Runway","terms":"landing strip"},"aeroway/taxiway":{"name":"Taxiway","terms":""},"aeroway/terminal":{"name":"Airport Terminal","terms":"airport,aerodrome"},"amenity/coworking_space":{"name":"Coworking Space","terms":""},"amenity/nursing_home":{"name":"Nursing Home","terms":""},"amenity/register_office":{"name":"Register Office","terms":""},"amenity/swimming_pool":{"name":"Swimming Pool","terms":""},"amenity/animal_boarding":{"name":"Animal Boarding Facility","terms":"boarding,cat,dog,horse,kitten,pet boarding,pet care,pet hotel,puppy,reptile"},"amenity/animal_breeding":{"name":"Animal Breeding Facility","terms":"breeding,bull,cat,cow,dog,horse,husbandry,kitten,livestock,pet breeding,puppy,reptile"},"amenity/animal_shelter":{"name":"Animal Shelter","terms":"adoption,aspca,cat,dog,horse,kitten,pet care,pet rescue,puppy,raptor,reptile,rescue,spca"},"amenity/arts_centre":{"name":"Arts Center","terms":""},"amenity/atm":{"name":"ATM","terms":"money,cash,machine"},"amenity/bank":{"name":"Bank","terms":"credit union,check,deposit,fund,investment,repository,reserve,safe,savings,stock,treasury,trust,vault"},"amenity/bar":{"name":"Bar","terms":"dive,beer,bier,booze"},"amenity/bbq":{"name":"Barbecue/Grill","terms":"bbq,grill"},"amenity/bench":{"name":"Bench","terms":"seat"},"amenity/bicycle_parking":{"name":"Bicycle Parking","terms":"bike"},"amenity/bicycle_rental":{"name":"Bicycle Rental","terms":"bike"},"amenity/bicycle_repair_station":{"name":"Bicycle Repair Tool Stand","terms":"bike,repair,chain,pump"},"amenity/biergarten":{"name":"Beer Garden","terms":"beer,bier,booze"},"amenity/boat_rental":{"name":"Boat Rental","terms":""},"amenity/bureau_de_change":{"name":"Currency Exchange","terms":"bureau de change,money changer"},"amenity/bus_station":{"name":"Bus Station","terms":""},"amenity/cafe":{"name":"Cafe","terms":"bistro,coffee,tea"},"amenity/car_rental":{"name":"Car Rental","terms":""},"amenity/car_sharing":{"name":"Car Sharing","terms":""},"amenity/car_wash":{"name":"Car Wash","terms":""},"amenity/casino":{"name":"Casino","terms":"gambling,roulette,craps,poker,blackjack"},"amenity/charging_station":{"name":"Charging Station","terms":"EV,Electric Vehicle,Supercharger"},"amenity/childcare":{"name":"Nursery/Childcare","terms":"daycare,orphanage,playgroup"},"amenity/cinema":{"name":"Cinema","terms":"drive-in,film,flick,movie,theater,picture,show,screen"},"amenity/clinic":{"name":"Clinic","terms":"medical,urgentcare"},"amenity/clock":{"name":"Clock","terms":""},"amenity/college":{"name":"College Grounds","terms":"university"},"amenity/community_centre":{"name":"Community Center","terms":"event,hall"},"amenity/compressed_air":{"name":"Compressed Air","terms":""},"amenity/courthouse":{"name":"Courthouse","terms":""},"amenity/crematorium":{"name":"Crematorium","terms":"cemetery,funeral"},"amenity/dentist":{"name":"Dentist","terms":"tooth,teeth"},"amenity/doctors":{"name":"Doctor","terms":"medic*"},"amenity/dojo":{"name":"Dojo / Martial Arts Academy","terms":"martial arts,dojang"},"amenity/drinking_water":{"name":"Drinking Water","terms":"fountain,potable"},"amenity/driving_school":{"name":"Driving School","terms":""},"amenity/embassy":{"name":"Embassy","terms":""},"amenity/fast_food":{"name":"Fast Food","terms":"restaurant,takeaway"},"amenity/ferry_terminal":{"name":"Ferry Terminal","terms":""},"amenity/fire_station":{"name":"Fire Station","terms":""},"amenity/food_court":{"name":"Food Court","terms":"fast food,restaurant,food"},"amenity/fountain":{"name":"Fountain","terms":""},"amenity/fuel":{"name":"Gas Station","terms":"petrol,fuel,gasoline,propane,diesel,lng,cng,biodiesel"},"amenity/grave_yard":{"name":"Graveyard","terms":""},"amenity/grit_bin":{"name":"Grit Bin","terms":"salt,sand"},"amenity/hospital":{"name":"Hospital Grounds","terms":"clinic,doctor,emergency room,health,infirmary,institution,sanatorium,sanitarium,sick,surgery,ward"},"amenity/hunting_stand":{"name":"Hunting Stand","terms":"game,gun,lookout,rifle,shoot*,wild,watch"},"amenity/ice_cream":{"name":"Ice Cream Shop","terms":"gelato,sorbet,sherbet,frozen,yogurt"},"amenity/internet_cafe":{"name":"Internet Cafe","terms":"cybercafe,taxiphone,teleboutique,coffee,cafe,net,lanhouse"},"amenity/kindergarten":{"name":"Preschool/Kindergarten Grounds","terms":"kindergarden,pre-school"},"amenity/library":{"name":"Library","terms":"book"},"amenity/marketplace":{"name":"Marketplace","terms":""},"amenity/motorcycle_parking":{"name":"Motorcycle Parking","terms":""},"amenity/nightclub":{"name":"Nightclub","terms":"disco*,night club,dancing,dance club"},"amenity/parking_entrance":{"name":"Parking Garage Entrance/Exit","terms":""},"amenity/parking_space":{"name":"Parking Space","terms":""},"amenity/parking":{"name":"Car Parking","terms":""},"amenity/pavilion":{"name":"Pavilion","terms":""},"amenity/pharmacy":{"name":"Pharmacy","terms":"drug*,med*,prescription"},"amenity/place_of_worship":{"name":"Place of Worship","terms":"abbey,basilica,bethel,cathedral,chancel,chantry,chapel,church,fold,house of God,house of prayer,house of worship,minster,mission,mosque,oratory,parish,sacellum,sanctuary,shrine,synagogue,tabernacle,temple"},"amenity/place_of_worship/buddhist":{"name":"Buddhist Temple","terms":"stupa,vihara,monastery,temple,pagoda,zendo,dojo"},"amenity/place_of_worship/christian":{"name":"Church","terms":"christian,abbey,basilica,bethel,cathedral,chancel,chantry,chapel,fold,house of God,house of prayer,house of worship,minster,mission,oratory,parish,sacellum,sanctuary,shrine,tabernacle,temple"},"amenity/place_of_worship/jewish":{"name":"Synagogue","terms":"jewish"},"amenity/place_of_worship/muslim":{"name":"Mosque","terms":"muslim"},"amenity/planetarium":{"name":"Planetarium","terms":"museum,astronomy,observatory"},"amenity/police":{"name":"Police","terms":"badge,constable,constabulary,cop,detective,fed,law,enforcement,officer,patrol"},"amenity/post_box":{"name":"Mailbox","terms":"letter,post"},"amenity/post_office":{"name":"Post Office","terms":"letter,mail"},"amenity/prison":{"name":"Prison Grounds","terms":"cell,jail"},"amenity/pub":{"name":"Pub","terms":"alcohol,drink,dive,beer,bier,booze"},"amenity/public_bath":{"name":"Public Bath","terms":"onsen,foot bath,hot springs"},"amenity/public_bookcase":{"name":"Public Bookcase","terms":"library,bookcrossing"},"amenity/ranger_station":{"name":"Ranger Station","terms":"visitor center,visitor centre,permit center,permit centre,backcountry office,warden office,warden center"},"amenity/recycling_centre":{"name":"Recycling Center","terms":"bottle,can,dump,glass,garbage,rubbish,scrap,trash"},"amenity/recycling":{"name":"Recycling","terms":"bin,can,bottle,glass,garbage,rubbish,scrap,trash"},"amenity/restaurant":{"name":"Restaurant","terms":"bar,breakfast,cafe,café,canteen,coffee,dine,dining,dinner,drive-in,eat,grill,lunch,table"},"amenity/sanitary_dump_station":{"name":"RV Toilet Disposal","terms":"Motor Home,Camper,Sanitary,Dump Station,Elsan,CDP,CTDP,Chemical Toilet"},"amenity/school":{"name":"School Grounds","terms":"academy,elementary school,middle school,high school"},"amenity/shelter":{"name":"Shelter","terms":"lean-to,gazebo,picnic"},"amenity/social_facility":{"name":"Social Facility","terms":""},"amenity/social_facility/food_bank":{"name":"Food Bank","terms":""},"amenity/social_facility/group_home":{"name":"Elderly Group Home","terms":"old,senior,living"},"amenity/social_facility/homeless_shelter":{"name":"Homeless Shelter","terms":"houseless,unhoused,displaced"},"amenity/social_facility/nursing_home":{"name":"Nursing Home","terms":"elderly,living,nursing,old,senior"},"amenity/studio":{"name":"Studio","terms":"recording,radio,television"},"amenity/taxi":{"name":"Taxi Stand","terms":"cab"},"amenity/telephone":{"name":"Telephone","terms":"phone"},"amenity/theatre":{"name":"Theater","terms":"theatre,performance,play,musical"},"amenity/toilets":{"name":"Toilets","terms":"bathroom,restroom,outhouse,privy,head,lavatory,latrine,water closet,WC,W.C."},"amenity/townhall":{"name":"Town Hall","terms":"village,city,government,courthouse,municipal"},"amenity/university":{"name":"University Grounds","terms":"college"},"amenity/vending_machine":{"name":"Vending Machine","terms":""},"amenity/vending_machine/news_papers":{"name":"Newspaper Vending Machine","terms":"newspaper"},"amenity/vending_machine/cigarettes":{"name":"Cigarette Vending Machine","terms":"cigarette"},"amenity/vending_machine/condoms":{"name":"Condom Vending Machine","terms":"condom"},"amenity/vending_machine/drinks":{"name":"Drink Vending Machine","terms":"drink,soda,beverage,juice,pop"},"amenity/vending_machine/excrement_bags":{"name":"Excrement Bag Vending Machine","terms":"excrement bags,poop,dog,animal"},"amenity/vending_machine/newspapers":{"name":"Newspaper Vending Machine","terms":"newspaper"},"amenity/vending_machine/parcel_pickup_dropoff":{"name":"Parcel Pickup/Dropoff Vending Machine","terms":"parcel,mail,pickup"},"amenity/vending_machine/parking_tickets":{"name":"Parking Ticket Vending Machine","terms":"parking,ticket"},"amenity/vending_machine/public_transport_tickets":{"name":"Transit Ticket Vending Machine","terms":"bus,train,ferry,rail,ticket,transportation"},"amenity/vending_machine/sweets":{"name":"Snack Vending Machine","terms":"candy,gum,chip,pretzel,cookie,cracker"},"amenity/veterinary":{"name":"Veterinary","terms":"pet clinic,veterinarian,animal hospital,pet doctor"},"amenity/waste_basket":{"name":"Waste Basket","terms":"bin,garbage,rubbish,litter,trash"},"amenity/waste_disposal":{"name":"Garbage Dumpster","terms":"garbage,rubbish,litter,trash"},"amenity/waste_transfer_station":{"name":"Waste Transfer Station","terms":"dump,garbage,recycling,rubbish,scrap,trash"},"amenity/water_point":{"name":"RV Drinking Water","terms":""},"amenity/watering_place":{"name":"Animal Watering Place","terms":""},"area":{"name":"Area","terms":""},"area/highway":{"name":"Road Surface","terms":""},"barrier":{"name":"Barrier","terms":""},"barrier/entrance":{"name":"Entrance","terms":""},"barrier/block":{"name":"Block","terms":""},"barrier/bollard":{"name":"Bollard","terms":""},"barrier/border_control":{"name":"Border Control","terms":""},"barrier/cattle_grid":{"name":"Cattle Grid","terms":""},"barrier/city_wall":{"name":"City Wall","terms":""},"barrier/cycle_barrier":{"name":"Cycle Barrier","terms":""},"barrier/ditch":{"name":"Trench","terms":""},"barrier/fence":{"name":"Fence","terms":""},"barrier/gate":{"name":"Gate","terms":""},"barrier/hedge":{"name":"Hedge","terms":""},"barrier/kissing_gate":{"name":"Kissing Gate","terms":""},"barrier/lift_gate":{"name":"Lift Gate","terms":""},"barrier/retaining_wall":{"name":"Retaining Wall","terms":""},"barrier/stile":{"name":"Stile","terms":""},"barrier/toll_booth":{"name":"Toll Booth","terms":""},"barrier/wall":{"name":"Wall","terms":""},"boundary/administrative":{"name":"Administrative Boundary","terms":""},"building":{"name":"Building","terms":""},"building/bunker":{"name":"Bunker","terms":""},"building/entrance":{"name":"Entrance/Exit","terms":""},"building/train_station":{"name":"Train Station","terms":""},"building/apartments":{"name":"Apartments","terms":""},"building/barn":{"name":"Barn","terms":""},"building/cabin":{"name":"Cabin","terms":""},"building/cathedral":{"name":"Cathedral Building","terms":""},"building/chapel":{"name":"Chapel Building","terms":""},"building/church":{"name":"Church Building","terms":""},"building/college":{"name":"College Building","terms":"university"},"building/commercial":{"name":"Commercial Building","terms":""},"building/construction":{"name":"Building Under Construction","terms":""},"building/detached":{"name":"Detached House","terms":"home,single,family,residence,dwelling"},"building/dormitory":{"name":"Dormitory","terms":""},"building/garage":{"name":"Garage","terms":""},"building/garages":{"name":"Garages","terms":""},"building/greenhouse":{"name":"Greenhouse","terms":""},"building/hospital":{"name":"Hospital Building","terms":""},"building/hotel":{"name":"Hotel Building","terms":""},"building/house":{"name":"House","terms":"home,family,residence,dwelling"},"building/hut":{"name":"Hut","terms":""},"building/industrial":{"name":"Industrial Building","terms":""},"building/kindergarten":{"name":"Preschool/Kindergarten Building","terms":"kindergarden,pre-school"},"building/public":{"name":"Public Building","terms":""},"building/residential":{"name":"Residential Building","terms":""},"building/retail":{"name":"Retail Building","terms":""},"building/roof":{"name":"Roof","terms":""},"building/school":{"name":"School Building","terms":"academy,elementary school,middle school,high school"},"building/semidetached_house":{"name":"Semi-Detached House","terms":"home,double,duplex,twin,family,residence,dwelling"},"building/shed":{"name":"Shed","terms":""},"building/stable":{"name":"Stable","terms":""},"building/static_caravan":{"name":"Static Mobile Home","terms":""},"building/terrace":{"name":"Row Houses","terms":"home,terrace,brownstone,family,residence,dwelling"},"building/university":{"name":"University Building","terms":"college"},"building/warehouse":{"name":"Warehouse","terms":""},"camp_site/camp_pitch":{"name":"Camp Pitch","terms":"tent,rv"},"club":{"name":"Club","terms":"social"},"craft":{"name":"Craft","terms":""},"craft/jeweler":{"name":"Jeweler","terms":""},"craft/locksmith":{"name":"Locksmith","terms":""},"craft/optician":{"name":"Optician","terms":""},"craft/tailor":{"name":"Tailor","terms":"clothes,suit"},"craft/basket_maker":{"name":"Basket Maker","terms":""},"craft/beekeeper":{"name":"Beekeeper","terms":""},"craft/blacksmith":{"name":"Blacksmith","terms":""},"craft/boatbuilder":{"name":"Boat Builder","terms":""},"craft/bookbinder":{"name":"Bookbinder","terms":"book repair"},"craft/brewery":{"name":"Brewery","terms":"beer,bier"},"craft/carpenter":{"name":"Carpenter","terms":"woodworker"},"craft/carpet_layer":{"name":"Carpet Layer","terms":""},"craft/caterer":{"name":"Caterer","terms":""},"craft/clockmaker":{"name":"Clockmaker","terms":""},"craft/confectionery":{"name":"Confectionery","terms":"sweets,candy"},"craft/dressmaker":{"name":"Dressmaker","terms":"seamstress"},"craft/electrician":{"name":"Electrician","terms":"power,wire"},"craft/gardener":{"name":"Gardener","terms":"landscaper,grounds keeper"},"craft/glaziery":{"name":"Glaziery","terms":"glass,stained-glass,window"},"craft/handicraft":{"name":"Handicraft","terms":""},"craft/hvac":{"name":"HVAC","terms":"heat*,vent*,air conditioning"},"craft/insulator":{"name":"Insulator","terms":""},"craft/key_cutter":{"name":"Key Cutter","terms":""},"craft/metal_construction":{"name":"Metal Construction","terms":""},"craft/painter":{"name":"Painter","terms":""},"craft/photographer":{"name":"Photographer","terms":""},"craft/photographic_laboratory":{"name":"Photographic Laboratory","terms":"film"},"craft/plasterer":{"name":"Plasterer","terms":""},"craft/plumber":{"name":"Plumber","terms":"pipe"},"craft/pottery":{"name":"Pottery","terms":"ceramic"},"craft/rigger":{"name":"Rigger","terms":""},"craft/roofer":{"name":"Roofer","terms":""},"craft/saddler":{"name":"Saddler","terms":""},"craft/sailmaker":{"name":"Sailmaker","terms":""},"craft/sawmill":{"name":"Sawmill","terms":"lumber"},"craft/scaffolder":{"name":"Scaffolder","terms":""},"craft/sculpter":{"name":"Sculpter","terms":""},"craft/shoemaker":{"name":"Shoemaker","terms":"cobbler"},"craft/stonemason":{"name":"Stonemason","terms":"masonry"},"craft/sweep":{"name":"Chimney Sweep","terms":""},"craft/tiler":{"name":"Tiler","terms":""},"craft/tinsmith":{"name":"Tinsmith","terms":""},"craft/upholsterer":{"name":"Upholsterer","terms":""},"craft/watchmaker":{"name":"Watchmaker","terms":""},"craft/window_construction":{"name":"Window Construction","terms":"glass"},"craft/winery":{"name":"Winery","terms":""},"embankment":{"name":"Embankment","terms":""},"emergency/designated":{"name":"Emergency Access Designated","terms":""},"emergency/destination":{"name":"Emergency Access Destination","terms":""},"emergency/no":{"name":"Emergency Access No","terms":""},"emergency/official":{"name":"Emergency Access Official","terms":""},"emergency/private":{"name":"Emergency Access Private","terms":""},"emergency/yes":{"name":"Emergency Access Yes","terms":""},"emergency/ambulance_station":{"name":"Ambulance Station","terms":"EMS,EMT,rescue"},"emergency/defibrillator":{"name":"Defibrillator","terms":"AED"},"emergency/fire_hydrant":{"name":"Fire Hydrant","terms":"fire plug"},"emergency/phone":{"name":"Emergency Phone","terms":""},"entrance":{"name":"Entrance/Exit","terms":""},"footway/crossing":{"name":"Street Crossing","terms":""},"footway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"footway/sidewalk":{"name":"Sidewalk","terms":""},"ford":{"name":"Ford","terms":""},"golf/bunker":{"name":"Sand Trap","terms":"hazard,bunker"},"golf/fairway":{"name":"Fairway","terms":""},"golf/green":{"name":"Putting Green","terms":""},"golf/hole":{"name":"Golf Hole","terms":""},"golf/lateral_water_hazard_area":{"name":"Lateral Water Hazard","terms":""},"golf/lateral_water_hazard_line":{"name":"Lateral Water Hazard","terms":""},"golf/rough":{"name":"Rough","terms":""},"golf/tee":{"name":"Tee Box","terms":"teeing ground"},"golf/water_hazard_area":{"name":"Water Hazard","terms":""},"golf/water_hazard_line":{"name":"Water Hazard","terms":""},"healthcare/blood_donation":{"name":"Blood Donor Center","terms":"blood bank,blood donation,blood transfusion,apheresis,plasmapheresis,plateletpheresis,stem cell donation"},"highway/bridleway":{"name":"Bridle Path","terms":"bridleway,equestrian,horse"},"highway/bus_stop":{"name":"Bus Stop","terms":""},"highway/corridor":{"name":"Indoor Corridor","terms":"gallery,hall,hallway,indoor,passage,passageway"},"highway/crossing":{"name":"Street Crossing","terms":""},"highway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"highway/cycleway":{"name":"Cycle Path","terms":"bike"},"highway/footway":{"name":"Foot Path","terms":"hike,hiking,trackway,trail,walk"},"highway/give_way":{"name":"Yield Sign","terms":"give way,yield,sign"},"highway/living_street":{"name":"Living Street","terms":""},"highway/mini_roundabout":{"name":"Mini-Roundabout","terms":""},"highway/motorway_junction":{"name":"Motorway Junction / Exit","terms":""},"highway/motorway_link":{"name":"Motorway Link","terms":"ramp,on ramp,off ramp"},"highway/motorway":{"name":"Motorway","terms":"autobahn,expressway,freeway,highway,interstate,parkway,thruway,turnpike"},"highway/path":{"name":"Path","terms":"hike,hiking,trackway,trail,walk"},"highway/pedestrian":{"name":"Pedestrian Street","terms":""},"highway/primary_link":{"name":"Primary Link","terms":"ramp,on ramp,off ramp"},"highway/primary":{"name":"Primary Road","terms":""},"highway/raceway":{"name":"Racetrack (Motorsport)","terms":"auto*,formula one,kart,motocross,nascar,race*,track"},"highway/residential":{"name":"Residential Road","terms":""},"highway/rest_area":{"name":"Rest Area","terms":"rest stop"},"highway/road":{"name":"Unknown Road","terms":""},"highway/secondary_link":{"name":"Secondary Link","terms":"ramp,on ramp,off ramp"},"highway/secondary":{"name":"Secondary Road","terms":""},"highway/service":{"name":"Service Road","terms":""},"highway/service/alley":{"name":"Alley","terms":""},"highway/service/drive-through":{"name":"Drive-Through","terms":""},"highway/service/driveway":{"name":"Driveway","terms":""},"highway/service/emergency_access":{"name":"Emergency Access","terms":""},"highway/service/parking_aisle":{"name":"Parking Aisle","terms":""},"highway/services":{"name":"Service Area","terms":"services,travel plaza,service station"},"highway/speed_camera":{"name":"Speed Camera","terms":""},"highway/steps":{"name":"Steps","terms":"stairs,staircase"},"highway/stop":{"name":"Stop Sign","terms":"stop,halt,sign"},"highway/street_lamp":{"name":"Street Lamp","terms":"streetlight,street light,lamp,light,gaslight"},"highway/tertiary_link":{"name":"Tertiary Link","terms":"ramp,on ramp,off ramp"},"highway/tertiary":{"name":"Tertiary Road","terms":""},"highway/track":{"name":"Unmaintained Track Road","terms":"woods road,forest road,logging road,fire road,farm road,agricultural road,ranch road,carriage road,primitive,unmaintained,rut,offroad,4wd,4x4,four wheel drive,atv,quad,jeep,double track,two track"},"highway/traffic_mirror":{"name":"Traffic Mirror","terms":"blind spot,convex,corner,curved,roadside,round,safety,sphere,visibility"},"highway/traffic_signals":{"name":"Traffic Signals","terms":"light,stoplight,traffic light"},"highway/trunk_link":{"name":"Trunk Link","terms":"ramp,on ramp,off ramp"},"highway/trunk":{"name":"Trunk Road","terms":""},"highway/turning_circle":{"name":"Turning Circle","terms":"cul-de-sac"},"highway/turning_loop":{"name":"Turning Loop (Island)","terms":"cul-de-sac"},"highway/unclassified":{"name":"Minor/Unclassified Road","terms":""},"historic":{"name":"Historic Site","terms":""},"historic/archaeological_site":{"name":"Archaeological Site","terms":""},"historic/boundary_stone":{"name":"Boundary Stone","terms":""},"historic/castle":{"name":"Castle","terms":""},"historic/memorial":{"name":"Memorial","terms":""},"historic/monument":{"name":"Monument","terms":""},"historic/ruins":{"name":"Ruins","terms":""},"historic/tomb":{"name":"Tomb","terms":""},"historic/wayside_cross":{"name":"Wayside Cross","terms":""},"historic/wayside_shrine":{"name":"Wayside Shrine","terms":""},"junction":{"name":"Junction","terms":""},"landuse":{"name":"Land Use","terms":""},"landuse/farm":{"name":"Farmland","terms":""},"landuse/allotments":{"name":"Community Garden","terms":"allotment,garden"},"landuse/aquaculture":{"name":"Aquaculture","terms":"fish farm,crustacean,algae,aquafarming,shrimp farm,oyster farm,mariculture,algaculture"},"landuse/basin":{"name":"Basin","terms":""},"landuse/cemetery":{"name":"Cemetery","terms":""},"landuse/churchyard":{"name":"Churchyard","terms":""},"landuse/commercial":{"name":"Commercial Area","terms":""},"landuse/construction":{"name":"Construction","terms":""},"landuse/farmland":{"name":"Farmland","terms":"crop,grow,plant"},"landuse/farmyard":{"name":"Farmyard","terms":"crop,grow,plant"},"landuse/forest":{"name":"Forest","terms":"tree"},"landuse/garages":{"name":"Garages","terms":""},"landuse/grass":{"name":"Grass","terms":""},"landuse/harbour":{"name":"Harbor","terms":"boat"},"landuse/industrial":{"name":"Industrial Area","terms":""},"landuse/landfill":{"name":"Landfill","terms":"dump"},"landuse/meadow":{"name":"Meadow","terms":""},"landuse/military":{"name":"Military Area","terms":""},"landuse/military/airfield":{"name":"Military Airfield","terms":"air force,army,base,bomb,fight,force,guard,heli*,jet,marine,navy,plane,troop,war"},"landuse/military/barracks":{"name":"Barracks","terms":"air force,army,base,fight,force,guard,marine,navy,troop,war"},"landuse/military/bunker":{"name":"Military Bunker","terms":"air force,army,base,fight,force,guard,marine,navy,troop,war"},"landuse/military/checkpoint":{"name":"Checkpoint","terms":"air force,army,base,force,guard,marine,navy,troop,war"},"landuse/military/danger_area":{"name":"Danger Area","terms":"air force,army,base,blast,bomb,explo*,force,guard,mine,marine,navy,troop,war"},"landuse/military/naval_base":{"name":"Naval Base","terms":"base,fight,force,guard,marine,navy,ship,sub,troop,war"},"landuse/military/nuclear_explosion_site":{"name":"Nuclear Explosion Site","terms":"atom,blast,bomb,detonat*,nuke,site,test"},"landuse/military/obstacle_course":{"name":"Obstacle Course","terms":"army,base,force,guard,marine,navy,troop,war"},"landuse/military/office":{"name":"Military Office","terms":"air force,army,base,enlist,fight,force,guard,marine,navy,recruit,troop,war"},"landuse/military/range":{"name":"Military Range","terms":"air force,army,base,fight,fire,force,guard,gun,marine,navy,rifle,shoot*,snip*,train,troop,war"},"landuse/military/training_area":{"name":"Training Area","terms":"air force,army,base,fight,fire,force,guard,gun,marine,navy,rifle,shoot*,snip*,train,troop,war"},"landuse/orchard":{"name":"Orchard","terms":"fruit"},"landuse/plant_nursery":{"name":"Plant Nursery","terms":"flower,garden,grow,vivero"},"landuse/quarry":{"name":"Quarry","terms":""},"landuse/railway":{"name":"Railway Corridor","terms":"rail,train,track"},"landuse/recreation_ground":{"name":"Recreation Ground","terms":"playing fields"},"landuse/residential":{"name":"Residential Area","terms":""},"landuse/retail":{"name":"Retail Area","terms":""},"landuse/vineyard":{"name":"Vineyard","terms":"grape,wine"},"leisure":{"name":"Leisure","terms":""},"leisure/adult_gaming_centre":{"name":"Adult Gaming Center","terms":"gambling,slot machine"},"leisure/bird_hide":{"name":"Bird Hide","terms":"machan,ornithology"},"leisure/bowling_alley":{"name":"Bowling Alley","terms":""},"leisure/common":{"name":"Common","terms":"open space"},"leisure/dance":{"name":"Dance Hall","terms":"ballroom,jive,swing,tango,waltz"},"leisure/dog_park":{"name":"Dog Park","terms":""},"leisure/firepit":{"name":"Firepit","terms":"fireplace,campfire"},"leisure/fitness_centre":{"name":"Gym / Fitness Center","terms":"health,gym,leisure,studio"},"leisure/fitness_centre/yoga":{"name":"Yoga Studio","terms":"studio"},"leisure/fitness_station":{"name":"Outdoor Fitness Station","terms":"fitness,gym"},"leisure/garden":{"name":"Garden","terms":""},"leisure/golf_course":{"name":"Golf Course","terms":"links"},"leisure/horse_riding":{"name":"Horseback Riding Facility","terms":"equestrian,stable"},"leisure/ice_rink":{"name":"Ice Rink","terms":"hockey,skating,curling"},"leisure/marina":{"name":"Marina","terms":"boat"},"leisure/miniature_golf":{"name":"Miniature Golf","terms":"crazy golf,mini golf,putt-putt"},"leisure/nature_reserve":{"name":"Nature Reserve","terms":"protected,wildlife"},"leisure/park":{"name":"Park","terms":"esplanade,estate,forest,garden,grass,green,grounds,lawn,lot,meadow,parkland,place,playground,plaza,pleasure garden,recreation area,square,tract,village green,woodland"},"leisure/picnic_table":{"name":"Picnic Table","terms":"bench"},"leisure/pitch":{"name":"Sport Pitch","terms":"field"},"leisure/pitch/american_football":{"name":"American Football Field","terms":""},"leisure/pitch/baseball":{"name":"Baseball Diamond","terms":""},"leisure/pitch/basketball":{"name":"Basketball Court","terms":""},"leisure/pitch/beachvolleyball":{"name":"Beach Volleyball Court","terms":"volleyball"},"leisure/pitch/bowls":{"name":"Bowling Green","terms":""},"leisure/pitch/cricket":{"name":"Cricket Field","terms":""},"leisure/pitch/equestrian":{"name":"Riding Arena","terms":"dressage,equestrian,horse,horseback,riding"},"leisure/pitch/rugby_league":{"name":"Rugby League Field","terms":""},"leisure/pitch/rugby_union":{"name":"Rugby Union Field","terms":""},"leisure/pitch/skateboard":{"name":"Skate Park","terms":""},"leisure/pitch/soccer":{"name":"Soccer Field","terms":""},"leisure/pitch/table_tennis":{"name":"Ping Pong Table","terms":"table tennis,ping pong"},"leisure/pitch/tennis":{"name":"Tennis Court","terms":""},"leisure/pitch/volleyball":{"name":"Volleyball Court","terms":""},"leisure/playground":{"name":"Playground","terms":"jungle gym,play area"},"leisure/resort":{"name":"Resort","terms":""},"leisure/running_track":{"name":"Racetrack (Running)","terms":"race*,running,sprint,track"},"leisure/slipway":{"name":"Slipway","terms":"boat launch,boat ramp"},"leisure/sports_centre":{"name":"Sports Center / Complex","terms":""},"leisure/sports_centre/swimming":{"name":"Swimming Pool Facility","terms":"dive,water"},"leisure/stadium":{"name":"Stadium","terms":""},"leisure/swimming_pool":{"name":"Swimming Pool","terms":"dive,water"},"leisure/track":{"name":"Racetrack (Non-Motorsport)","terms":"cycle,dog,greyhound,horse,race*,track"},"leisure/water_park":{"name":"Water Park","terms":"swim,pool,dive"},"line":{"name":"Line","terms":""},"man_made":{"name":"Man Made","terms":""},"man_made/embankment":{"name":"Embankment","terms":""},"man_made/adit":{"name":"Adit","terms":"entrance,underground,mine,cave"},"man_made/breakwater":{"name":"Breakwater","terms":""},"man_made/bridge":{"name":"Bridge","terms":""},"man_made/chimney":{"name":"Chimney","terms":""},"man_made/cutline":{"name":"Cut line","terms":""},"man_made/flagpole":{"name":"Flagpole","terms":""},"man_made/gasometer":{"name":"Gasometer","terms":"gas holder"},"man_made/groyne":{"name":"Groyne","terms":""},"man_made/lighthouse":{"name":"Lighthouse","terms":""},"man_made/mast":{"name":"Mast","terms":"antenna,broadcast tower,cell phone tower,cell tower,communication mast,communication tower,guyed tower,mobile phone tower,radio mast,radio tower,television tower,transmission mast,transmission tower,tv tower"},"man_made/observation":{"name":"Observation Tower","terms":"lookout tower,fire tower"},"man_made/petroleum_well":{"name":"Oil Well","terms":"drilling rig,oil derrick,oil drill,oil horse,oil rig,oil pump,petroleum well,pumpjack"},"man_made/pier":{"name":"Pier","terms":"dock"},"man_made/pipeline":{"name":"Pipeline","terms":""},"man_made/pumping_station":{"name":"Pumping Station","terms":""},"man_made/silo":{"name":"Silo","terms":"grain,corn,wheat"},"man_made/storage_tank":{"name":"Storage Tank","terms":"water,oil,gas,petrol"},"man_made/surveillance_camera":{"name":"Surveillance Camera","terms":"anpr,alpr,camera,car plate recognition,cctv,guard,license plate recognition,monitoring,number plate recognition,security,video,webcam"},"man_made/surveillance":{"name":"Surveillance","terms":"anpr,alpr,camera,car plate recognition,cctv,guard,license plate recognition,monitoring,number plate recognition,security,video,webcam"},"man_made/survey_point":{"name":"Survey Point","terms":""},"man_made/tower":{"name":"Tower","terms":""},"man_made/wastewater_plant":{"name":"Wastewater Plant","terms":"sewage*,water treatment plant,reclamation plant"},"man_made/water_tower":{"name":"Water Tower","terms":""},"man_made/water_well":{"name":"Water Well","terms":""},"man_made/water_works":{"name":"Water Works","terms":""},"man_made/works":{"name":"Factory","terms":"assembly,build,brewery,car,plant,plastic,processing,manufacture,refinery"},"natural":{"name":"Natural","terms":""},"natural/bare_rock":{"name":"Bare Rock","terms":"rock"},"natural/bay":{"name":"Bay","terms":""},"natural/beach":{"name":"Beach","terms":"shore"},"natural/cave_entrance":{"name":"Cave Entrance","terms":"cavern,hollow,grotto,shelter,cavity"},"natural/cliff":{"name":"Cliff","terms":"escarpment"},"natural/coastline":{"name":"Coastline","terms":"shore"},"natural/fell":{"name":"Fell","terms":""},"natural/glacier":{"name":"Glacier","terms":""},"natural/grassland":{"name":"Grassland","terms":"prairie,savanna"},"natural/heath":{"name":"Heath","terms":""},"natural/peak":{"name":"Peak","terms":"acme,aiguille,alp,climax,crest,crown,hill,mount,mountain,pinnacle,summit,tip,top"},"natural/ridge":{"name":"Ridge","terms":"crest"},"natural/saddle":{"name":"Saddle","terms":"pass,mountain pass,top"},"natural/sand":{"name":"Sand","terms":"desert"},"natural/scree":{"name":"Scree","terms":"loose rocks"},"natural/scrub":{"name":"Scrub","terms":"bush,shrubs"},"natural/spring":{"name":"Spring","terms":""},"natural/tree_row":{"name":"Tree row","terms":""},"natural/tree":{"name":"Tree","terms":""},"natural/volcano":{"name":"Volcano","terms":"mountain,crater"},"natural/water":{"name":"Water","terms":""},"natural/water/lake":{"name":"Lake","terms":"lakelet,loch,mere"},"natural/water/pond":{"name":"Pond","terms":"lakelet,millpond,tarn,pool,mere"},"natural/water/reservoir":{"name":"Reservoir","terms":""},"natural/wetland":{"name":"Wetland","terms":""},"natural/wood":{"name":"Wood","terms":"tree"},"noexit/yes":{"name":"No Exit","terms":"no exit,road end,dead end"},"office":{"name":"Office","terms":""},"office/travel_agent":{"name":"Travel Agency","terms":""},"office/accountant":{"name":"Accountant","terms":""},"office/administrative":{"name":"Administrative Office","terms":""},"office/architect":{"name":"Architect","terms":""},"office/company":{"name":"Company Office","terms":""},"office/coworking":{"name":"Coworking Space","terms":"coworking,office"},"office/educational_institution":{"name":"Educational Institution","terms":""},"office/employment_agency":{"name":"Employment Agency","terms":"job"},"office/estate_agent":{"name":"Real Estate Office","terms":""},"office/financial":{"name":"Financial Office","terms":""},"office/government":{"name":"Government Office","terms":""},"office/government/register_office":{"name":"Register Office","terms":"clerk,marriage,death,birth,certificate"},"office/insurance":{"name":"Insurance Office","terms":""},"office/it":{"name":"IT Office","terms":""},"office/lawyer":{"name":"Law Office","terms":""},"office/lawyer/notary":{"name":"Notary Office","terms":"clerk,signature,wills,deeds,estate"},"office/newspaper":{"name":"Newspaper","terms":""},"office/ngo":{"name":"NGO Office","terms":""},"office/physician":{"name":"Physician","terms":""},"office/political_party":{"name":"Political Party","terms":""},"office/research":{"name":"Research Office","terms":""},"office/telecommunication":{"name":"Telecom Office","terms":""},"office/therapist":{"name":"Therapist","terms":""},"piste":{"name":"Piste/Ski Trail","terms":"ski,sled,sleigh,snowboard,nordic,downhill,snowmobile"},"place/farm":{"name":"Farm","terms":""},"place/city":{"name":"City","terms":""},"place/hamlet":{"name":"Hamlet","terms":""},"place/island":{"name":"Island","terms":"archipelago,atoll,bar,cay,isle,islet,key,reef"},"place/isolated_dwelling":{"name":"Isolated Dwelling","terms":""},"place/locality":{"name":"Locality","terms":""},"place/neighbourhood":{"name":"Neighborhood","terms":"neighbourhood"},"place/quarter":{"name":"Sub-Borough / Quarter","terms":"boro,borough,quarter"},"place/square":{"name":"Square","terms":""},"place/suburb":{"name":"Borough / Suburb","terms":"boro,borough,quarter"},"place/town":{"name":"Town","terms":""},"place/village":{"name":"Village","terms":""},"point":{"name":"Point","terms":""},"power/sub_station":{"name":"Substation","terms":""},"power/generator":{"name":"Power Generator","terms":""},"power/line":{"name":"Power Line","terms":""},"power/minor_line":{"name":"Minor Power Line","terms":""},"power/plant":{"name":"Power Station Grounds","terms":"coal,gas,generat*,hydro,nuclear,power,station"},"power/pole":{"name":"Power Pole","terms":""},"power/substation":{"name":"Substation","terms":""},"power/tower":{"name":"High-Voltage Tower","terms":""},"power/transformer":{"name":"Transformer","terms":""},"public_transport/platform":{"name":"Platform","terms":""},"public_transport/stop_position":{"name":"Stop Position","terms":""},"railway/abandoned":{"name":"Abandoned Railway","terms":""},"railway/crossing":{"name":"Railway Crossing (Path)","terms":"crossing,pedestrian crossing,railroad crossing,level crossing,grade crossing,path through railroad,train crossing"},"railway/disused":{"name":"Disused Railway","terms":""},"railway/funicular":{"name":"Funicular","terms":"venicular,cliff railway,cable car,cable railway,funicular railway"},"railway/halt":{"name":"Railway Halt","terms":"break,interrupt,rest,wait,interruption"},"railway/level_crossing":{"name":"Railway Crossing (Road)","terms":"crossing,railroad crossing,level crossing,grade crossing,road through railroad,train crossing"},"railway/monorail":{"name":"Monorail","terms":""},"railway/narrow_gauge":{"name":"Narrow Gauge Rail","terms":"narrow gauge railway,narrow gauge railroad"},"railway/platform":{"name":"Railway Platform","terms":""},"railway/rail":{"name":"Rail","terms":""},"railway/station":{"name":"Railway Station","terms":"train station,station"},"railway/subway_entrance":{"name":"Subway Entrance","terms":""},"railway/subway":{"name":"Subway","terms":""},"railway/tram_stop":{"name":"Tram Stop","terms":"light rail,streetcar,tram,trolley"},"railway/tram":{"name":"Tram","terms":"light rail,streetcar,tram,trolley"},"relation":{"name":"Relation","terms":""},"route/ferry":{"name":"Ferry Route","terms":""},"shop":{"name":"Shop","terms":""},"shop/fishmonger":{"name":"Fishmonger","terms":""},"shop/vacant":{"name":"Vacant Shop","terms":""},"shop/alcohol":{"name":"Liquor Store","terms":"alcohol,beer,booze,wine"},"shop/anime":{"name":"Anime Shop","terms":"manga,japan,cosplay,figurine,dakimakura"},"shop/antiques":{"name":"Antiques Shop","terms":""},"shop/art":{"name":"Art Store","terms":"art*,exhibit*,gallery"},"shop/baby_goods":{"name":"Baby Goods Store","terms":""},"shop/bag":{"name":"Bag/Luggage Store","terms":"handbag,purse"},"shop/bakery":{"name":"Bakery","terms":""},"shop/bathroom_furnishing":{"name":"Bathroom Furnishing Store","terms":""},"shop/beauty":{"name":"Beauty Shop","terms":"spa,salon,tanning"},"shop/beauty/nails":{"name":"Nail Salon","terms":"manicure,pedicure"},"shop/beauty/tanning":{"name":"Tanning Salon","terms":""},"shop/bed":{"name":"Bedding/Mattress Store","terms":""},"shop/beverages":{"name":"Beverage Store","terms":""},"shop/bicycle":{"name":"Bicycle Shop","terms":"bike,repair"},"shop/bookmaker":{"name":"Bookmaker","terms":"betting"},"shop/books":{"name":"Book Store","terms":""},"shop/boutique":{"name":"Boutique","terms":""},"shop/butcher":{"name":"Butcher","terms":"meat"},"shop/candles":{"name":"Candle Shop","terms":""},"shop/car_parts":{"name":"Car Parts Store","terms":"auto"},"shop/car_repair":{"name":"Car Repair Shop","terms":"auto,garage,service"},"shop/car":{"name":"Car Dealership","terms":"auto"},"shop/carpet":{"name":"Carpet Store","terms":"rug"},"shop/charity":{"name":"Charity Store","terms":"thrift,op shop,nonprofit"},"shop/cheese":{"name":"Cheese Store","terms":""},"shop/chemist":{"name":"Drugstore","terms":"med*,drug*,gift"},"shop/chocolate":{"name":"Chocolate Store","terms":""},"shop/clothes":{"name":"Clothing Store","terms":""},"shop/coffee":{"name":"Coffee Store","terms":""},"shop/computer":{"name":"Computer Store","terms":""},"shop/confectionery":{"name":"Candy Store","terms":""},"shop/convenience":{"name":"Convenience Store","terms":""},"shop/copyshop":{"name":"Copy Store","terms":""},"shop/cosmetics":{"name":"Cosmetics Store","terms":""},"shop/craft":{"name":"Arts and Crafts Store","terms":"art*,paint*,frame"},"shop/curtain":{"name":"Curtain Store","terms":"drape*,window"},"shop/dairy":{"name":"Dairy Store","terms":"milk,egg,cheese"},"shop/deli":{"name":"Deli","terms":"lunch,meat,sandwich"},"shop/department_store":{"name":"Department Store","terms":""},"shop/doityourself":{"name":"DIY Store","terms":""},"shop/dry_cleaning":{"name":"Dry Cleaner","terms":""},"shop/e-cigarette":{"name":"E-Cigarette Shop","terms":"electronic,vapor"},"shop/electronics":{"name":"Electronics Store","terms":"appliance,audio,computer,tv"},"shop/erotic":{"name":"Erotic Store","terms":"sex,porn"},"shop/fabric":{"name":"Fabric Store","terms":"sew"},"shop/farm":{"name":"Produce Stand","terms":"farm shop,farm stand"},"shop/fashion":{"name":"Fashion Store","terms":""},"shop/florist":{"name":"Florist","terms":"flower"},"shop/frame":{"name":"Framing Shop","terms":"art*,paint*,photo*,frame"},"shop/funeral_directors":{"name":"Funeral Home","terms":"undertaker,memorial home"},"shop/furnace":{"name":"Furnace Store","terms":"oven,stove"},"shop/furniture":{"name":"Furniture Store","terms":"chair,sofa,table"},"shop/garden_centre":{"name":"Garden Center","terms":"landscape,mulch,shrub,tree"},"shop/gas":{"name":"Bottled Gas Shop","terms":"cng,lpg,natural gas,propane,refill,tank"},"shop/gift":{"name":"Gift Shop","terms":"souvenir"},"shop/greengrocer":{"name":"Greengrocer","terms":"fruit,vegetable"},"shop/hairdresser":{"name":"Hairdresser","terms":"barber"},"shop/hardware":{"name":"Hardware Store","terms":""},"shop/hearing_aids":{"name":"Hearing Aids Store","terms":""},"shop/herbalist":{"name":"Herbalist","terms":""},"shop/hifi":{"name":"Hifi Store","terms":"stereo,video"},"shop/houseware":{"name":"Houseware Store","terms":"home,household"},"shop/interior_decoration":{"name":"Interior Decoration Store","terms":""},"shop/jewelry":{"name":"Jeweler","terms":"diamond,gem,ring"},"shop/kiosk":{"name":"News Kiosk","terms":""},"shop/kitchen":{"name":"Kitchen Design Store","terms":""},"shop/laundry":{"name":"Laundry","terms":""},"shop/leather":{"name":"Leather Store","terms":""},"shop/locksmith":{"name":"Locksmith","terms":"key,lockpick"},"shop/lottery":{"name":"Lottery Shop","terms":""},"shop/mall":{"name":"Mall","terms":"shopping"},"shop/massage":{"name":"Massage Shop","terms":""},"shop/medical_supply":{"name":"Medical Supply Store","terms":""},"shop/mobile_phone":{"name":"Mobile Phone Store","terms":""},"shop/money_lender":{"name":"Money Lender","terms":""},"shop/motorcycle":{"name":"Motorcycle Dealership","terms":"bike"},"shop/music":{"name":"Music Store","terms":"CD,vinyl"},"shop/musical_instrument":{"name":"Musical Instrument Store","terms":"guitar"},"shop/newsagent":{"name":"Newspaper/Magazine Shop","terms":""},"shop/nutrition_supplements":{"name":"Nutrition Supplements Store","terms":""},"shop/optician":{"name":"Optician","terms":"eye,glasses"},"shop/organic":{"name":"Organic Goods Store","terms":""},"shop/outdoor":{"name":"Outdoors Store","terms":"camping,climbing,hiking"},"shop/paint":{"name":"Paint Store","terms":""},"shop/pastry":{"name":"Pastry Shop","terms":"patisserie,cake shop,cakery"},"shop/pawnbroker":{"name":"Pawn Shop","terms":""},"shop/perfumery":{"name":"Perfume Store","terms":""},"shop/pet":{"name":"Pet Store","terms":"animal,cat,dog,fish,kitten,puppy,reptile"},"shop/photo":{"name":"Photography Store","terms":"camera,film"},"shop/pyrotechnics":{"name":"Fireworks Store","terms":""},"shop/radiotechnics":{"name":"Radio/Electronic Component Store","terms":""},"shop/religion":{"name":"Religious Store","terms":""},"shop/scuba_diving":{"name":"Scuba Diving Shop","terms":""},"shop/seafood":{"name":"Seafood Shop","terms":"fishmonger"},"shop/second_hand":{"name":"Consignment/Thrift Store","terms":"secondhand,second hand,resale,thrift,used"},"shop/shoes":{"name":"Shoe Store","terms":""},"shop/sports":{"name":"Sporting Goods Store","terms":""},"shop/stationery":{"name":"Stationery Store","terms":"card,paper"},"shop/storage_rental":{"name":"Storage Rental","terms":""},"shop/supermarket":{"name":"Supermarket","terms":"grocery,store,shop"},"shop/tailor":{"name":"Tailor","terms":"clothes,suit"},"shop/tattoo":{"name":"Tattoo Parlor","terms":""},"shop/tea":{"name":"Tea Store","terms":""},"shop/ticket":{"name":"Ticket Seller","terms":""},"shop/tobacco":{"name":"Tobacco Shop","terms":""},"shop/toys":{"name":"Toy Store","terms":""},"shop/travel_agency":{"name":"Travel Agency","terms":""},"shop/tyres":{"name":"Tire Store","terms":""},"shop/vacuum_cleaner":{"name":"Vacuum Cleaner Store","terms":""},"shop/variety_store":{"name":"Variety Store","terms":""},"shop/video_games":{"name":"Video Game Store","terms":""},"shop/video":{"name":"Video Store","terms":"DVD"},"shop/watches":{"name":"Watches Shop","terms":""},"shop/water_sports":{"name":"Watersport/Swim Shop","terms":""},"shop/weapons":{"name":"Weapon Shop","terms":"ammo,gun,knife,knives"},"shop/window_blind":{"name":"Window Blind Store","terms":""},"shop/wine":{"name":"Wine Shop","terms":""},"tourism":{"name":"Tourism","terms":""},"tourism/alpine_hut":{"name":"Alpine Hut","terms":""},"tourism/apartment":{"name":"Guest Apartment / Condo","terms":""},"tourism/aquarium":{"name":"Aquarium","terms":"fish,sea,water"},"tourism/artwork":{"name":"Artwork","terms":"mural,sculpture,statue"},"tourism/attraction":{"name":"Tourist Attraction","terms":""},"tourism/camp_site":{"name":"Campground","terms":"tent,rv"},"tourism/caravan_site":{"name":"RV Park","terms":"Motor Home,Camper"},"tourism/chalet":{"name":"Chalet","terms":""},"tourism/gallery":{"name":"Art Gallery","terms":"art*,exhibit*,paint*,photo*,sculpt*"},"tourism/guest_house":{"name":"Guest House","terms":"B&B,Bed and Breakfast"},"tourism/hostel":{"name":"Hostel","terms":""},"tourism/hotel":{"name":"Hotel","terms":""},"tourism/information":{"name":"Information","terms":""},"tourism/information/board":{"name":"Information Board","terms":""},"tourism/information/guidepost":{"name":"Guidepost","terms":""},"tourism/information/map":{"name":"Map","terms":""},"tourism/information/office":{"name":"Tourist Information Office","terms":""},"tourism/motel":{"name":"Motel","terms":""},"tourism/museum":{"name":"Museum","terms":"art*,exhibit*,gallery,foundation,hall,institution,paint*,photo*,sculpt*"},"tourism/picnic_site":{"name":"Picnic Site","terms":"camp"},"tourism/theme_park":{"name":"Theme Park","terms":""},"tourism/viewpoint":{"name":"Viewpoint","terms":""},"tourism/zoo":{"name":"Zoo","terms":"animal"},"traffic_calming":{"name":"Traffic Calming","terms":"bump,hump,slow,speed"},"traffic_calming/bump":{"name":"Speed Bump","terms":"hump,speed,slow"},"traffic_calming/chicane":{"name":"Traffic Chicane","terms":"driveway link,speed,slow"},"traffic_calming/choker":{"name":"Traffic Choker","terms":"speed,slow"},"traffic_calming/cushion":{"name":"Speed Cushion","terms":"bump,hump,speed,slow"},"traffic_calming/dip":{"name":"Dip","terms":"speed,slow"},"traffic_calming/hump":{"name":"Speed Hump","terms":"bump,speed,slow"},"traffic_calming/island":{"name":"Traffic Island","terms":"circle,roundabout,slow"},"traffic_calming/rumble_strip":{"name":"Rumble Strip","terms":"audible lines,sleeper lines,growlers"},"traffic_calming/table":{"name":"Raised Pedestrian Crossing","terms":"flat top,hump,speed,slow"},"type/multipolygon":{"name":"Multipolygon","terms":""},"type/boundary":{"name":"Boundary","terms":""},"type/boundary/administrative":{"name":"Administrative Boundary","terms":""},"type/restriction":{"name":"Restriction","terms":""},"type/restriction/no_left_turn":{"name":"No Left Turn","terms":""},"type/restriction/no_right_turn":{"name":"No Right Turn","terms":""},"type/restriction/no_straight_on":{"name":"No Straight On","terms":""},"type/restriction/no_u_turn":{"name":"No U-turn","terms":""},"type/restriction/only_left_turn":{"name":"Left Turn Only","terms":""},"type/restriction/only_right_turn":{"name":"Right Turn Only","terms":""},"type/restriction/only_straight_on":{"name":"No Turns","terms":""},"type/route_master":{"name":"Route Master","terms":""},"type/route":{"name":"Route","terms":""},"type/route/bicycle":{"name":"Cycle Route","terms":""},"type/route/bus":{"name":"Bus Route","terms":""},"type/route/detour":{"name":"Detour Route","terms":""},"type/route/ferry":{"name":"Ferry Route","terms":""},"type/route/foot":{"name":"Foot Route","terms":""},"type/route/hiking":{"name":"Hiking Route","terms":""},"type/route/horse":{"name":"Riding Route","terms":""},"type/route/pipeline":{"name":"Pipeline Route","terms":""},"type/route/power":{"name":"Power Route","terms":""},"type/route/road":{"name":"Road Route","terms":""},"type/route/train":{"name":"Train Route","terms":""},"type/route/tram":{"name":"Tram Route","terms":""},"type/site":{"name":"Site","terms":""},"vertex":{"name":"Other","terms":""},"waterway/boatyard":{"name":"Boatyard","terms":""},"waterway/canal":{"name":"Canal","terms":""},"waterway/dam":{"name":"Dam","terms":""},"waterway/ditch":{"name":"Ditch","terms":""},"waterway/dock":{"name":"Wet Dock / Dry Dock","terms":"boat,ship,vessel,marine"},"waterway/drain":{"name":"Drain","terms":""},"waterway/fuel":{"name":"Marine Fuel Station","terms":"petrol,gas,diesel,boat"},"waterway/river":{"name":"River","terms":"beck,branch,brook,course,creek,estuary,rill,rivulet,run,runnel,stream,tributary,watercourse"},"waterway/riverbank":{"name":"Riverbank","terms":""},"waterway/sanitary_dump_station":{"name":"Marine Toilet Disposal","terms":"Boat,Watercraft,Sanitary,Dump Station,Pumpout,Pump out,Elsan,CDP,CTDP,Chemical Toilet"},"waterway/stream":{"name":"Stream","terms":"beck,branch,brook,burn,course,creek,current,drift,flood,flow,freshet,race,rill,rindle,rivulet,run,runnel,rush,spate,spritz,surge,tide,torrent,tributary,watercourse"},"waterway/water_point":{"name":"Marine Drinking Water","terms":""},"waterway/waterfall":{"name":"Waterfall","terms":"fall"},"waterway/weir":{"name":"Weir","terms":""}}}};
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 (c) AGIV"},{"id":"AGIV","name":"Belgium AGIV Orthophoto Flanders","type":"tms","template":"http://tile.informatievlaanderen.be/ws/raadpleegdiensten/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=omwrgbmrvl&STYLE=&FORMAT=image/png&tileMatrixSet=GoogleMapsVL&tileMatrix={zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,21],"polygon":[[[2.522393220658428,51.101723961331],[3.1260610915867457,51.34117672029327],[3.174929443042849,51.382459567439525],[3.3761520666856217,51.38784154353026],[3.410647373595811,51.33040116175589],[3.4020235468682634,51.28547573497245],[3.4911364230529203,51.256700377228974],[3.4825125963253734,51.30345118353617],[3.5773746903283947,51.323216048914524],[3.813092620881357,51.27288873325703],[3.8217164476089045,51.236906864834886],[3.9309515861578386,51.236906864834886],[4.054559769252684,51.27468708752057],[4.20116482362099,51.35194974615148],[4.169544125619984,51.38066543475199],[4.342020660170932,51.395016527087456],[4.3650175314443915,51.46491366130351],[4.5374940659953396,51.50071687469512],[4.571989372905529,51.479238319799464],[4.560490937268798,51.44879304380801],[4.638105377816725,51.45058450468522],[4.750215125274841,51.5239738914927],[4.8364533925503155,51.507874144493115],[5.080795149830825,51.49892738159079],[5.135412719105292,51.447001512638565],[5.106666630013469,51.391429175957505],[5.264770120018504,51.31782647548482],[5.264770120018504,51.28727359653538],[5.4085005654776275,51.292666758936925],[5.486115006025553,51.325012432665545],[5.5809771000285755,51.28367780302667],[5.583851708937758,51.23510703218069],[5.767826679125435,51.20449910348059],[5.8770618176743685,51.161253258857485],[5.704585283123422,50.80292546633848],[5.905807906766195,50.7865720955422],[5.9374286047672005,50.732019528192964],[5.902933297857012,50.70107817444857],[5.8138204216723555,50.69379488717487],[5.615472406938765,50.761122144578216],[5.500488050571466,50.71200098472672],[5.204403332925673,50.70289881954383],[5.164158808197117,50.67558172042608],[5.037676016193088,50.70107817444857],[4.988807664736986,50.750210783384084],[4.916942442007425,50.72656077355532],[4.790459650003396,50.766576871275696],[4.681224511454462,50.77021300246129],[4.6697260758177315,50.73565834458533],[4.287403090896464,50.67922491935501],[3.91082932379356,50.677403355240585],[3.718230526878334,50.752029520237265],[3.6549891308763196,50.71200098472672],[3.5342555566906557,50.710180693059606],[3.514133294326379,50.741116039142966],[3.45664111614273,50.74384464791457],[3.373277457776438,50.69561581502901],[3.310036061774423,50.70745012302645],[3.2899137994101473,50.7365680045137],[3.1648683118607086,50.742935129324266],[3.1318103094051106,50.77203096207303],[3.080067349039826,50.76021296163662],[2.8745328120332805,50.73929687829333],[2.8960923788521487,50.71109084772858],[2.8745328120332805,50.69561581502901],[2.796918371485353,50.70289881954383],[2.699181668573149,50.80020030189157],[2.6201299235706315,50.79747497850781],[2.5698242676599374,50.85830267681076],[2.5669496587507554,50.923581424665855],[2.6028822701155367,50.94984841176044],[2.549702005295661,50.996006093918574],[2.522393220658428,51.101723961331]]],"terms_text":"Orthophoto Flanders most recent (c) AGIV","best":true},{"id":"Benin_cotonou_pleiade_2016","name":"Benin: Cotonou Pleiade 2016","type":"tms","template":"http://geoxxx.agrocampus-ouest.fr/owsifl/gwc/service/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=Benin:cotonou_pleiade_2016&STYLE=&FORMAT=image/jpeg&tileMatrixSet=EPSG:3857&tileMatrix=EPSG:3857:{zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,21],"polygon":[[[2.31953818544,6.55745092536],[2.33645249928,6.56023631702],[2.36377172444,6.56211241002],[2.36737717181,6.56067658005],[2.37777373205,6.54939665325],[2.3777926612,6.53484752744],[2.36994151563,6.4933195729],[2.37038356708,6.45527010853],[2.36958186167,6.45269435578],[2.36188103586,6.44177160245],[2.35391742884,6.40545220189],[2.3674929737,6.40149524022],[2.39525870424,6.40071623744],[2.40128040262,6.40374371884],[2.40587684694,6.40340733291],[2.42045897749,6.39382909301],[2.42485054154,6.3979366042],[2.42949152505,6.39887495342],[2.43625257397,6.39628121034],[2.43958410532,6.40041525877],[2.44439433776,6.40189359345],[2.45375647532,6.39899446003],[2.47144744127,6.3963166199],[2.48162019208,6.3910582748],[2.49453210303,6.38739776192],[2.50893162289,6.38888498676],[2.50719014059,6.39228876781],[2.50120407357,6.39162040687],[2.4963025358,6.39521449649],[2.49509997769,6.40123077776],[2.49543290813,6.40400928653],[2.49830345887,6.41022131795],[2.50191336015,6.41281720321],[2.5108701911,6.41321333458],[2.52218648559,6.40849403999],[2.53352059576,6.4051656109],[2.53809922441,6.40960941297],[2.5411100736,6.41090182623],[2.54650822333,6.41099034757],[2.54654385468,6.40651114868],[2.57638511144,6.40723702943],[2.57642074279,6.41176933466],[2.58575615684,6.41196408125],[2.58867792765,6.41095493903],[2.60877400982,6.39413560832],[2.62569890171,6.39487921149],[2.64554556441,6.39728706193],[2.65039142819,6.39339200408],[2.6536650586,6.36823275735],[2.6431181786,6.3665949733],[2.61251084779,6.3628944474],[2.56867983171,6.3607044406],[2.54682890549,6.36055393954],[2.54687344468,6.35546343647],[2.50206702036,6.35461353888],[2.47064016846,6.35595920942],[2.46777184468,6.35202842507],[2.46422652522,6.35020467258],[2.45253944198,6.35006302163],[2.4511320036,6.34813302357],[2.44737289603,6.34629155079],[2.43757427441,6.34653944174],[2.43297783009,6.33841209773],[2.43016295333,6.33706638135],[2.42244876576,6.33706638135],[2.39236031651,6.34114999999],[2.39315311407,6.34114999999],[2.3652849434,6.34445228474],[2.35386064137,6.34529777247],[2.34377474198,6.34457844399],[2.34093759563,6.34533982549],[2.31086028117,6.36567095094],[2.28434610184,6.37465215648],[2.28146887022,6.37761782314],[2.27599054995,6.39517244756],[2.27611525968,6.39819996182],[2.31528747657,6.4926104105],[2.31579967725,6.5530659484],[2.31953818544,6.55745092536]],[[1.69563043958,6.25076170066],[1.70009994721,6.24711901182],[1.70417862346,6.24697179839],[1.75874803806,6.25835802546],[1.77079143482,6.25995187823],[1.81712109941,6.27161341959],[1.84456614779,6.27656750346],[1.85767848509,6.27944518918],[1.88843363033,6.28325588467],[1.90481876292,6.28594870029],[1.90617692982,6.29435189983],[1.90083111364,6.29721233234],[1.89880903445,6.29953873942],[1.89404334121,6.30085024405],[1.89047742238,6.29969866569],[1.88747882146,6.29636150888],[1.88344050885,6.29622344016],[1.86969682855,6.29226563906],[1.8564007671,6.29198230539],[1.85206654725,6.28674503171],[1.84991419093,6.28906373821],[1.84691224958,6.29202989661],[1.8435272712,6.29332703219],[1.84040507404,6.29315437611],[1.83626738336,6.29129499924],[1.83409832485,6.28733273348],[1.83416513363,6.2851988527],[1.83229560117,6.28456355663],[1.82785949792,6.28644177291],[1.82182443779,6.2908379014],[1.81562903657,6.28997904337],[1.81211044063,6.29143113241],[1.80757635117,6.29570768815],[1.80471693522,6.29692955475],[1.80073513171,6.29709778253],[1.79775991387,6.29612383144],[1.79625448928,6.29491967121],[1.79490049792,6.28965143736],[1.79641483036,6.28608317469],[1.80097564333,6.28338261222],[1.79566657198,6.28013306439],[1.79156005874,6.28174455931],[1.78498607441,6.28122215216],[1.78092410036,6.27752986974],[1.77588226414,6.27550220232],[1.76744654171,6.27696318619],[1.75653444036,6.27496207997],[1.74833032171,6.27238985028],[1.74761769468,6.27726423691],[1.74572477914,6.27938486862],[1.73948038482,6.27984972411],[1.73680357955,6.27761398678],[1.73572127725,6.27891558552],[1.72901812928,6.27911038233],[1.72435487617,6.27422273126],[1.72449294765,6.2678607472],[1.72555966124,6.26683029328],[1.69933944056,6.26159387355],[1.69572953928,6.25725948175],[1.69563043958,6.25076170066]]],"best":true},{"id":"Bing","name":"Bing aerial imagery","type":"bing","template":"http://www.bing.com/maps/","description":"Satellite and aerial imagery.","scaleExtent":[0,22],"default":true},{"id":"British_Columbia_Mosaic","name":"British Columbia Mosaic","type":"tms","template":"http://{switch:a,b,c,d}.imagery.paulnorman.ca/tiles/bc_mosaic/{zoom}/{x}/{y}.png","scaleExtent":[9,20],"polygon":[[[-123.3176032,49.3272567],[-123.4405258,49.3268222],[-123.440717,49.3384429],[-123.4398375,49.3430357],[-123.4401258,49.3435398],[-123.4401106,49.3439946],[-123.4406265,49.3444493],[-123.4404747,49.3455762],[-123.4397768,49.3460606],[-123.4389726,49.3461298],[-123.4372904,49.3567236],[-123.4374774,49.3710843],[-123.4335292,49.3709446],[-123.4330357,49.373725],[-123.4332717,49.3751221],[-123.4322847,49.3761001],[-123.4317482,49.3791736],[-123.4314264,49.3795927],[-123.4307826,49.3823866],[-123.4313405,49.3827358],[-123.4312118,49.3838533],[-123.4300415,49.3845883],[-123.4189858,49.3847087],[-123.4192235,49.4135198],[-123.3972532,49.4135691],[-123.3972758,49.4243473],[-123.4006929,49.4243314],[-123.4007741,49.5703491],[-123.4000812,49.570345],[-123.4010761,49.5933838],[-123.3760399,49.5932848],[-123.3769811,49.6756063],[-123.3507288,49.6756396],[-123.3507969,49.7086751],[-123.332887,49.708722],[-123.3327888,49.7256288],[-123.3007111,49.7255625],[-123.3009164,49.7375384],[-123.2885986,49.737638],[-123.2887823,49.8249207],[-123.2997955,49.8249207],[-123.3011721,49.8497814],[-123.3218218,49.850669],[-123.3273284,49.8577696],[-123.3276726,49.9758852],[-123.3008279,49.9752212],[-123.3007204,50.0997002],[-123.2501716,50.100735],[-123.25091,50.2754901],[-123.0224338,50.2755598],[-123.0224879,50.3254853],[-123.0009318,50.3254689],[-123.0007778,50.3423899],[-122.9775023,50.3423408],[-122.9774766,50.3504306],[-122.9508137,50.3504961],[-122.950795,50.3711984],[-122.9325221,50.3711521],[-122.9321048,50.399793],[-122.8874234,50.3999748],[-122.8873385,50.4256108],[-122.6620152,50.4256959],[-122.6623083,50.3994506],[-122.5990316,50.3992413],[-122.5988274,50.3755206],[-122.5724832,50.3753706],[-122.5735621,50.2493891],[-122.5990415,50.2494643],[-122.5991504,50.2265663],[-122.6185016,50.2266359],[-122.6185741,50.2244081],[-122.6490609,50.2245126],[-122.6492181,50.1993528],[-122.7308575,50.1993758],[-122.7311583,50.1244287],[-122.7490352,50.1245109],[-122.7490541,50.0903032],[-122.7687806,50.0903435],[-122.7689801,49.9494546],[-122.999047,49.9494706],[-122.9991199,49.8754553],[-122.9775894,49.8754553],[-122.9778145,49.6995098],[-122.9992362,49.6994781],[-122.9992524,49.6516526],[-123.0221525,49.6516526],[-123.0221162,49.5995096],[-123.0491898,49.5994625],[-123.0491898,49.5940523],[-123.0664647,49.5940405],[-123.0663594,49.5451868],[-123.0699906,49.5451202],[-123.0699008,49.5413153],[-123.0706835,49.5392837],[-123.0708888,49.5379931],[-123.0711454,49.5368773],[-123.0711069,49.5358115],[-123.0713764,49.532822],[-123.0716458,49.5321141],[-123.07171,49.5313896],[-123.0720308,49.5304153],[-123.0739554,49.5303486],[-123.0748023,49.5294992],[-123.0748151,49.5288079],[-123.0743403,49.5280584],[-123.073532,49.5274588],[-123.0733652,49.5270423],[-123.0732882,49.5255932],[-123.0737116,49.5249602],[-123.0736218,49.5244938],[-123.0992583,49.5244854],[-123.0991649,49.4754502],[-123.071052,49.4755252],[-123.071088,49.4663034],[-123.0739204,49.4663054],[-123.07422,49.4505028],[-123.0746319,49.4500858],[-123.074651,49.449329],[-123.0745999,49.449018],[-123.0744619,49.4486927],[-123.0743336,49.4479899],[-123.0742427,49.4477688],[-123.0743061,49.4447473],[-123.0747103,49.4447556],[-123.0746384,49.4377306],[-122.9996506,49.4377363],[-122.9996506,49.4369214],[-122.8606163,49.4415314],[-122.8102616,49.4423972],[-122.8098984,49.3766739],[-122.4036093,49.3766617],[-122.4036341,49.3771944],[-122.264739,49.3773028],[-122.263542,49.2360088],[-122.2155742,49.236139],[-122.0580956,49.235878],[-121.9538274,49.2966525],[-121.9400911,49.3045389],[-121.9235761,49.3142257],[-121.8990871,49.3225436],[-121.8883447,49.3259752],[-121.8552982,49.3363575],[-121.832697,49.3441519],[-121.7671336,49.3654361],[-121.6736683,49.3654589],[-121.6404153,49.3743775],[-121.5961976,49.3860493],[-121.5861178,49.3879193],[-121.5213684,49.3994649],[-121.5117375,49.4038378],[-121.4679302,49.4229024],[-121.4416803,49.4345607],[-121.422429,49.4345788],[-121.3462885,49.3932312],[-121.3480144,49.3412388],[-121.5135035,49.320577],[-121.6031683,49.2771727],[-121.6584065,49.1856125],[-121.679953,49.1654109],[-121.7815793,49.0702559],[-121.8076228,49.0622471],[-121.9393997,49.0636219],[-121.9725524,49.0424179],[-121.9921394,49.0332869],[-122.0035289,49.0273413],[-122.0178564,49.0241067],[-122.1108634,48.9992786],[-122.1493067,48.9995305],[-122.1492705,48.9991498],[-122.1991447,48.9996019],[-122.199181,48.9991974],[-122.234365,48.9994829],[-122.234365,49.000173],[-122.3994722,49.0012385],[-122.4521338,49.0016326],[-122.4521338,49.000883],[-122.4584089,49.0009306],[-122.4584814,48.9993124],[-122.4992458,48.9995022],[-122.4992458,48.9992906],[-122.5492618,48.9995107],[-122.5492564,48.9993206],[-122.6580785,48.9994212],[-122.6581061,48.9954007],[-122.7067604,48.9955344],[-122.7519761,48.9956392],[-122.7922063,48.9957204],[-122.7921907,48.9994331],[-123.0350417,48.9995724],[-123.0350437,49.0000958],[-123.0397091,49.0000536],[-123.0397444,49.0001812],[-123.0485506,49.0001348],[-123.0485329,49.0004712],[-123.0557122,49.000448],[-123.0556324,49.0002284],[-123.0641365,49.0001293],[-123.064158,48.9999421],[-123.074899,48.9996928],[-123.0750717,49.0006218],[-123.0899573,49.0003726],[-123.109229,48.9999421],[-123.1271193,49.0003046],[-123.1359953,48.9998741],[-123.1362716,49.0005765],[-123.153851,48.9998061],[-123.1540533,49.0006806],[-123.1710015,49.0001274],[-123.2000916,48.9996849],[-123.2003446,49.0497785],[-123.2108845,49.0497232],[-123.2112218,49.051989],[-123.2070479,49.0520857],[-123.2078911,49.0607884],[-123.2191688,49.0600978],[-123.218958,49.0612719],[-123.2251766,49.0612719],[-123.2253874,49.0622388],[-123.2297088,49.0620316],[-123.2298142,49.068592],[-123.2331869,49.0687301],[-123.2335031,49.0705945],[-123.249313,49.0702493],[-123.2497346,49.0802606],[-123.2751358,49.0803986],[-123.2751358,49.0870947],[-123.299483,49.0873018],[-123.29944,49.080253],[-123.3254508,49.0803944],[-123.3254353,49.1154662],[-123.2750966,49.1503341],[-123.275181,49.1873267],[-123.2788067,49.1871063],[-123.278891,49.1910741],[-123.3004767,49.1910741],[-123.3004186,49.2622933],[-123.3126185,49.2622416],[-123.3125958,49.2714948],[-123.3154251,49.2714727],[-123.3156628,49.2818906],[-123.3174735,49.2818832],[-123.3174961,49.2918488],[-123.3190353,49.2918488],[-123.3190692,49.298602],[-123.3202349,49.2985651],[-123.3202786,49.3019749],[-123.3222679,49.3019605],[-123.3223943,49.3118263],[-123.3254002,49.3118086],[-123.3253898,49.3201721],[-123.3192695,49.3201957],[-123.3192242,49.3246748],[-123.3179437,49.3246596],[-123.3179861,49.3254065],[-123.3176032,49.3272567]]],"terms_url":"http://imagery.paulnorman.ca/tiles/about.html","terms_text":"Copyright Province of British Columbia, City of Surrey"},{"id":"lu.geoportail.opendata.cadastre","name":"Cadastre geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/cadastre/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/plan-cadastral-numerise-pcn-webservices-wms-et-wmts/","terms_text":"Administration du Cadastre et de la Topographie"},{"id":"osm-cambodia_laos_thailand_vietnam-bilingual","name":"Cambodia, Laos, Thailand, Vietnam, Myanmar bilingual","type":"tms","template":"http://{switch:a,b,c,d}.tile.osm-tools.org/osm_then/{zoom}/{x}/{y}.png","scaleExtent":[0,19],"polygon":[[[92.1023798,20.8135629],[93.5690546,24.0975527],[94.1733026,23.9269484],[95.1950312,26.707274],[96.7550898,27.5286657],[97.5845575,28.5805966],[98.738122,27.514051],[98.7436151,25.8799151],[97.6779413,24.7577376],[97.9635858,24.042382],[98.8205194,24.1627239],[99.5236444,22.9593356],[100.3695917,21.5051376],[101.7923212,22.4830518],[105.3628778,23.3331079],[106.8185663,22.8480137],[108.1973505,21.3619661],[107.4389505,18.8539792],[117.1453714,7.4656173],[119.6172953,5.2875389],[118.1231546,4.0502277],[117.2552347,4.3624942],[115.8654642,4.3460623],[115.5084085,3.0249771],[114.552598,1.5100953],[113.5418558,1.2574836],[112.9650736,1.5704982],[112.2454691,1.5100953],[111.67418,1.0158321],[110.4546976,0.9004918],[109.4988871,1.9218969],[103.2256937,1.1256762],[100.4626322,3.2388904],[97.6721048,8.0588831],[93.892808,15.9398659],[92.1023798,20.8135629]]],"terms_url":"http://www.osm-tools.org/","terms_text":"© osm-tools.org & OpenStreetMap contributors, CC-BY-SA"},{"id":"South_Africa-CapeTown-Aerial-2013","name":"City of Cape Town 2013 Aerial","type":"tms","template":"http://{switch:a,b,c}.coct.aerial.openstreetmap.org.za/layer/za_coct_aerial_2013/{zoom}/{x}/{y}.jpg","description":"OpenStreetMap use only. City of Cape Town Aerial ortho-photography of the municipal area. 12cm ground sample distance","scaleExtent":[1,21],"polygon":[[[18.4486565,-33.893623],[18.4485868,-33.902644],[18.4702,-33.9027665],[18.4813902,-33.8472383],[18.4492466,-33.801069],[18.4281537,-33.7356408],[18.43914,-33.7177232],[18.4071895,-33.6589917],[18.3322379,-33.5775191],[18.3324525,-33.5504487],[18.353996,-33.5505918],[18.3542535,-33.5236025],[18.3652398,-33.5236561],[18.3650252,-33.5148009],[18.3760115,-33.5147652],[18.3760545,-33.5058017],[18.4296557,-33.5059449],[18.4296986,-33.4878541],[18.4404919,-33.4878899],[18.4405991,-33.4698849],[18.4943721,-33.4700997],[18.4943292,-33.4791564],[18.5158297,-33.4791743],[18.5157439,-33.4881941],[18.5264727,-33.4883015],[18.5263225,-33.5243538],[18.5479304,-33.5244253],[18.5479519,-33.5153913],[18.5693666,-33.5154987],[18.5693666,-33.524479],[18.5801169,-33.5245327],[18.580074,-33.5425978],[18.5907814,-33.5425978],[18.5907385,-33.5606413],[18.5799453,-33.5605341],[18.5798809,-33.569617],[18.5906956,-33.569617],[18.5906526,-33.5786811],[18.6230108,-33.5787347],[18.622925,-33.5877264],[18.6659691,-33.5878872],[18.6659262,-33.614928],[18.6767194,-33.6149726],[18.6765772,-33.6510279],[18.687298,-33.6510167],[18.6873409,-33.6600365],[18.6980697,-33.6600901],[18.6980697,-33.6690733],[18.7520358,-33.6692519],[18.7520787,-33.6421924],[18.7736437,-33.642246],[18.773708,-33.6331886],[18.8274595,-33.6332958],[18.8275239,-33.6603044],[18.8166663,-33.6602866],[18.8166019,-33.6783233],[18.8058087,-33.6783055],[18.8058087,-33.7053892],[18.8273951,-33.7054428],[18.8273308,-33.7234701],[18.838124,-33.7234344],[18.8380381,-33.7413865],[18.8165161,-33.7413687],[18.8163659,-33.7955057],[18.8055941,-33.7955057],[18.8055083,-33.8135675],[18.794758,-33.8135497],[18.7947151,-33.8315364],[18.7731072,-33.8315186],[18.7731287,-33.8405194],[18.7623569,-33.8405194],[18.7622711,-33.903588],[18.7514564,-33.9035167],[18.7510809,-33.9847823],[18.7619063,-33.9848001],[18.7617776,-34.0298785],[18.772603,-34.0298963],[18.7725815,-34.0389073],[18.7940338,-34.0389406],[18.7938756,-34.0406987],[18.7984461,-34.0411855],[18.8032445,-34.0411788],[18.8034055,-34.0389206],[18.8159367,-34.038974],[18.8163444,-34.0299318],[18.8379845,-34.0316479],[18.8380006,-34.030003],[18.8484183,-34.0300074],[18.8484666,-34.0218491],[18.859925,-34.0234675],[18.8598606,-34.0210132],[18.868272,-34.0220803],[18.8681862,-34.0211733],[18.8854596,-34.0234319],[18.8851806,-34.0213156],[18.9025184,-34.021031],[18.9025828,-34.0119958],[18.9134189,-34.0119958],[18.9134833,-33.9939582],[18.9458844,-33.9940294],[18.9458629,-34.003102],[18.9674279,-34.0029953],[18.9674708,-34.0120848],[18.9782211,-34.0120848],[18.9783284,-34.0211377],[18.9891431,-34.0211377],[18.9891645,-34.039134],[19.0000167,-34.0391251],[19.0000221,-34.0571798],[19.0108368,-34.0572509],[19.0107939,-34.0841436],[19.0000007,-34.0841258],[19.0000221,-34.0931977],[18.9891538,-34.0931711],[18.9891753,-34.1021976],[18.9783177,-34.1021798],[18.9783177,-34.111232],[18.967503,-34.1112143],[18.9674923,-34.1292536],[18.9566025,-34.1292358],[18.9565596,-34.1382408],[18.9674172,-34.1383118],[18.9674172,-34.1473157],[18.9891753,-34.147298],[18.9891753,-34.165303],[18.9782748,-34.1652852],[18.9783177,-34.1742863],[18.9674172,-34.1742685],[18.9674601,-34.1833042],[18.9565596,-34.1833219],[18.9565596,-34.1923565],[18.9457449,-34.192321],[18.945702,-34.2013192],[18.9348659,-34.2013725],[18.9348873,-34.2193305],[18.9023575,-34.2193482],[18.9017567,-34.2362557],[18.8878414,-34.2373467],[18.8894185,-34.2554123],[18.8805887,-34.2553414],[18.8792744,-34.2644348],[18.8696882,-34.2644126],[18.8697097,-34.2734386],[18.8371369,-34.2734208],[18.8371155,-34.2643771],[18.848016,-34.2644037],[18.8480267,-34.237391],[18.8154861,-34.210281],[18.8156471,-34.1741265],[18.8548824,-34.1562743],[18.7617561,-34.0840547],[18.6533734,-34.077479],[18.4797433,-34.1101217],[18.4463713,-34.1342269],[18.4444508,-34.1640868],[18.4359965,-34.1640513],[18.435975,-34.1820172],[18.4468111,-34.182106],[18.4467253,-34.1911052],[18.4659299,-34.1912117],[18.4866151,-34.2453911],[18.4788904,-34.2543659],[18.4860036,-34.2543748],[18.4677109,-34.2994116],[18.4892222,-34.3445792],[18.500112,-34.3445837],[18.4999189,-34.3626174],[18.467432,-34.3625111],[18.4673676,-34.3534947],[18.3916005,-34.3170651],[18.3917722,-34.2900161],[18.3701643,-34.2808678],[18.370682,-34.2178866],[18.3492324,-34.1816178],[18.3274743,-34.1814936],[18.3276674,-34.1634565],[18.3118746,-34.1543832],[18.3114025,-34.1435331],[18.3236656,-34.1346886],[18.3499297,-34.1042053],[18.3393189,-34.0882843],[18.3612487,-34.0597219],[18.3550474,-34.0553843],[18.3427522,-34.064326],[18.3199963,-34.0644326],[18.296071,-34.045126],[18.3068213,-34.0252637],[18.3287725,-34.0191992],[18.3289227,-34.001252],[18.3397374,-34.0012698],[18.3398017,-33.9866282],[18.3628687,-33.9735145],[18.3638129,-33.9292474],[18.3726212,-33.9292741],[18.3728358,-33.917763],[18.3977267,-33.8933469],[18.4486565,-33.893623]]],"terms_url":"https://www.capetown.gov.za","terms_text":"City of Cape Town Aerial - OPENSTREETMAP USE ONLY"},{"id":"South_Africa-CapeTown-Aerial","name":"City of Cape Town 2015 Aerial","type":"tms","template":"http://{switch:a,b,c}.coct.aerial.openstreetmap.org.za/layer/za_coct_aerial_2015/{zoom}/{x}/{y}.jpg","description":"OpenStreetMap use only. City of Cape Town Aerial ortho-photography of the municipal area. 8cm ground sample distance","scaleExtent":[1,21],"polygon":[[[18.4486565,-33.893623],[18.4485868,-33.902644],[18.4702,-33.9027665],[18.4813902,-33.8472383],[18.4492466,-33.801069],[18.4281537,-33.7356408],[18.43914,-33.7177232],[18.4071895,-33.6589917],[18.3322379,-33.5775191],[18.3324525,-33.5504487],[18.353996,-33.5505918],[18.3542535,-33.5236025],[18.3652398,-33.5236561],[18.3650252,-33.5148009],[18.3760115,-33.5147652],[18.3760545,-33.5058017],[18.4296557,-33.5059449],[18.4296986,-33.4878541],[18.4404919,-33.4878899],[18.4405991,-33.4698849],[18.4943721,-33.4700997],[18.4943292,-33.4791564],[18.5158297,-33.4791743],[18.5157439,-33.4881941],[18.5264727,-33.4883015],[18.5263225,-33.5243538],[18.5479304,-33.5244253],[18.5479519,-33.5153913],[18.5693666,-33.5154987],[18.5693666,-33.524479],[18.5801169,-33.5245327],[18.580074,-33.5425978],[18.5907814,-33.5425978],[18.5907385,-33.5606413],[18.5799453,-33.5605341],[18.5798809,-33.569617],[18.5906956,-33.569617],[18.5906526,-33.5786811],[18.6230108,-33.5787347],[18.622925,-33.5877264],[18.6659691,-33.5878872],[18.6659262,-33.614928],[18.6767194,-33.6149726],[18.6765772,-33.6510279],[18.687298,-33.6510167],[18.6873409,-33.6600365],[18.6980697,-33.6600901],[18.6980697,-33.6690733],[18.7520358,-33.6692519],[18.7520787,-33.6421924],[18.7736437,-33.642246],[18.773708,-33.6331886],[18.8274595,-33.6332958],[18.8275239,-33.6603044],[18.8166663,-33.6602866],[18.8166019,-33.6783233],[18.8058087,-33.6783055],[18.8058087,-33.7053892],[18.8273951,-33.7054428],[18.8273308,-33.7234701],[18.838124,-33.7234344],[18.8380381,-33.7413865],[18.8165161,-33.7413687],[18.8163659,-33.7955057],[18.8055941,-33.7955057],[18.8055083,-33.8135675],[18.794758,-33.8135497],[18.7947151,-33.8315364],[18.7731072,-33.8315186],[18.7731287,-33.8405194],[18.7623569,-33.8405194],[18.7622711,-33.903588],[18.7514564,-33.9035167],[18.7510809,-33.9847823],[18.7619063,-33.9848001],[18.7617776,-34.0298785],[18.772603,-34.0298963],[18.7725815,-34.0389073],[18.7940338,-34.0389406],[18.7938756,-34.0406987],[18.7984461,-34.0411855],[18.8032445,-34.0411788],[18.8034055,-34.0389206],[18.8159367,-34.038974],[18.8163444,-34.0299318],[18.8379845,-34.0316479],[18.8380006,-34.030003],[18.8484183,-34.0300074],[18.8484666,-34.0218491],[18.859925,-34.0234675],[18.8598606,-34.0210132],[18.868272,-34.0220803],[18.8681862,-34.0211733],[18.8854596,-34.0234319],[18.8851806,-34.0213156],[18.9025184,-34.021031],[18.9025828,-34.0119958],[18.9134189,-34.0119958],[18.9134833,-33.9939582],[18.9458844,-33.9940294],[18.9458629,-34.003102],[18.9674279,-34.0029953],[18.9674708,-34.0120848],[18.9782211,-34.0120848],[18.9783284,-34.0211377],[18.9891431,-34.0211377],[18.9891645,-34.039134],[19.0000167,-34.0391251],[19.0000221,-34.0571798],[19.0108368,-34.0572509],[19.0107939,-34.0841436],[19.0000007,-34.0841258],[19.0000221,-34.0931977],[18.9891538,-34.0931711],[18.9891753,-34.1021976],[18.9783177,-34.1021798],[18.9783177,-34.111232],[18.967503,-34.1112143],[18.9674923,-34.1292536],[18.9566025,-34.1292358],[18.9565596,-34.1382408],[18.9674172,-34.1383118],[18.9674172,-34.1473157],[18.9891753,-34.147298],[18.9891753,-34.165303],[18.9782748,-34.1652852],[18.9783177,-34.1742863],[18.9674172,-34.1742685],[18.9674601,-34.1833042],[18.9565596,-34.1833219],[18.9565596,-34.1923565],[18.9457449,-34.192321],[18.945702,-34.2013192],[18.9348659,-34.2013725],[18.9348873,-34.2193305],[18.9023575,-34.2193482],[18.9017567,-34.2362557],[18.8878414,-34.2373467],[18.8894185,-34.2554123],[18.8805887,-34.2553414],[18.8792744,-34.2644348],[18.8696882,-34.2644126],[18.8697097,-34.2734386],[18.8371369,-34.2734208],[18.8371155,-34.2643771],[18.848016,-34.2644037],[18.8480267,-34.237391],[18.8154861,-34.210281],[18.8156471,-34.1741265],[18.8548824,-34.1562743],[18.7617561,-34.0840547],[18.6533734,-34.077479],[18.4797433,-34.1101217],[18.4463713,-34.1342269],[18.4444508,-34.1640868],[18.4359965,-34.1640513],[18.435975,-34.1820172],[18.4468111,-34.182106],[18.4467253,-34.1911052],[18.4659299,-34.1912117],[18.4866151,-34.2453911],[18.4788904,-34.2543659],[18.4860036,-34.2543748],[18.4677109,-34.2994116],[18.4892222,-34.3445792],[18.500112,-34.3445837],[18.4999189,-34.3626174],[18.467432,-34.3625111],[18.4673676,-34.3534947],[18.3916005,-34.3170651],[18.3917722,-34.2900161],[18.3701643,-34.2808678],[18.370682,-34.2178866],[18.3492324,-34.1816178],[18.3274743,-34.1814936],[18.3276674,-34.1634565],[18.3118746,-34.1543832],[18.3114025,-34.1435331],[18.3236656,-34.1346886],[18.3499297,-34.1042053],[18.3393189,-34.0882843],[18.3612487,-34.0597219],[18.3550474,-34.0553843],[18.3427522,-34.064326],[18.3199963,-34.0644326],[18.296071,-34.045126],[18.3068213,-34.0252637],[18.3287725,-34.0191992],[18.3289227,-34.001252],[18.3397374,-34.0012698],[18.3398017,-33.9866282],[18.3628687,-33.9735145],[18.3638129,-33.9292474],[18.3726212,-33.9292741],[18.3728358,-33.917763],[18.3977267,-33.8933469],[18.4486565,-33.893623]]],"terms_url":"https://www.capetown.gov.za","terms_text":"City of Cape Town Aerial - OPENSTREETMAP USE ONLY","best":true},{"id":"CRAIG-Auvergne-2013","name":"CRAIG - Auvergne 2013 - 25 cm","type":"tms","template":"http://tiles.craig.fr/osm/tms/1.0.0/ortho_2013/webmercator/{zoom-1}/{x}/{-y}.jpeg","polygon":[[[2.9401192,44.6338837],[2.9971896,44.633931],[2.9971676,44.6473385],[3.0159744,44.6473541],[3.0159305,44.6741168],[3.0349486,44.6741326],[3.0349036,44.7015216],[3.0536338,44.7015371],[3.0535675,44.7418954],[3.0723301,44.741911],[3.0722196,44.8091687],[3.0921583,44.8091852],[3.092137,44.8221252],[3.1301398,44.8221567],[3.1300495,44.8770722],[3.1485587,44.8770875],[3.1485807,44.8636964],[3.1682313,44.8637126],[3.1682538,44.8500261],[3.2064,44.8500576],[3.2063789,44.8628393],[3.2439492,44.8628704],[3.2439263,44.8767893],[3.2631452,44.8768052],[3.2630782,44.9175197],[3.3200437,44.9175667],[3.3200227,44.9303336],[3.3390815,44.9303493],[3.3390586,44.9441978],[3.3769989,44.9442292],[3.3770218,44.9302879],[3.396031,44.9303036],[3.39612,44.8762713],[3.4148252,44.8762867],[3.4148923,44.8355255],[3.4333371,44.8355408],[3.4333819,44.8082784],[3.4525549,44.8082943],[3.4525774,44.7946344],[3.5089262,44.7946811],[3.508904,44.8081469],[3.604265,44.8082258],[3.6042213,44.8348239],[3.6236136,44.83484],[3.6235695,44.8616583],[3.6424823,44.8616739],[3.642549,44.821102],[3.6610055,44.8211172],[3.6610275,44.8077696],[3.6992999,44.8078013],[3.6992782,44.820994],[3.7361139,44.8210245],[3.7361819,44.7797075],[3.7751058,44.7797397],[3.775151,44.7522344],[3.8118352,44.7522648],[3.8118567,44.7392021],[3.8311822,44.7392181],[3.8312061,44.7246766],[3.887824,44.7247235],[3.8878019,44.7381833],[3.925626,44.7382146],[3.9256039,44.7516682],[3.9454097,44.7516846],[3.9453656,44.7784691],[3.9643737,44.7784848],[3.9643516,44.7919273],[4.0033183,44.7919596],[4.0032964,44.8052575],[4.0216937,44.8052727],[4.0216718,44.8185687],[4.0596515,44.8186001],[4.0596082,44.8449216],[4.0798132,44.8449383],[4.0797928,44.8573502],[4.173882,44.857428],[4.1738604,44.8705468],[4.1932576,44.8705628],[4.193235,44.8842744],[4.2140385,44.8842916],[4.2139961,44.9100242],[4.2324138,44.9100394],[4.2323689,44.9373093],[4.2715486,44.9373416],[4.2715273,44.9502971],[4.3288672,44.9503445],[4.3287793,45.0036659],[4.3489259,45.0036825],[4.3489038,45.0170656],[4.4060793,45.0171127],[4.4059904,45.0710024],[4.3884707,45.0709879],[4.3884482,45.0845976],[4.407943,45.0846137],[4.4079231,45.09663],[4.4843608,45.0966929],[4.4842941,45.1370472],[4.4663631,45.1370324],[4.4663413,45.1502035],[4.4864469,45.15022],[4.4864022,45.1772415],[4.5065524,45.177258],[4.5064402,45.2450058],[4.4881342,45.2449908],[4.4881106,45.2592077],[4.4698588,45.2591927],[4.469836,45.2729835],[4.4508849,45.2729679],[4.4508626,45.2864203],[4.3936753,45.2863733],[4.3936303,45.3135182],[4.3750893,45.3135029],[4.3750662,45.3274054],[4.3950734,45.3274218],[4.3950283,45.3545849],[4.3767871,45.35457],[4.3767639,45.3685486],[4.3576564,45.3685329],[4.3576335,45.3823359],[4.2814576,45.3822734],[4.2814334,45.3968834],[4.2444556,45.3968531],[4.2444325,45.4107893],[4.1481178,45.4107104],[4.1481388,45.3980659],[4.1291913,45.3980504],[4.1292145,45.3840899],[4.0902138,45.3840579],[4.0902351,45.3712093],[4.0135507,45.3711464],[4.0135259,45.3860975],[3.9170932,45.3860185],[3.9170704,45.3997355],[3.9375703,45.3997523],[3.9375481,45.4131142],[3.975277,45.4131451],[3.9752552,45.4262061],[3.9953725,45.4262226],[3.9956999,45.5209568],[3.9777821,45.5209421],[3.977693,45.5743873],[3.9581755,45.5743714],[3.9581522,45.5883658],[3.9396019,45.5883506],[3.9395781,45.6026212],[3.9202279,45.6026054],[3.9202048,45.6164603],[3.8818916,45.616429],[3.8818468,45.643276],[3.8441329,45.6432453],[3.8441098,45.6570896],[3.8261689,45.657075],[3.8261241,45.6838865],[3.8072175,45.6838711],[3.8071277,45.7375802],[3.7882101,45.7375648],[3.7881863,45.7517966],[3.7688482,45.7517809],[3.7688028,45.7789651],[3.750719,45.7789504],[3.7505822,45.8606554],[3.7696692,45.8606709],[3.7695793,45.914333],[3.751661,45.9143185],[3.7516379,45.9280879],[3.7328974,45.9280727],[3.7328527,45.9547155],[3.8101795,45.9547782],[3.8101569,45.9682278],[3.8495994,45.9682598],[3.8495098,46.0216192],[3.8318849,46.0216049],[3.8317936,46.0759058],[3.8505037,46.0759209],[3.8504583,46.1029545],[3.8324727,46.10294],[3.8323353,46.1845598],[3.8142194,46.1845452],[3.8141522,46.2244234],[3.8336864,46.2244392],[3.8336634,46.2381001],[3.8528929,46.2381156],[3.8528703,46.2514729],[3.8931424,46.2515054],[3.8931205,46.2644677],[3.9130562,46.2644838],[3.9130335,46.2779317],[3.9518926,46.2779631],[3.9518709,46.2908227],[3.971523,46.2908386],[3.9715012,46.3036947],[4.0105021,46.3037261],[4.0104784,46.3177638],[4.0298278,46.3177794],[4.029783,46.3442827],[4.0116018,46.344268],[4.0114647,46.4253437],[4.031532,46.4253598],[4.0314635,46.4657978],[4.0132435,46.4657832],[4.0132204,46.479378],[3.9943703,46.4793629],[3.9943461,46.4936113],[3.9745971,46.4935955],[3.9745735,46.5075278],[3.8775423,46.5074499],[3.8774959,46.5347758],[3.8583577,46.5347605],[3.8583347,46.5483156],[3.8186897,46.5482838],[3.8187114,46.5355316],[3.7992386,46.535516],[3.7992156,46.5490706],[3.7610377,46.5490399],[3.7609226,46.6168059],[3.7423295,46.616791],[3.7422834,46.6439624],[3.7228558,46.6439468],[3.7228098,46.6710357],[3.7038706,46.6710206],[3.7038474,46.6846709],[3.6841096,46.6846551],[3.6840631,46.711998],[3.6648359,46.7119826],[3.6647898,46.7390375],[3.6457623,46.7390222],[3.6457158,46.7663375],[3.6257542,46.7663216],[3.6257314,46.7797093],[3.5672301,46.7796626],[3.5672528,46.7663082],[3.5471462,46.7662922],[3.5471922,46.7392824],[3.5271621,46.7392664],[3.5272308,46.6988967],[3.4877399,46.6988651],[3.4877618,46.685943],[3.4679636,46.6859272],[3.4679407,46.6994059],[3.4679179,46.7127907],[3.4486497,46.7127753],[3.4486258,46.7267878],[3.350433,46.7267092],[3.3504786,46.6999004],[3.3303913,46.6998843],[3.3303448,46.7271984],[3.2327174,46.7271203],[3.2327406,46.7135148],[3.2129042,46.7134989],[3.212927,46.7001302],[3.1735446,46.7000987],[3.173498,46.7275094],[3.1541227,46.7274939],[3.1541002,46.7407271],[3.1147772,46.7406957],[3.114754,46.7542756],[3.0753432,46.7542441],[3.0752971,46.7813548],[3.05597,46.7813394],[3.055924,46.8083069],[2.99704,46.8082598],[2.9970166,46.8219593],[2.9379443,46.8219121],[2.9379675,46.8082604],[2.8986634,46.808229],[2.8986872,46.7942392],[2.878991,46.7942234],[2.8790134,46.7810427],[2.8594188,46.781027],[2.8594415,46.7677056],[2.8400446,46.7676901],[2.8400671,46.754466],[2.7414032,46.7543871],[2.741382,46.7668245],[2.7023351,46.7667932],[2.7023571,46.7538869],[2.6826621,46.7538711],[2.6826849,46.7404752],[2.6634875,46.7404599],[2.6635123,46.7258966],[2.6434164,46.7258805],[2.6434382,46.7130938],[2.6241432,46.7130784],[2.6241658,46.6998093],[2.6039699,46.6997931],[2.6039936,46.6858433],[2.5651245,46.6858122],[2.5651469,46.6726126],[2.5459278,46.6725972],[2.5459966,46.6321534],[2.5659222,46.6321694],[2.565946,46.6181104],[2.5456397,46.6180941],[2.5456862,46.5907192],[2.5664225,46.5907358],[2.5664449,46.5775417],[2.5854963,46.577557],[2.5855181,46.5647199],[2.5661318,46.5647044],[2.5661557,46.5506246],[2.468279,46.5505461],[2.4683039,46.5358205],[2.3321246,46.5357112],[2.3321701,46.5088566],[2.3126474,46.5088409],[2.3126703,46.4953444],[2.2928767,46.4953285],[2.2928996,46.4818182],[2.2748687,46.4818037],[2.2749151,46.4544154],[2.2553921,46.4543997],[2.255529,46.3734888],[2.275948,46.3735052],[2.276037,46.3208741],[2.3145615,46.3209052],[2.3145849,46.3070421],[2.3537075,46.3070737],[2.3537313,46.2929669],[2.3938428,46.2929992],[2.3938862,46.2672854],[2.4515727,46.267332],[2.451596,46.2534921],[2.4709353,46.2535077],[2.4709807,46.2265552],[2.4915062,46.2265718],[2.4915521,46.199329],[2.5108806,46.1993446],[2.5109254,46.1727799],[2.5311728,46.1727963],[2.5313772,46.051352],[2.5516349,46.0513684],[2.5516577,46.0377665],[2.5705635,46.0377818],[2.5706774,45.9699434],[2.5514356,45.9699278],[2.551458,45.9566151],[2.5322621,45.9565995],[2.5322849,45.9430066],[2.5130653,45.942991],[2.513134,45.9020279],[2.4749412,45.9019969],[2.4749633,45.8888235],[2.4361947,45.888792],[2.4362172,45.8753288],[2.417209,45.8753133],[2.4172548,45.8479368],[2.3784736,45.8479053],[2.378497,45.8339746],[2.3595157,45.8339592],[2.3595606,45.8070849],[2.3787254,45.8071005],[2.3787481,45.7935783],[2.3986981,45.7935945],[2.3987203,45.7803477],[2.4182486,45.7803636],[2.4183161,45.7400007],[2.4572171,45.7400324],[2.4572394,45.7266956],[2.4758919,45.7267107],[2.4759144,45.7132391],[2.49533,45.7132549],[2.4954204,45.6591268],[2.4576942,45.659096],[2.4577622,45.618343],[2.4391188,45.6183278],[2.4391866,45.5776619],[2.4585044,45.5776777],[2.4585496,45.5505348],[2.4780887,45.5505508],[2.4781108,45.5372464],[2.4975506,45.5372623],[2.4975949,45.5106757],[2.4785536,45.5106601],[2.4786444,45.4561337],[2.4597798,45.4561183],[2.4598701,45.401757],[2.4224876,45.4017264],[2.4224651,45.4152816],[2.4023154,45.4152651],[2.4022929,45.4288193],[2.3256006,45.4287565],[2.3256684,45.3879609],[2.3456182,45.3879773],[2.3456629,45.3611091],[2.326256,45.3610932],[2.326279,45.3472146],[2.3073819,45.3471991],[2.3074045,45.3335972],[2.2881095,45.3335813],[2.2881307,45.3208191],[2.2696332,45.3208039],[2.2696574,45.306212],[2.2506602,45.3061964],[2.2506828,45.2925147],[2.2316866,45.2924992],[2.2317086,45.2792355],[2.2130009,45.2792202],[2.213046,45.2520355],[2.1937387,45.2520197],[2.1937617,45.2381134],[2.1756091,45.2380985],[2.1757423,45.1576822],[2.1573543,45.157667],[2.1574448,45.1029478],[2.1202408,45.1029172],[2.1202629,45.0895468],[2.1006669,45.0895306],[2.1006902,45.0754441],[2.0824591,45.0754291],[2.082548,45.0215961],[2.1025534,45.0216126],[2.1025982,44.994453],[2.0457406,44.9944061],[2.0458508,44.9275321],[2.0657794,44.9275486],[2.0658912,44.8596881],[2.0856964,44.8597044],[2.0857193,44.8458126],[2.1055593,44.8458291],[2.1056029,44.8193264],[2.124743,44.8193422],[2.1247657,44.805512],[2.1435067,44.8055275],[2.143551,44.778597],[2.1256091,44.7785822],[2.1256984,44.7242739],[2.1066459,44.7242581],[2.1067116,44.6842263],[2.1263414,44.6842426],[2.1263635,44.670735],[2.14598,44.6707513],[2.146069,44.6164441],[2.1839622,44.6164756],[2.183983,44.6037819],[2.2404173,44.6038288],[2.2403728,44.6309515],[2.25948,44.6309674],[2.2594571,44.644934],[2.316678,44.6449815],[2.3167011,44.6308801],[2.3361516,44.6308963],[2.3361734,44.6175824],[2.3724238,44.6176125],[2.3724009,44.6315823],[2.4110495,44.6316144],[2.4110701,44.6190741],[2.4492173,44.6191058],[2.4491956,44.6323197],[2.5048575,44.6323659],[2.5048126,44.6597555],[2.5246119,44.6597719],[2.524567,44.6871739],[2.5422544,44.6871886],[2.5422313,44.70122],[2.5807101,44.701252],[2.5805999,44.7683374],[2.61769,44.7683681],[2.6176235,44.808838],[2.6367564,44.8088539],[2.6366899,44.8492948],[2.6733105,44.8493251],[2.6732888,44.8625164],[2.6933766,44.862533],[2.6933323,44.8894303],[2.7305201,44.8894611],[2.7304757,44.9164461],[2.7499202,44.9164622],[2.7500519,44.8364688],[2.8073346,44.8365162],[2.8073139,44.8491017],[2.8263796,44.8491175],[2.8264007,44.8362845],[2.8457039,44.8363004],[2.8457707,44.7957107],[2.8642166,44.795726],[2.8642611,44.7686452],[2.8839885,44.7686615],[2.8840323,44.7419697],[2.9020315,44.7419846],[2.9021426,44.6743192],[2.9219777,44.6743357],[2.9220221,44.6472986],[2.9400972,44.6473136],[2.9401192,44.6338837]]],"terms_url":"http://wiki.openstreetmap.org/wiki/WikiProject_France/CRAIG","terms_text":"Orthophotographie CRAIG/Sintegra/IGN 2013"},{"id":"Czech_CUZK-KM-tms","name":"Czech CUZK:KM tiles proxy","type":"tms","template":"http://osm-{switch:a,b,c}.zby.cz/tiles_cuzk.php/{zoom}/{x}/{y}.png","scaleExtent":[13,18],"polygon":[[[15.0063684,49.0177392],[15.1559854,49.0013828],[15.190896,48.9424551],[15.3105895,48.9882938],[15.4053469,48.9752013],[15.5400022,48.9162426],[15.7145553,48.8670572],[15.8342488,48.880178],[15.968904,48.8178233],[16.0885976,48.7455261],[16.3978059,48.7455261],[16.4875761,48.8145394],[16.6721036,48.7784014],[16.6820781,48.7356594],[16.9015163,48.7126294],[16.9464014,48.6237005],[17.1159672,48.8375227],[17.2107246,48.880178],[17.4052266,48.8178233],[17.4800351,48.8539329],[17.5299074,48.8178233],[17.7044605,48.8670572],[17.8141796,48.9359033],[17.8840008,48.9359033],[17.9438476,49.0210099],[18.0635412,49.0340903],[18.1184007,49.0994409],[18.1981964,49.3047337],[18.3877112,49.3339917],[18.577226,49.5091747],[18.7567663,49.4994587],[18.8465365,49.5253637],[18.8764598,49.5706645],[18.7966641,49.693412],[18.64206,49.7095399],[18.5872004,49.8351543],[18.6121366,49.8833809],[18.5622643,49.9347695],[18.512392,49.9058702],[18.362775,49.9540261],[18.3278644,49.9219275],[18.2630304,49.9732751],[18.1184007,50.0053395],[18.0635412,50.075806],[17.9139242,49.9796897],[17.779269,50.0309757],[17.714435,50.1237921],[17.6047159,50.1653411],[17.7593201,50.21962],[17.7343839,50.3439092],[17.6396265,50.2802117],[17.3802905,50.2802117],[17.3503671,50.3439092],[17.2805459,50.3375433],[17.1857885,50.4075214],[16.9015163,50.4615247],[16.8666057,50.4138779],[16.9663503,50.3184404],[17.0361715,50.2323826],[16.8366823,50.21962],[16.7120015,50.1046034],[16.5823335,50.1589513],[16.5623846,50.2387626],[16.4327166,50.3375433],[16.3529209,50.3916263],[16.2781124,50.3916263],[16.2082911,50.4456477],[16.3978059,50.5344899],[16.4476782,50.5978464],[16.3529209,50.670601],[16.2382145,50.6769221],[16.2182656,50.6326561],[16.1284954,50.6832425],[16.0486997,50.6073425],[15.988853,50.7021983],[15.8741467,50.6832425],[15.8292616,50.7653291],[15.729517,50.743243],[15.450232,50.8157725],[15.3903852,50.7747914],[15.3804108,50.8598659],[15.2956278,50.8850434],[15.2956278,50.9887568],[15.1709471,51.0201394],[14.9914067,51.0013124],[15.0063684,50.8881896],[14.8417898,50.8756034],[14.7969047,50.8252246],[14.6323261,50.8567177],[14.6622495,50.9353576],[14.5724793,50.9227841],[14.6123772,50.9856174],[14.4976708,51.0483657],[14.4178751,51.0232765],[14.3081561,51.0671736],[14.2532965,51.0044508],[14.4029134,50.9322145],[14.3729901,50.897627],[14.2433221,50.9070625],[14.2084114,50.844123],[14.0338583,50.8126214],[13.9789988,50.8252246],[13.9041903,50.7968626],[13.8742669,50.740087],[13.5351352,50.7243038],[13.530148,50.6579561],[13.4703012,50.6136722],[13.3905055,50.664279],[13.3256715,50.5883483],[13.250863,50.6105074],[13.1960035,50.5059517],[13.0513738,50.5218084],[12.9665909,50.4106997],[12.8269484,50.4710483],[12.7022676,50.4138779],[12.5077656,50.401164],[12.343187,50.2547088],[12.323238,50.1845054],[12.2484296,50.2738373],[12.1736211,50.3311765],[12.0988126,50.33436],[12.1187616,50.25152],[12.2234934,50.1653411],[12.2035445,50.1237921],[12.5027784,49.9732751],[12.4778422,49.9379795],[12.5476634,49.9155052],[12.4678677,49.8029766],[12.408021,49.7611134],[12.4828294,49.6869593],[12.5327017,49.6869593],[12.5177401,49.6288466],[12.6075102,49.5415474],[12.6723442,49.4378793],[12.8119867,49.3469896],[12.9466419,49.3437405],[13.2309141,49.1288206],[13.3256715,49.1059712],[13.4353906,49.0438984],[13.4154417,48.9948387],[13.5002246,48.949006],[13.5650586,48.9882938],[13.6847522,48.8834577],[13.7445989,48.9031312],[13.8243946,48.7751149],[13.8992031,48.7751149],[14.0587945,48.676418],[14.0438328,48.6302932],[14.1435774,48.5907241],[14.3729901,48.5610269],[14.4827091,48.6500662],[14.5774665,48.607215],[14.6273389,48.6335892],[14.7071346,48.5808269],[14.7470324,48.7027561],[14.8118664,48.7389485],[14.8168536,48.794831],[14.9864195,48.7652539],[15.0063684,49.0177392]]],"overlay":true},{"id":"Czech_RUIAN-budovy","name":"Czech RUIAN budovy","type":"tms","template":"http://tile.poloha.net/budovy/{zoom}/{x}/{y}.png","scaleExtent":[12,20],"polygon":[[[15.0063684,49.0177392],[15.1559854,49.0013828],[15.190896,48.9424551],[15.3105895,48.9882938],[15.4053469,48.9752013],[15.5400022,48.9162426],[15.7145553,48.8670572],[15.8342488,48.880178],[15.968904,48.8178233],[16.0885976,48.7455261],[16.3978059,48.7455261],[16.4875761,48.8145394],[16.6721036,48.7784014],[16.6820781,48.7356594],[16.9015163,48.7126294],[16.9464014,48.6237005],[17.1159672,48.8375227],[17.2107246,48.880178],[17.4052266,48.8178233],[17.4800351,48.8539329],[17.5299074,48.8178233],[17.7044605,48.8670572],[17.8141796,48.9359033],[17.8840008,48.9359033],[17.9438476,49.0210099],[18.0635412,49.0340903],[18.1184007,49.0994409],[18.1981964,49.3047337],[18.3877112,49.3339917],[18.577226,49.5091747],[18.7567663,49.4994587],[18.8465365,49.5253637],[18.8764598,49.5706645],[18.7966641,49.693412],[18.64206,49.7095399],[18.5872004,49.8351543],[18.6121366,49.8833809],[18.5622643,49.9347695],[18.512392,49.9058702],[18.362775,49.9540261],[18.3278644,49.9219275],[18.2630304,49.9732751],[18.1184007,50.0053395],[18.0635412,50.075806],[17.9139242,49.9796897],[17.779269,50.0309757],[17.714435,50.1237921],[17.6047159,50.1653411],[17.7593201,50.21962],[17.7343839,50.3439092],[17.6396265,50.2802117],[17.3802905,50.2802117],[17.3503671,50.3439092],[17.2805459,50.3375433],[17.1857885,50.4075214],[16.9015163,50.4615247],[16.8666057,50.4138779],[16.9663503,50.3184404],[17.0361715,50.2323826],[16.8366823,50.21962],[16.7120015,50.1046034],[16.5823335,50.1589513],[16.5623846,50.2387626],[16.4327166,50.3375433],[16.3529209,50.3916263],[16.2781124,50.3916263],[16.2082911,50.4456477],[16.3978059,50.5344899],[16.4476782,50.5978464],[16.3529209,50.670601],[16.2382145,50.6769221],[16.2182656,50.6326561],[16.1284954,50.6832425],[16.0486997,50.6073425],[15.988853,50.7021983],[15.8741467,50.6832425],[15.8292616,50.7653291],[15.729517,50.743243],[15.450232,50.8157725],[15.3903852,50.7747914],[15.3804108,50.8598659],[15.2956278,50.8850434],[15.2956278,50.9887568],[15.1709471,51.0201394],[14.9914067,51.0013124],[15.0063684,50.8881896],[14.8417898,50.8756034],[14.7969047,50.8252246],[14.6323261,50.8567177],[14.6622495,50.9353576],[14.5724793,50.9227841],[14.6123772,50.9856174],[14.4976708,51.0483657],[14.4178751,51.0232765],[14.3081561,51.0671736],[14.2532965,51.0044508],[14.4029134,50.9322145],[14.3729901,50.897627],[14.2433221,50.9070625],[14.2084114,50.844123],[14.0338583,50.8126214],[13.9789988,50.8252246],[13.9041903,50.7968626],[13.8742669,50.740087],[13.5351352,50.7243038],[13.530148,50.6579561],[13.4703012,50.6136722],[13.3905055,50.664279],[13.3256715,50.5883483],[13.250863,50.6105074],[13.1960035,50.5059517],[13.0513738,50.5218084],[12.9665909,50.4106997],[12.8269484,50.4710483],[12.7022676,50.4138779],[12.5077656,50.401164],[12.343187,50.2547088],[12.323238,50.1845054],[12.2484296,50.2738373],[12.1736211,50.3311765],[12.0988126,50.33436],[12.1187616,50.25152],[12.2234934,50.1653411],[12.2035445,50.1237921],[12.5027784,49.9732751],[12.4778422,49.9379795],[12.5476634,49.9155052],[12.4678677,49.8029766],[12.408021,49.7611134],[12.4828294,49.6869593],[12.5327017,49.6869593],[12.5177401,49.6288466],[12.6075102,49.5415474],[12.6723442,49.4378793],[12.8119867,49.3469896],[12.9466419,49.3437405],[13.2309141,49.1288206],[13.3256715,49.1059712],[13.4353906,49.0438984],[13.4154417,48.9948387],[13.5002246,48.949006],[13.5650586,48.9882938],[13.6847522,48.8834577],[13.7445989,48.9031312],[13.8243946,48.7751149],[13.8992031,48.7751149],[14.0587945,48.676418],[14.0438328,48.6302932],[14.1435774,48.5907241],[14.3729901,48.5610269],[14.4827091,48.6500662],[14.5774665,48.607215],[14.6273389,48.6335892],[14.7071346,48.5808269],[14.7470324,48.7027561],[14.8118664,48.7389485],[14.8168536,48.794831],[14.9864195,48.7652539],[15.0063684,49.0177392]]],"terms_url":"http://poloha.net/"},{"id":"Czech_RUIAN-parcely","name":"Czech RUIAN parcely","type":"tms","template":"http://tile.poloha.net/parcely/{zoom}/{x}/{y}.png","scaleExtent":[12,20],"polygon":[[[15.0063684,49.0177392],[15.1559854,49.0013828],[15.190896,48.9424551],[15.3105895,48.9882938],[15.4053469,48.9752013],[15.5400022,48.9162426],[15.7145553,48.8670572],[15.8342488,48.880178],[15.968904,48.8178233],[16.0885976,48.7455261],[16.3978059,48.7455261],[16.4875761,48.8145394],[16.6721036,48.7784014],[16.6820781,48.7356594],[16.9015163,48.7126294],[16.9464014,48.6237005],[17.1159672,48.8375227],[17.2107246,48.880178],[17.4052266,48.8178233],[17.4800351,48.8539329],[17.5299074,48.8178233],[17.7044605,48.8670572],[17.8141796,48.9359033],[17.8840008,48.9359033],[17.9438476,49.0210099],[18.0635412,49.0340903],[18.1184007,49.0994409],[18.1981964,49.3047337],[18.3877112,49.3339917],[18.577226,49.5091747],[18.7567663,49.4994587],[18.8465365,49.5253637],[18.8764598,49.5706645],[18.7966641,49.693412],[18.64206,49.7095399],[18.5872004,49.8351543],[18.6121366,49.8833809],[18.5622643,49.9347695],[18.512392,49.9058702],[18.362775,49.9540261],[18.3278644,49.9219275],[18.2630304,49.9732751],[18.1184007,50.0053395],[18.0635412,50.075806],[17.9139242,49.9796897],[17.779269,50.0309757],[17.714435,50.1237921],[17.6047159,50.1653411],[17.7593201,50.21962],[17.7343839,50.3439092],[17.6396265,50.2802117],[17.3802905,50.2802117],[17.3503671,50.3439092],[17.2805459,50.3375433],[17.1857885,50.4075214],[16.9015163,50.4615247],[16.8666057,50.4138779],[16.9663503,50.3184404],[17.0361715,50.2323826],[16.8366823,50.21962],[16.7120015,50.1046034],[16.5823335,50.1589513],[16.5623846,50.2387626],[16.4327166,50.3375433],[16.3529209,50.3916263],[16.2781124,50.3916263],[16.2082911,50.4456477],[16.3978059,50.5344899],[16.4476782,50.5978464],[16.3529209,50.670601],[16.2382145,50.6769221],[16.2182656,50.6326561],[16.1284954,50.6832425],[16.0486997,50.6073425],[15.988853,50.7021983],[15.8741467,50.6832425],[15.8292616,50.7653291],[15.729517,50.743243],[15.450232,50.8157725],[15.3903852,50.7747914],[15.3804108,50.8598659],[15.2956278,50.8850434],[15.2956278,50.9887568],[15.1709471,51.0201394],[14.9914067,51.0013124],[15.0063684,50.8881896],[14.8417898,50.8756034],[14.7969047,50.8252246],[14.6323261,50.8567177],[14.6622495,50.9353576],[14.5724793,50.9227841],[14.6123772,50.9856174],[14.4976708,51.0483657],[14.4178751,51.0232765],[14.3081561,51.0671736],[14.2532965,51.0044508],[14.4029134,50.9322145],[14.3729901,50.897627],[14.2433221,50.9070625],[14.2084114,50.844123],[14.0338583,50.8126214],[13.9789988,50.8252246],[13.9041903,50.7968626],[13.8742669,50.740087],[13.5351352,50.7243038],[13.530148,50.6579561],[13.4703012,50.6136722],[13.3905055,50.664279],[13.3256715,50.5883483],[13.250863,50.6105074],[13.1960035,50.5059517],[13.0513738,50.5218084],[12.9665909,50.4106997],[12.8269484,50.4710483],[12.7022676,50.4138779],[12.5077656,50.401164],[12.343187,50.2547088],[12.323238,50.1845054],[12.2484296,50.2738373],[12.1736211,50.3311765],[12.0988126,50.33436],[12.1187616,50.25152],[12.2234934,50.1653411],[12.2035445,50.1237921],[12.5027784,49.9732751],[12.4778422,49.9379795],[12.5476634,49.9155052],[12.4678677,49.8029766],[12.408021,49.7611134],[12.4828294,49.6869593],[12.5327017,49.6869593],[12.5177401,49.6288466],[12.6075102,49.5415474],[12.6723442,49.4378793],[12.8119867,49.3469896],[12.9466419,49.3437405],[13.2309141,49.1288206],[13.3256715,49.1059712],[13.4353906,49.0438984],[13.4154417,48.9948387],[13.5002246,48.949006],[13.5650586,48.9882938],[13.6847522,48.8834577],[13.7445989,48.9031312],[13.8243946,48.7751149],[13.8992031,48.7751149],[14.0587945,48.676418],[14.0438328,48.6302932],[14.1435774,48.5907241],[14.3729901,48.5610269],[14.4827091,48.6500662],[14.5774665,48.607215],[14.6273389,48.6335892],[14.7071346,48.5808269],[14.7470324,48.7027561],[14.8118664,48.7389485],[14.8168536,48.794831],[14.9864195,48.7652539],[15.0063684,49.0177392]]],"terms_url":"http://poloha.net/"},{"id":"Duna_2013","name":"Danube flood orthophoto 2013","type":"tms","template":"http://e.tile.openstreetmap.hu/dunai-arviz-2013/{zoom}/{x}/{y}.jpg","scaleExtent":[10,20],"polygon":[[[19.0773152,47.6959718],[19.0779881,47.6959835],[19.0946205,47.6944562],[19.0805603,47.595874],[19.0743376,47.5890907],[19.0795196,47.5888284],[19.07717,47.5724109],[19.0577884,47.5720924],[19.0773152,47.6959718]]],"terms_url":"http://fototerkep.hu/","terms_text":"Fotótérkép.hu"},{"id":"Delaware2012Orthophotography","name":"Delaware 2012 Orthophotography","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/0/https://firstmap.delaware.gov/arcgis/services/DE_Imagery/DE_Imagery_2012/ImageServer/WMSServer","description":"This data set consists of 0.3-meter pixel resolution (approximately 1-foot), 4-band true color and near infrared (R, G, B, IR) orthoimages covering New Castle, Kent and Sussex Counties in Delaware.","polygon":[[[-75.01770587603,38.45188674427],[-75.74173524589,38.4499581145],[-75.80699639658,39.73907123636],[-75.75558784863,39.80106251053],[-75.64692187603,39.8563815616],[-75.47114773904,39.84645578141],[-75.37725787603,39.81477822231],[-75.48746302671,39.6718115509],[-75.50901151986,39.43446011595],[-75.39326532808,39.27784018498],[-75.30707135548,39.01666513594],[-75.1931721774,38.82218696272],[-75.05341480753,38.80875503297],[-75.01770587603,38.45188674427]]],"terms_url":"https://firstmap.delaware.gov/arcgis/rest/services/DE_Imagery/DE_Imagery_2012/ImageServer","terms_text":"Digital Aerial Solutions, LLC"},{"id":"DigitalGlobe-Premium","name":"DigitalGlobe Premium Imagery","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/digitalglobe.316c9a2e/{zoom}/{x}/{y}.png?access_token=pk.eyJ1IjoiZGlnaXRhbGdsb2JlIiwiYSI6ImNqMmFxdGp5aTAwOWIzM3M1NDZ2eGU1a2QifQ.JN5adNxCwK_oprEwFEtjjg","scaleExtent":[0,19],"terms_url":"https://wiki.openstreetmap.org/wiki/DigitalGlobe","terms_text":"Terms & Feedback","default":true},{"id":"DigitalGlobe-Standard","name":"DigitalGlobe Standard Imagery","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/digitalglobe.0a8e44ba/{zoom}/{x}/{y}.png?access_token=pk.eyJ1IjoiZGlnaXRhbGdsb2JlIiwiYSI6ImNqMmFxcGJ2MjAwOHEzMm9nZmF2c3luZWkifQ.HsF19zOlj8PeOxo5BhNqyQ","scaleExtent":[0,19],"terms_url":"https://wiki.openstreetmap.org/wiki/DigitalGlobe","terms_text":"Terms & Feedback","default":true},{"id":"maaamet.ee-orto","name":"Estonia Ortho (Maaamet)","type":"tms","template":"http://kaart.maakaart.ee/orto/{zoom}/{x}/{y}.jpeg","scaleExtent":[14,20],"polygon":[[[21.6940073,57.5025466],[21.6940073,59.8274564],[28.2110546,59.8274564],[28.2110546,57.5025466],[21.6940073,57.5025466]]],"terms_text":"Maa-Ameti ortofoto"},{"id":"FOMI_2000","name":"FÖMI orthophoto 2000","type":"tms","template":"http://e.tile.openstreetmap.hu/ortofoto2000/{zoom}/{x}/{y}.jpg","description":"Hungary","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","description":"Hungary","scaleExtent":[0,17],"polygon":[[[16.1139147,46.8691038],[16.1789749,46.90662],[16.2000429,46.9415079],[16.2217547,46.9355441],[16.2462784,46.9463851],[16.2553226,46.9642125],[16.2764694,46.9626082],[16.290583,47.0139849],[16.3016199,46.9992329],[16.3414618,46.9965225],[16.3505162,47.0106313],[16.3734016,46.9985929],[16.412765,47.00475],[16.4332705,46.9927417],[16.4478119,47.003893],[16.479997,46.9941169],[16.5121988,47.0011695],[16.4635584,47.0322699],[16.4478586,47.0227481],[16.439123,47.029663],[16.445673,47.038872],[16.520323,47.056103],[16.473213,47.0736169],[16.4637199,47.09392],[16.500798,47.110058],[16.500035,47.123295],[16.5295349,47.1287419],[16.5171609,47.1496938],[16.454951,47.1425878],[16.4648728,47.1683349],[16.4555643,47.1875584],[16.4305559,47.1847022],[16.4195013,47.1949147],[16.4189215,47.2107114],[16.4371293,47.2097043],[16.4426335,47.2337117],[16.4313127,47.2527554],[16.4671512,47.2531652],[16.4892319,47.2798885],[16.4646338,47.3338455],[16.4337002,47.3528101],[16.458513,47.3670496],[16.4454619,47.4070195],[16.4831657,47.4093628],[16.4963821,47.3892659],[16.5170941,47.4100218],[16.5749054,47.4054243],[16.5807291,47.4191699],[16.661847,47.455595],[16.6706419,47.47422],[16.6523395,47.500342],[16.6895619,47.510161],[16.7147797,47.540199],[16.663545,47.567733],[16.673199,47.6049544],[16.6595343,47.6061018],[16.652758,47.622852],[16.6314207,47.6283176],[16.5739108,47.619667],[16.5147382,47.6461964],[16.4967504,47.6393149],[16.425464,47.6621679],[16.4437449,47.674205],[16.4480507,47.6964725],[16.4746984,47.6811576],[16.4872245,47.6979767],[16.5521729,47.7225519],[16.5363779,47.736785],[16.5479799,47.751544],[16.6095193,47.7603722],[16.6344148,47.7590843],[16.65729,47.7414879],[16.7209405,47.7353565],[16.7534062,47.6828165],[16.8301587,47.681058],[16.8394284,47.7045139],[16.8668943,47.7211462],[16.876679,47.6876452],[17.0937421,47.7077706],[17.0706562,47.7285366],[17.0516019,47.7938499],[17.0749479,47.8084997],[17.047139,47.8285635],[17.0519452,47.8377691],[17.0105513,47.8581765],[17.0163878,47.8673325],[17.0857537,47.8746239],[17.113171,47.9271605],[17.0917133,47.9342916],[17.1183782,47.9601083],[17.094657,47.9708775],[17.2010289,48.019992],[17.241769,48.0224651],[17.257955,47.998655],[17.334651,47.993125],[17.4029929,47.947849],[17.4539199,47.8852579],[17.5267369,47.865509],[17.5675779,47.8151289],[17.608402,47.8218859],[17.7085789,47.756678],[17.7798739,47.739487],[17.8660959,47.74575],[17.9001292,47.7392633],[17.946867,47.744668],[17.9708709,47.7578392],[18.0044103,47.7463402],[18.0380583,47.7576812],[18.2958774,47.7314616],[18.4540681,47.7651226],[18.4931553,47.7527552],[18.5590761,47.7659963],[18.6460866,47.7590921],[18.7260691,47.7890411],[18.7411784,47.8138245],[18.7920013,47.8230869],[18.8485417,47.8167221],[18.855876,47.826077],[18.828014,47.834291],[18.8135749,47.85555],[18.76353,47.8716049],[18.756858,47.896838],[18.776746,47.955092],[18.7552499,47.9763469],[18.8157429,47.993442],[18.819998,48.039676],[18.833268,48.048239],[18.8749364,48.0470707],[18.886674,48.058682],[18.9089819,48.051139],[18.9439039,48.058865],[18.9816099,48.0536009],[19.0148639,48.078179],[19.0585249,48.0573529],[19.0843619,48.072781],[19.107402,48.065596],[19.1352889,48.074146],[19.2413679,48.0536529],[19.2557819,48.0715559],[19.3031119,48.088711],[19.3865969,48.091914],[19.400018,48.082304],[19.454053,48.101436],[19.467354,48.083933],[19.4944199,48.109906],[19.492377,48.1396639],[19.5128219,48.154663],[19.504518,48.173443],[19.528967,48.190358],[19.526044,48.20313],[19.577502,48.2160149],[19.6308263,48.2500725],[19.6445239,48.2391719],[19.669857,48.239212],[19.691219,48.203894],[19.721125,48.201473],[19.74618,48.2165119],[19.7871629,48.19253],[19.7987329,48.19482],[19.8052829,48.183733],[19.782415,48.165039],[19.794812,48.153529],[19.821331,48.169081],[19.8452819,48.162742],[19.8551729,48.178431],[19.8601309,48.169409],[19.898745,48.1663119],[19.9145359,48.146863],[19.898298,48.1249019],[19.937383,48.131118],[19.9743939,48.1660049],[19.988706,48.1621679],[20.029038,48.1776849],[20.049449,48.1671999],[20.0729859,48.179606],[20.0700369,48.1917019],[20.1340909,48.225182],[20.1331879,48.253982],[20.206162,48.250979],[20.2038299,48.261906],[20.228466,48.262779],[20.2349469,48.279933],[20.286858,48.26164],[20.3257109,48.272794],[20.3374649,48.301667],[20.3656579,48.316606],[20.384077,48.3511809],[20.4098349,48.365857],[20.402532,48.382565],[20.4205349,48.403858],[20.416228,48.418536],[20.507929,48.489363],[20.5065069,48.534415],[20.537471,48.527878],[20.5464939,48.544292],[20.586595,48.535759],[20.6538739,48.561413],[20.836359,48.58284],[20.8378,48.57421],[20.8504359,48.5816329],[20.8453301,48.5665046],[20.8681549,48.551818],[20.922323,48.559453],[20.9346349,48.538341],[20.955882,48.533963],[20.9561979,48.521666],[20.9815849,48.5177669],[21.0151139,48.532313],[21.0663209,48.525894],[21.1174479,48.4910549],[21.1608749,48.521499],[21.179634,48.518232],[21.221061,48.537497],[21.305488,48.5222489],[21.313377,48.550841],[21.326875,48.554129],[21.319384,48.561201],[21.4154499,48.558951],[21.4226649,48.578821],[21.4406099,48.585104],[21.514091,48.551065],[21.5420199,48.508395],[21.6139329,48.509416],[21.6201879,48.469826],[21.663549,48.417961],[21.6645609,48.392164],[21.7017409,48.380695],[21.711871,48.357617],[21.8174139,48.332787],[21.8352029,48.3346409],[21.837213,48.363253],[21.8842979,48.356047],[21.8848429,48.367539],[21.897883,48.36256],[21.8997959,48.3702229],[21.9281859,48.3615969],[21.9268059,48.370899],[21.949198,48.378728],[21.994463,48.377323],[22.0213259,48.392749],[22.0546049,48.377528],[22.0764859,48.387241],[22.086743,48.371564],[22.1359089,48.380519],[22.131056,48.3912329],[22.152768,48.3962409],[22.1561913,48.4093076],[22.2125722,48.4256468],[22.2371405,48.4100396],[22.2654858,48.4098675],[22.2398761,48.3870055],[22.2675722,48.3611612],[22.3178106,48.3545437],[22.3132861,48.3250712],[22.3372944,48.3079113],[22.3384267,48.2792074],[22.3847547,48.2339632],[22.4006407,48.249198],[22.4328384,48.2525166],[22.456386,48.2423109],[22.4899029,48.2534237],[22.4972201,48.2395546],[22.5161491,48.237965],[22.5311088,48.2094282],[22.5711442,48.1961428],[22.5616362,48.1816066],[22.5982449,48.144756],[22.5902763,48.1073414],[22.6754492,48.091997],[22.7347192,48.119848],[22.7576242,48.1200599],[22.7703914,48.1090162],[22.772319,48.1218742],[22.8027688,48.1221112],[22.8025285,48.1070813],[22.8254256,48.1175119],[22.8364365,48.080249],[22.8611284,48.0750312],[22.8677955,48.0524256],[22.8820424,48.0548053],[22.8659692,48.0113165],[22.835562,47.9905988],[22.8407599,47.9813636],[22.8725729,47.9752683],[22.8697274,47.9659593],[22.8915652,47.9672446],[22.897435,47.9540629],[22.8473299,47.9077579],[22.7928135,47.8908586],[22.7586924,47.8941446],[22.77775,47.8422508],[22.7136344,47.8360928],[22.6801938,47.7877527],[22.6111171,47.7717455],[22.5490018,47.7722246],[22.4812121,47.8108886],[22.4513078,47.803389],[22.4313319,47.7398119],[22.3566167,47.7486206],[22.3177714,47.7660887],[22.3176236,47.7433657],[22.2851369,47.7292757],[22.264325,47.7310675],[22.2589955,47.6979057],[22.2306796,47.693196],[22.1796501,47.5916115],[22.1289245,47.5978984],[22.0942787,47.5583628],[22.0782587,47.5621299],[22.0534529,47.5474795],[22.0712176,47.5380742],[22.0617872,47.5288029],[22.0451278,47.5398919],[22.0367222,47.5326653],[22.0071886,47.48362],[22.0327909,47.4508372],[22.0238835,47.3908631],[22.0119849,47.3758016],[21.9627373,47.381053],[21.9382461,47.3725317],[21.8777922,47.2857763],[21.8872845,47.2730473],[21.8534909,47.2397622],[21.8580662,47.1873597],[21.8124804,47.1667511],[21.7924092,47.1059751],[21.7268258,47.0983882],[21.6976037,47.057915],[21.6504151,47.0408303],[21.6888701,47.0019977],[21.6678744,46.9712337],[21.6814917,46.9652089],[21.6381964,46.9330487],[21.5984455,46.9274708],[21.6142857,46.8867275],[21.6016694,46.8668202],[21.520328,46.8373749],[21.5186086,46.8000703],[21.4831761,46.7650246],[21.5263389,46.7393249],[21.529369,46.7209721],[21.4923253,46.6859652],[21.4728438,46.6959075],[21.4299047,46.693937],[21.4309553,46.6781367],[21.4546661,46.660863],[21.4162375,46.6426231],[21.4097959,46.6218052],[21.3657038,46.6379501],[21.3300499,46.6318155],[21.3139733,46.617666],[21.3012351,46.5908672],[21.3207905,46.5828562],[21.2743045,46.5407362],[21.2600254,46.5021583],[21.2744188,46.4767333],[21.2964506,46.4762973],[21.3174343,46.4507288],[21.2895176,46.4154784],[21.2963256,46.4069601],[21.2250116,46.4136899],[21.2064214,46.4033825],[21.1992563,46.3479034],[21.1762269,46.3357664],[21.180497,46.3044494],[21.1155437,46.3018529],[21.1030549,46.2624637],[21.0708792,46.2539014],[21.0660827,46.2429394],[21.0366237,46.2480392],[21.0246723,46.2665329],[20.960817,46.2623039],[20.9465849,46.2793024],[20.9250701,46.2766191],[20.9218133,46.2618129],[20.8732713,46.2877555],[20.7756538,46.2759602],[20.7490474,46.2508489],[20.7618619,46.204563],[20.727401,46.2077485],[20.7341052,46.1939355],[20.7140487,46.1660531],[20.6843592,46.1447802],[20.6549178,46.1497739],[20.6394471,46.1267602],[20.5450486,46.1790935],[20.5014839,46.190334],[20.4949436,46.1709908],[20.4592293,46.1428837],[20.3975133,46.1574709],[20.3685325,46.1528554],[20.3557074,46.1696256],[20.2968136,46.1521542],[20.2549024,46.1158522],[20.2484757,46.1300956],[20.2330132,46.1241668],[20.1817362,46.1601137],[20.1364966,46.1449476],[20.1009667,46.1772756],[20.0636156,46.1437275],[20.0346142,46.1458888],[20.0158072,46.1768354],[19.9354075,46.1764243],[19.8533469,46.1500005],[19.8179747,46.1281652],[19.7585403,46.1479754],[19.6982054,46.1879317],[19.6827672,46.1800388],[19.661508,46.1904394],[19.6317396,46.1692993],[19.5676482,46.179106],[19.5604013,46.1665762],[19.5026585,46.1424492],[19.5271208,46.1210269],[19.4645033,46.0953827],[19.4665828,46.0820437],[19.4160037,46.0460453],[19.3803957,46.0358749],[19.3640923,46.0522965],[19.2819012,46.0148048],[19.2965348,45.9881173],[19.2856472,45.9968981],[19.1479857,45.9963445],[19.1338422,46.0370993],[19.104873,46.0401673],[19.0660427,46.0001999],[19.0796791,45.9636376],[19.0059803,45.9590674],[19.0092745,45.9236559],[18.9061334,45.9353801],[18.8794572,45.9166827],[18.8647137,45.9208493],[18.8685629,45.9113361],[18.8276792,45.9051714],[18.8220041,45.9145893],[18.8075092,45.9036055],[18.809247,45.8796189],[18.7956242,45.8784488],[18.7048857,45.9181883],[18.6700246,45.9108439],[18.6596602,45.9168934],[18.6651348,45.899279],[18.6412808,45.8890396],[18.6550179,45.8742393],[18.6277704,45.8733782],[18.6148449,45.8531438],[18.6236656,45.8398531],[18.5732391,45.8137578],[18.5749849,45.8004344],[18.559716,45.8037961],[18.5223504,45.7826858],[18.4906706,45.7947167],[18.4821905,45.7655032],[18.4562828,45.7695229],[18.4450763,45.7605195],[18.446853,45.737128],[18.40763,45.7397119],[18.3918949,45.7616983],[18.3642257,45.7729364],[18.3394214,45.7471605],[18.2968157,45.7612196],[18.2440473,45.7612305],[18.2307311,45.7790328],[18.1908702,45.7878759],[18.1681939,45.7762712],[18.1246514,45.7896277],[18.1068067,45.7708256],[18.0818922,45.7645205],[17.9958808,45.7957311],[17.9302095,45.7863301],[17.9066757,45.7925692],[17.8653145,45.7670064],[17.8262748,45.8099957],[17.8089784,45.8040989],[17.7809054,45.8174884],[17.7603399,45.811923],[17.7408624,45.8295975],[17.6632915,45.8381849],[17.6276211,45.8979446],[17.5700676,45.9358204],[17.4378254,45.9503823],[17.4258964,45.9272681],[17.4108059,45.9399665],[17.392149,45.9302149],[17.3828713,45.9475733],[17.3476208,45.9423413],[17.3438769,45.9605329],[17.3537711,45.9525011],[17.3905375,45.9581914],[17.387423,45.9661823],[17.3583539,45.9642737],[17.3754852,45.9686921],[17.3751895,45.9881054],[17.3635685,45.9915442],[17.3567202,45.9735836],[17.3339583,45.9960781],[17.3319847,45.9728948],[17.3129974,45.9665347],[17.323647,45.9887776],[17.2987653,45.9838652],[17.3041996,46.0021128],[17.2579726,46.0110256],[17.29632,46.0285169],[17.2541514,46.030005],[17.270955,46.0567055],[17.2324767,46.0592034],[17.2525145,46.0664725],[17.2313144,46.0790345],[17.2019916,46.0765488],[17.2331299,46.0989644],[17.2104017,46.1001693],[17.2129734,46.113855],[17.175927,46.1084583],[17.1743424,46.1287608],[17.1865197,46.1332308],[17.1810983,46.1505485],[17.1562307,46.1585819],[17.1592857,46.1696818],[17.1261012,46.1684495],[17.1227409,46.1789791],[17.0752482,46.1889531],[17.0661614,46.2022984],[16.9735401,46.2251982],[16.973954,46.2431113],[16.9504085,46.2415285],[16.8862356,46.2814598],[16.8713682,46.3252767],[16.8802109,46.3356966],[16.8615374,46.3452401],[16.8656232,46.3556489],[16.8521959,46.3517189],[16.8498589,46.3626245],[16.8352859,46.3638195],[16.8376499,46.3748032],[16.8261732,46.3670994],[16.7933444,46.387385],[16.7592072,46.3776563],[16.7298672,46.40149],[16.7182119,46.3898704],[16.6772872,46.4494536],[16.6631785,46.4486958],[16.6663732,46.4582995],[16.6187915,46.4619875],[16.604468,46.4760773],[16.5235997,46.5053761],[16.5325768,46.5314027],[16.5176728,46.5363516],[16.5084107,46.5652692],[16.4829969,46.5660383],[16.4834008,46.5786011],[16.4455713,46.610952],[16.4248583,46.6131645],[16.385941,46.6442485],[16.3915424,46.6637257],[16.4198454,46.6584771],[16.4286335,46.6939737],[16.3689211,46.7040082],[16.3798266,46.7153869],[16.3710856,46.7222945],[16.3570587,46.7142387],[16.3185954,46.7541449],[16.3305417,46.7752119],[16.3121626,46.7780033],[16.3127666,46.797314],[16.3406373,46.8051851],[16.3508404,46.8300552],[16.3403309,46.8468762],[16.3015007,46.8595142],[16.2913867,46.8728341],[16.2332296,46.8766702],[16.1560866,46.8537074],[16.126571,46.8569079],[16.1139147,46.8691038]]],"terms_url":"http://www.fomi.hu/","terms_text":"Földmérési és Távérzékelési Intézet"},{"id":"FR-BAN","name":"FR-BAN","type":"tms","template":"http://{switch:a,b,c}.layers.openstreetmap.fr/bano/{zoom}/{x}/{y}.png","description":"French address registry or Base Adresses Nationale","scaleExtent":[12,20],"polygon":[[[8.3247852,49.0891892],[6.1566882,49.6167369],[4.8666714,50.2126152],[2.4937064,51.1761675],[1.3121526,50.9324682],[1.2659981,50.1877492],[0.1121369,49.8258592],[-0.3494075,49.4312336],[-1.0232625,49.4852345],[-1.3278818,49.7901162],[-2.1032765,49.7901162],[-1.6232703,48.7420657],[-3.1002126,48.9728514],[-5.1125465,48.6811558],[-5.3525496,48.4367783],[-4.5984193,47.7194959],[-2.555398,47.0232784],[-2.4738077,46.6638823],[-1.6676954,46.1055717],[-1.334807,45.5141125],[-1.4914604,44.1627003],[-1.9940567,43.3708146],[-0.956228,42.7364747],[2.2029487,42.2841894],[3.2342502,42.5444129],[3.2407774,43.1140543],[4.0436261,43.3280964],[6.4325902,42.808345],[7.6270723,43.5934102],[7.8163619,44.1720643],[7.0396221,44.41967],[7.268075,45.4958141],[7.1244761,46.2140775],[6.5631347,46.771283],[7.6571492,47.59128],[7.6527839,47.5941813],[7.6224698,47.5776739],[7.6047297,47.578221],[7.5877054,47.5901532],[7.521558,47.65161],[7.503992,47.70235],[7.520958,47.77685],[7.557124,47.84839],[7.549463,47.879205],[7.574615,47.93028],[7.613179,47.96804],[7.611904,47.9871],[7.5612401,48.0383618],[7.574915,48.1258],[7.595338,48.15977],[7.633047,48.19717],[7.662748,48.22473],[7.684659,48.30305],[7.763463,48.49158],[7.8004602,48.5125977],[7.799582,48.5878],[7.834088,48.64439],[7.9121073,48.6889897],[7.9672295,48.7571585],[8.020692,48.78879],[8.043024,48.7956],[8.0864658,48.8130551],[8.1364418,48.8978239],[8.1970586,48.96021],[8.2816129,48.9948995],[8.2996723,49.025966],[8.3124269,49.0599642],[8.3247852,49.0891892]],[[9.3609615,43.1345098],[8.4393174,42.48439],[8.4836272,41.8175373],[8.8469677,41.3768281],[9.2058772,41.3136241],[9.48946,41.5461776],[9.6356823,42.1994563],[9.6046655,42.901254],[9.3609615,43.1345098]]],"terms_url":"https://wiki.openstreetmap.org/wiki/WikiProject_France/WikiProject_Base_Adresses_Nationale_Ouverte_(BANO)","terms_text":"Tiles © cquest@Openstreetmap France, data © OpenStreetMap contributors, ODBL"},{"id":"FR-Cadastre","name":"FR-Cadastre","type":"tms","template":"http://tms.cadastre.openstreetmap.fr/*/tout/{zoom}/{x}/{y}.png","description":"French land registry","scaleExtent":[12,20],"polygon":[[[8.3247852,49.0891892],[6.1566882,49.6167369],[4.8666714,50.2126152],[2.4937064,51.1761675],[1.3121526,50.9324682],[1.2659981,50.1877492],[0.1121369,49.8258592],[-0.3494075,49.4312336],[-1.0232625,49.4852345],[-1.3278818,49.7901162],[-2.1032765,49.7901162],[-1.6232703,48.7420657],[-3.1002126,48.9728514],[-5.1125465,48.6811558],[-5.3525496,48.4367783],[-4.5984193,47.7194959],[-2.555398,47.0232784],[-2.4738077,46.6638823],[-1.6676954,46.1055717],[-1.334807,45.5141125],[-1.4914604,44.1627003],[-1.9940567,43.3708146],[-0.956228,42.7364747],[2.2029487,42.2841894],[3.2342502,42.5444129],[3.2407774,43.1140543],[4.0436261,43.3280964],[6.4325902,42.808345],[7.6270723,43.5934102],[7.8163619,44.1720643],[7.0396221,44.41967],[7.268075,45.4958141],[7.1244761,46.2140775],[6.5631347,46.771283],[7.6571492,47.59128],[7.6527839,47.5941813],[7.6224698,47.5776739],[7.6047297,47.578221],[7.5877054,47.5901532],[7.521558,47.65161],[7.503992,47.70235],[7.520958,47.77685],[7.557124,47.84839],[7.549463,47.879205],[7.574615,47.93028],[7.613179,47.96804],[7.611904,47.9871],[7.5612401,48.0383618],[7.574915,48.1258],[7.595338,48.15977],[7.633047,48.19717],[7.662748,48.22473],[7.684659,48.30305],[7.763463,48.49158],[7.8004602,48.5125977],[7.799582,48.5878],[7.834088,48.64439],[7.9121073,48.6889897],[7.9672295,48.7571585],[8.020692,48.78879],[8.043024,48.7956],[8.0864658,48.8130551],[8.1364418,48.8978239],[8.1970586,48.96021],[8.2816129,48.9948995],[8.2996723,49.025966],[8.3124269,49.0599642],[8.3247852,49.0891892]],[[9.3609615,43.1345098],[8.4393174,42.48439],[8.4836272,41.8175373],[8.8469677,41.3768281],[9.2058772,41.3136241],[9.48946,41.5461776],[9.6356823,42.1994563],[9.6046655,42.901254],[9.3609615,43.1345098]]],"terms_url":"http://wiki.openstreetmap.org/wiki/WikiProject_Cadastre_Fran%C3%A7ais/Conditions_d%27utilisation","terms_text":"cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : 2015"},{"id":"Freemap.sk-Car","name":"Freemap.sk Car","type":"tms","template":"http://t{switch:1,2,3,4}.freemap.sk/A/{zoom}/{x}/{y}.jpeg","scaleExtent":[8,16],"polygon":[[[19.83682,49.25529],[19.80075,49.42385],[19.60437,49.48058],[19.49179,49.63961],[19.21831,49.52604],[19.16778,49.42521],[19.00308,49.42236],[18.97611,49.5308],[18.54685,49.51425],[18.31432,49.33818],[18.15913,49.2961],[18.05564,49.11134],[17.56396,48.84938],[17.17929,48.88816],[17.058,48.81105],[16.90426,48.61947],[16.79685,48.38561],[17.06762,48.01116],[17.32787,47.97749],[17.51699,47.82535],[17.74776,47.73093],[18.29515,47.72075],[18.67959,47.75541],[18.89755,47.81203],[18.79463,47.88245],[18.84318,48.04046],[19.46212,48.05333],[19.62064,48.22938],[19.89585,48.09387],[20.33766,48.2643],[20.55395,48.52358],[20.82335,48.55714],[21.10271,48.47096],[21.45863,48.55513],[21.74536,48.31435],[22.15293,48.37179],[22.61255,49.08914],[22.09997,49.23814],[21.9686,49.36363],[21.6244,49.46989],[21.06873,49.46402],[20.94336,49.31088],[20.73052,49.44006],[20.22804,49.41714],[20.05234,49.23052],[19.83682,49.25529]]],"terms_text":"Copyright ©2007-2012 Freemap Slovakia (www.freemap.sk). Some rights reserved."},{"id":"Freemap.sk-Cyclo","name":"Freemap.sk Cyclo","type":"tms","template":"http://t{switch:1,2,3,4}.freemap.sk/C/{zoom}/{x}/{y}.jpeg","scaleExtent":[8,16],"polygon":[[[19.83682,49.25529],[19.80075,49.42385],[19.60437,49.48058],[19.49179,49.63961],[19.21831,49.52604],[19.16778,49.42521],[19.00308,49.42236],[18.97611,49.5308],[18.54685,49.51425],[18.31432,49.33818],[18.15913,49.2961],[18.05564,49.11134],[17.56396,48.84938],[17.17929,48.88816],[17.058,48.81105],[16.90426,48.61947],[16.79685,48.38561],[17.06762,48.01116],[17.32787,47.97749],[17.51699,47.82535],[17.74776,47.73093],[18.29515,47.72075],[18.67959,47.75541],[18.89755,47.81203],[18.79463,47.88245],[18.84318,48.04046],[19.46212,48.05333],[19.62064,48.22938],[19.89585,48.09387],[20.33766,48.2643],[20.55395,48.52358],[20.82335,48.55714],[21.10271,48.47096],[21.45863,48.55513],[21.74536,48.31435],[22.15293,48.37179],[22.61255,49.08914],[22.09997,49.23814],[21.9686,49.36363],[21.6244,49.46989],[21.06873,49.46402],[20.94336,49.31088],[20.73052,49.44006],[20.22804,49.41714],[20.05234,49.23052],[19.83682,49.25529]]],"terms_text":"Copyright ©2007-2012 Freemap Slovakia (www.freemap.sk). Some rights reserved."},{"id":"Freemap.sk-Hiking","name":"Freemap.sk Hiking","type":"tms","template":"http://t{switch:1,2,3,4}.freemap.sk/T/{zoom}/{x}/{y}.jpeg","scaleExtent":[8,16],"polygon":[[[19.83682,49.25529],[19.80075,49.42385],[19.60437,49.48058],[19.49179,49.63961],[19.21831,49.52604],[19.16778,49.42521],[19.00308,49.42236],[18.97611,49.5308],[18.54685,49.51425],[18.31432,49.33818],[18.15913,49.2961],[18.05564,49.11134],[17.56396,48.84938],[17.17929,48.88816],[17.058,48.81105],[16.90426,48.61947],[16.79685,48.38561],[17.06762,48.01116],[17.32787,47.97749],[17.51699,47.82535],[17.74776,47.73093],[18.29515,47.72075],[18.67959,47.75541],[18.89755,47.81203],[18.79463,47.88245],[18.84318,48.04046],[19.46212,48.05333],[19.62064,48.22938],[19.89585,48.09387],[20.33766,48.2643],[20.55395,48.52358],[20.82335,48.55714],[21.10271,48.47096],[21.45863,48.55513],[21.74536,48.31435],[22.15293,48.37179],[22.61255,49.08914],[22.09997,49.23814],[21.9686,49.36363],[21.6244,49.46989],[21.06873,49.46402],[20.94336,49.31088],[20.73052,49.44006],[20.22804,49.41714],[20.05234,49.23052],[19.83682,49.25529]]],"terms_text":"Copyright ©2007-2012 Freemap Slovakia (www.freemap.sk). Some rights reserved."},{"id":"Freemap.sk-Ski","name":"Freemap.sk Ski","type":"tms","template":"http://t{switch:1,2,3,4}.freemap.sk/K/{zoom}/{x}/{y}.jpeg","scaleExtent":[8,16],"polygon":[[[19.83682,49.25529],[19.80075,49.42385],[19.60437,49.48058],[19.49179,49.63961],[19.21831,49.52604],[19.16778,49.42521],[19.00308,49.42236],[18.97611,49.5308],[18.54685,49.51425],[18.31432,49.33818],[18.15913,49.2961],[18.05564,49.11134],[17.56396,48.84938],[17.17929,48.88816],[17.058,48.81105],[16.90426,48.61947],[16.79685,48.38561],[17.06762,48.01116],[17.32787,47.97749],[17.51699,47.82535],[17.74776,47.73093],[18.29515,47.72075],[18.67959,47.75541],[18.89755,47.81203],[18.79463,47.88245],[18.84318,48.04046],[19.46212,48.05333],[19.62064,48.22938],[19.89585,48.09387],[20.33766,48.2643],[20.55395,48.52358],[20.82335,48.55714],[21.10271,48.47096],[21.45863,48.55513],[21.74536,48.31435],[22.15293,48.37179],[22.61255,49.08914],[22.09997,49.23814],[21.9686,49.36363],[21.6244,49.46989],[21.06873,49.46402],[20.94336,49.31088],[20.73052,49.44006],[20.22804,49.41714],[20.05234,49.23052],[19.83682,49.25529]]],"terms_text":"Copyright ©2007-2012 Freemap Slovakia (www.freemap.sk). Some rights reserved."},{"id":"Geodatastyrelsen_Denmark","name":"Geodatastyrelsen (Denmark)","type":"tms","template":"http://osmtools.septima.dk/mapproxy/tiles/1.0.0/kortforsyningen_ortoforaar/EPSG3857/{zoom}/{x}/{y}.jpeg","scaleExtent":[0,21],"polygon":[[[8.3743941,54.9551655],[8.3683809,55.4042149],[8.2103997,55.4039795],[8.2087314,55.4937345],[8.0502655,55.4924731],[8.0185123,56.7501399],[8.1819161,56.7509948],[8.1763274,57.0208898],[8.3413329,57.0219872],[8.3392467,57.1119574],[8.5054433,57.1123212],[8.5033923,57.2020499],[9.3316304,57.2027636],[9.3319079,57.2924835],[9.4978864,57.2919578],[9.4988593,57.3820608],[9.6649749,57.3811615],[9.6687295,57.5605591],[9.8351961,57.5596265],[9.8374896,57.6493322],[10.1725726,57.6462818],[10.1754245,57.7367768],[10.5118282,57.7330269],[10.5152095,57.8228945],[10.6834853,57.8207722],[10.6751613,57.6412021],[10.5077045,57.6433097],[10.5039992,57.5535088],[10.671038,57.5514113],[10.6507805,57.1024538],[10.4857673,57.1045138],[10.4786236,56.9249051],[10.3143981,56.9267573],[10.3112341,56.8369269],[10.4750295,56.83509],[10.4649016,56.5656681],[10.9524239,56.5589761],[10.9479249,56.4692243],[11.1099335,56.4664675],[11.1052639,56.376833],[10.9429901,56.3795284],[10.9341235,56.1994768],[10.7719685,56.2020244],[10.7694751,56.1120103],[10.6079695,56.1150259],[10.4466742,56.116717],[10.2865948,56.118675],[10.2831527,56.0281851],[10.4439274,56.0270388],[10.4417713,55.7579243],[10.4334961,55.6693533],[10.743814,55.6646861],[10.743814,55.5712253],[10.8969041,55.5712253],[10.9051793,55.3953852],[11.0613726,55.3812841],[11.0593038,55.1124061],[11.0458567,55.0318621],[11.2030844,55.0247474],[11.2030844,55.117139],[11.0593038,55.1124061],[11.0613726,55.3812841],[11.0789572,55.5712253],[10.8969041,55.5712253],[10.9258671,55.6670198],[10.743814,55.6646861],[10.7562267,55.7579243],[10.4417713,55.7579243],[10.4439274,56.0270388],[10.4466742,56.116717],[10.6079695,56.1150259],[10.6052053,56.0247462],[10.9258671,56.0201215],[10.9197132,55.9309388],[11.0802782,55.92792],[11.0858066,56.0178284],[11.7265047,56.005058],[11.7319981,56.0952142],[12.0540333,56.0871256],[12.0608477,56.1762576],[12.7023469,56.1594405],[12.6611131,55.7114318],[12.9792318,55.7014026],[12.9612912,55.5217294],[12.3268659,55.5412096],[12.3206071,55.4513655],[12.4778226,55.447067],[12.4702432,55.3570479],[12.6269738,55.3523837],[12.6200898,55.2632576],[12.4627339,55.26722],[12.4552949,55.1778223],[12.2987046,55.1822303],[12.2897344,55.0923641],[12.6048608,55.0832904],[12.5872011,54.9036285],[12.2766618,54.9119031],[12.2610181,54.7331602],[12.1070691,54.7378161],[12.0858621,54.4681655],[11.7794953,54.4753579],[11.7837381,54.5654783],[11.1658525,54.5782155],[11.1706443,54.6686508],[10.8617173,54.6733956],[10.8651245,54.7634667],[10.7713646,54.7643888],[10.7707276,54.7372807],[10.7551428,54.7375776],[10.7544039,54.7195666],[10.7389074,54.7197588],[10.7384368,54.7108482],[10.7074486,54.7113045],[10.7041094,54.6756741],[10.5510973,54.6781698],[10.5547184,54.7670245],[10.2423994,54.7705935],[10.2459845,54.8604673],[10.0902268,54.8622134],[10.0873731,54.7723851],[9.1555798,54.7769557],[9.1562752,54.8675369],[8.5321973,54.8663765],[8.531432,54.95516],[8.3743941,54.9551655]],[[11.4577738,56.819554],[11.7849181,56.8127385],[11.7716715,56.6332796],[11.4459621,56.6401087],[11.4577738,56.819554]],[[11.3274736,57.3612962],[11.3161808,57.1818004],[11.1508692,57.1847276],[11.1456628,57.094962],[10.8157703,57.1001693],[10.8290599,57.3695272],[11.3274736,57.3612962]],[[11.5843266,56.2777928],[11.5782882,56.1880397],[11.7392309,56.1845765],[11.7456428,56.2743186],[11.5843266,56.2777928]],[[14.6825922,55.3639405],[14.8395247,55.3565231],[14.8263755,55.2671261],[15.1393406,55.2517359],[15.1532015,55.3410836],[15.309925,55.3330556],[15.295719,55.2437356],[15.1393406,55.2517359],[15.1255631,55.1623802],[15.2815819,55.1544167],[15.2535578,54.9757646],[14.6317464,55.0062496],[14.6825922,55.3639405]]],"terms_url":"http://download.kortforsyningen.dk/content/vilkaar-og-betingelser","terms_text":"Geodatastyrelsen og Danske Kommuner","best":true},{"id":"Geoportal-PL-aerial_image","name":"Geoportal.gov.pl (Orthophotomap)","type":"tms","template":"http://wms.misek.pl/geoportal.orto/tms/{zoom}/{x}/{y}","scaleExtent":[6,24],"polygon":[[[15.9751041,54.3709213],[16.311164,54.5561775],[17.1391878,54.7845723],[18.3448458,54.9022727],[19.6613689,54.4737213],[20.2815206,54.4213456],[21.4663914,54.3406369],[22.7759855,54.3769755],[22.8625989,54.4233613],[23.2956657,54.2678633],[23.5347186,54.0955258],[23.5208604,53.9775182],[23.7183389,53.4629603],[23.9296755,53.1856735],[23.9296755,52.6887269],[23.732197,52.6067497],[23.5658994,52.5878101],[23.2090523,52.3302642],[23.1951942,52.2370089],[23.5035377,52.1860596],[23.6906226,52.0030113],[23.5970802,51.739903],[23.6629063,51.3888562],[23.9366046,50.9827781],[24.1687284,50.8604752],[24.0197534,50.8035823],[24.1098313,50.6610467],[24.0578633,50.4188439],[23.6178674,50.3083403],[22.6824431,49.5163532],[22.7378756,49.2094935],[22.9041733,49.0780441],[22.8625989,48.9940062],[22.6096878,49.0371785],[22.0761495,49.2004392],[21.8474902,49.3721872],[21.3763135,49.4488281],[21.1026153,49.3721872],[20.9120659,49.3022043],[20.6452967,49.3902311],[20.1845136,49.3315641],[20.1186875,49.2004392],[19.9419962,49.1302123],[19.765305,49.2117568],[19.7479823,49.3992506],[19.6024718,49.4150307],[19.5089294,49.5815389],[19.4292451,49.5905232],[19.2317666,49.4150307],[18.9961783,49.387976],[18.9338167,49.4916048],[18.8368097,49.4938552],[18.8021643,49.6623381],[18.6427958,49.7094091],[18.521537,49.8994693],[18.0815412,50.0109209],[17.8875272,49.9886512],[17.7385522,50.0687739],[17.6068999,50.1709584],[17.7454813,50.2153184],[17.710836,50.3017019],[17.4163505,50.2640668],[16.9486384,50.4453265],[16.8932058,50.4033889],[17.0006064,50.3105529],[17.017929,50.2241854],[16.8135215,50.186489],[16.6402948,50.0976742],[16.4324227,50.2862087],[16.1968344,50.4276731],[16.4220291,50.5885165],[16.3388803,50.6632429],[16.2280152,50.6368824],[16.0547884,50.6127057],[15.5732181,50.7641544],[15.2683391,50.8976368],[15.2440873,50.980597],[15.0292862,51.0133036],[15.0015699,50.8582883],[14.8110205,50.8735944],[14.956531,51.0721176],[15.0188926,51.2914636],[14.9392083,51.4601459],[14.7209426,51.5571799],[14.7521234,51.6260562],[14.5996839,51.8427626],[14.70362,52.0733396],[14.5581095,52.2497371],[14.5165351,52.425436],[14.6031485,52.5878101],[14.1146491,52.8208272],[14.152759,52.9733951],[14.3502374,53.0734212],[14.4229927,53.2665624],[14.1977979,53.8734759],[14.2220497,53.9958517],[15.9751041,54.3709213]]],"terms_text":"Copyright © Główny Urząd Geodezji i Kartografii.","best":true},{"id":"IBGE_DF_Addresses","name":"IBGE Distrito Federal","type":"tms","template":"https://api.mapbox.com/styles/v1/wille/cirnnxni1000jg8nfppc8g7pm/tiles/256/{zoom}/{x}/{y}?access_token=pk.eyJ1Ijoid2lsbGUiLCJhIjoicFNVWk5VWSJ9.hluCd0YGvYHNlFi_utWe2g","description":"Addresses data from IBGE","scaleExtent":[0,19],"polygon":[[[-48.2444,-16.0508],[-48.2444,-15.5005],[-47.5695,-15.5005],[-47.5695,-16.0508],[-48.2444,-16.0508]]],"overlay":true},{"id":"IBGE_Setores_Rurais","name":"IBGE Mapa de Setores Rurais","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/tmpsantos.i00mo1kj/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJncjlmd0t3In0.DmZsIeOW-3x-C5eX-wAqTw","scaleExtent":[0,14],"polygon":[[[-29.3325,2.335959],[-28.72472,2.031551],[-27.76041,-8.937033],[-27.67249,-22.20839],[-51.11495,-35.46552],[-53.39394,-33.85064],[-53.62553,-33.72493],[-53.62503,-33.15428],[-53.24498,-32.73392],[-53.65747,-32.51873],[-53.8329,-32.16592],[-54.64174,-31.55507],[-55.29638,-31.3429],[-55.57371,-30.99691],[-56.06384,-31.16749],[-56.10468,-30.86436],[-56.86862,-30.20752],[-57.39671,-30.40464],[-57.74384,-30.22142],[-55.83724,-28.16598],[-54.86969,-27.44994],[-53.9016,-27.02998],[-53.74972,-26.25781],[-53.97158,-25.74513],[-54.44723,-25.79609],[-54.67802,-25.64668],[-54.36097,-24.35145],[-54.41679,-24.06527],[-54.64355,-23.94107],[-55.22163,-24.11355],[-55.49138,-24.02797],[-55.71734,-22.68488],[-55.90555,-22.39886],[-56.45255,-22.21731],[-56.8256,-22.4002],[-57.34109,-22.34351],[-58.08472,-22.13075],[-57.95766,-20.99818],[-58.26551,-20.24147],[-58.03577,-19.95871],[-58.23083,-19.75211],[-57.64739,-18.19828],[-57.89356,-17.57377],[-58.16997,-17.53519],[-58.48825,-17.21961],[-58.57691,-16.81466],[-58.45563,-16.42158],[-60.2541,-16.32571],[-60.33481,-15.51483],[-60.67423,-15.1122],[-60.34999,-14.99707],[-60.63603,-13.84119],[-61.07283,-13.62569],[-61.9025,-13.62647],[-62.21395,-13.25048],[-62.80185,-13.10905],[-63.17194,-12.76568],[-63.74229,-12.54071],[-64.32845,-12.59578],[-65.10261,-12.0682],[-65.45781,-11.27865],[-65.41641,-9.838943],[-66.52331,-9.985873],[-67.66452,-10.80093],[-67.99778,-10.75991],[-68.52286,-11.20807],[-69.88988,-11.02776],[-70.30957,-11.1699],[-70.71896,-11.02003],[-70.68128,-9.669083],[-71.27536,-10.08971],[-72.18053,-10.09967],[-72.41623,-9.587397],[-73.29207,-9.454149],[-73.0625,-9.017267],[-73.61432,-8.40982],[-74.09056,-7.527548],[-74.03652,-7.27885],[-73.84718,-7.238285],[-73.78618,-6.774872],[-73.22362,-6.430106],[-73.33719,-6.029736],[-72.93016,-5.038711],[-71.93973,-4.425027],[-70.96802,-4.248294],[-70.79598,-4.064931],[-70.02393,-4.167345],[-69.51025,-1.134089],[-69.70776,-0.567619],[-70.13645,-0.226161],[-70.14083,0.5844],[-69.26594,0.806502],[-69.34226,0.968924],[-69.92481,1.015705],[-69.92343,1.773851],[-68.38511,1.82943],[-68.24848,2.119808],[-67.94571,1.948424],[-67.37696,2.327468],[-67.05751,1.858336],[-67.00579,1.291603],[-66.79967,1.314684],[-66.28683,0.857709],[-65.67671,1.111146],[-65.42494,0.966549],[-65.15671,1.24203],[-64.27483,1.601591],[-64.0486,2.065137],[-63.47236,2.279358],[-64.13446,2.433909],[-64.10005,2.723778],[-64.32628,3.118275],[-64.28142,3.541983],[-64.88451,4.117671],[-64.88064,4.342461],[-64.13653,4.223152],[-63.95465,4.021316],[-63.17706,4.048301],[-62.96093,3.763658],[-62.82024,4.106019],[-62.49922,4.270815],[-61.91181,4.26284],[-61.35393,4.630097],[-61.04904,4.623115],[-60.70452,4.969851],[-60.78709,5.296764],[-60.22457,5.371207],[-59.89857,5.107541],[-59.97549,4.603025],[-59.59676,4.439875],[-59.41942,3.96994],[-59.71017,3.542008],[-59.88955,2.72301],[-59.63006,2.316332],[-59.63382,1.966581],[-59.18812,1.478079],[-58.80545,1.320732],[-58.35933,1.689932],[-57.6,1.803907],[-57.39854,2.065119],[-57.12392,2.128758],[-56.02925,1.949445],[-56.23884,2.263348],[-55.98195,2.628657],[-55.64816,2.519953],[-54.93958,2.682515],[-54.24988,2.25056],[-53.73937,2.473731],[-52.98578,2.280494],[-52.65712,2.564069],[-52.41739,3.22121],[-51.73983,4.119158],[-51.7246,4.556867],[-51.0112,5.522895],[-43.48209,5.335832],[-29.3325,2.335959]]]},{"id":"IBGE_Setores_Urbanos","name":"IBGE Mapa de Setores Urbanos","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/tmpsantos.hgda0m6h/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJncjlmd0t3In0.DmZsIeOW-3x-C5eX-wAqTw","scaleExtent":[0,19],"polygon":[[[-29.3325,2.335959],[-28.72472,2.031551],[-27.76041,-8.937033],[-27.67249,-22.20839],[-51.11495,-35.46552],[-53.39394,-33.85064],[-53.62553,-33.72493],[-53.62503,-33.15428],[-53.24498,-32.73392],[-53.65747,-32.51873],[-53.8329,-32.16592],[-54.64174,-31.55507],[-55.29638,-31.3429],[-55.57371,-30.99691],[-56.06384,-31.16749],[-56.10468,-30.86436],[-56.86862,-30.20752],[-57.39671,-30.40464],[-57.74384,-30.22142],[-55.83724,-28.16598],[-54.86969,-27.44994],[-53.9016,-27.02998],[-53.74972,-26.25781],[-53.97158,-25.74513],[-54.44723,-25.79609],[-54.67802,-25.64668],[-54.36097,-24.35145],[-54.41679,-24.06527],[-54.64355,-23.94107],[-55.22163,-24.11355],[-55.49138,-24.02797],[-55.71734,-22.68488],[-55.90555,-22.39886],[-56.45255,-22.21731],[-56.8256,-22.4002],[-57.34109,-22.34351],[-58.08472,-22.13075],[-57.95766,-20.99818],[-58.26551,-20.24147],[-58.03577,-19.95871],[-58.23083,-19.75211],[-57.64739,-18.19828],[-57.89356,-17.57377],[-58.16997,-17.53519],[-58.48825,-17.21961],[-58.57691,-16.81466],[-58.45563,-16.42158],[-60.2541,-16.32571],[-60.33481,-15.51483],[-60.67423,-15.1122],[-60.34999,-14.99707],[-60.63603,-13.84119],[-61.07283,-13.62569],[-61.9025,-13.62647],[-62.21395,-13.25048],[-62.80185,-13.10905],[-63.17194,-12.76568],[-63.74229,-12.54071],[-64.32845,-12.59578],[-65.10261,-12.0682],[-65.45781,-11.27865],[-65.41641,-9.838943],[-66.52331,-9.985873],[-67.66452,-10.80093],[-67.99778,-10.75991],[-68.52286,-11.20807],[-69.88988,-11.02776],[-70.30957,-11.1699],[-70.71896,-11.02003],[-70.68128,-9.669083],[-71.27536,-10.08971],[-72.18053,-10.09967],[-72.41623,-9.587397],[-73.29207,-9.454149],[-73.0625,-9.017267],[-73.61432,-8.40982],[-74.09056,-7.527548],[-74.03652,-7.27885],[-73.84718,-7.238285],[-73.78618,-6.774872],[-73.22362,-6.430106],[-73.33719,-6.029736],[-72.93016,-5.038711],[-71.93973,-4.425027],[-70.96802,-4.248294],[-70.79598,-4.064931],[-70.02393,-4.167345],[-69.51025,-1.134089],[-69.70776,-0.567619],[-70.13645,-0.226161],[-70.14083,0.5844],[-69.26594,0.806502],[-69.34226,0.968924],[-69.92481,1.015705],[-69.92343,1.773851],[-68.38511,1.82943],[-68.24848,2.119808],[-67.94571,1.948424],[-67.37696,2.327468],[-67.05751,1.858336],[-67.00579,1.291603],[-66.79967,1.314684],[-66.28683,0.857709],[-65.67671,1.111146],[-65.42494,0.966549],[-65.15671,1.24203],[-64.27483,1.601591],[-64.0486,2.065137],[-63.47236,2.279358],[-64.13446,2.433909],[-64.10005,2.723778],[-64.32628,3.118275],[-64.28142,3.541983],[-64.88451,4.117671],[-64.88064,4.342461],[-64.13653,4.223152],[-63.95465,4.021316],[-63.17706,4.048301],[-62.96093,3.763658],[-62.82024,4.106019],[-62.49922,4.270815],[-61.91181,4.26284],[-61.35393,4.630097],[-61.04904,4.623115],[-60.70452,4.969851],[-60.78709,5.296764],[-60.22457,5.371207],[-59.89857,5.107541],[-59.97549,4.603025],[-59.59676,4.439875],[-59.41942,3.96994],[-59.71017,3.542008],[-59.88955,2.72301],[-59.63006,2.316332],[-59.63382,1.966581],[-59.18812,1.478079],[-58.80545,1.320732],[-58.35933,1.689932],[-57.6,1.803907],[-57.39854,2.065119],[-57.12392,2.128758],[-56.02925,1.949445],[-56.23884,2.263348],[-55.98195,2.628657],[-55.64816,2.519953],[-54.93958,2.682515],[-54.24988,2.25056],[-53.73937,2.473731],[-52.98578,2.280494],[-52.65712,2.564069],[-52.41739,3.22121],[-51.73983,4.119158],[-51.7246,4.556867],[-51.0112,5.522895],[-43.48209,5.335832],[-29.3325,2.335959]]]},{"id":"Haiti-Drone","name":"Imagerie Drone (Haiti)","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/iomhaiti/{zoom}/{x}/{y}","polygon":[[[-72.1547401,19.6878969],[-72.162234,19.689011],[-72.164995,19.6932445],[-72.1657838,19.6979977],[-72.161603,19.7035677],[-72.1487449,19.7028993],[-72.1477194,19.7026765],[-72.1485082,19.7001514],[-72.1436963,19.7011169],[-72.1410143,19.7000029],[-72.139476,19.6973664],[-72.1382533,19.6927617],[-72.1386872,19.6923161],[-72.1380561,19.6896423],[-72.1385294,19.6894938],[-72.1388055,19.6901251],[-72.1388844,19.6876741],[-72.1378195,19.6872656],[-72.13778,19.6850003],[-72.1369517,19.6855945],[-72.136794,19.6840719],[-72.135729,19.6835148],[-72.1355713,19.6740817],[-72.1366362,19.6708133],[-72.1487843,19.6710733],[-72.1534779,19.6763843],[-72.1530835,19.6769414],[-72.1533251,19.6769768],[-72.1532807,19.6796525],[-72.1523834,19.6797175],[-72.1522749,19.6803488],[-72.1519101,19.6803395],[-72.1518608,19.6805067],[-72.1528173,19.6806552],[-72.1522299,19.6833011],[-72.1507801,19.6831499],[-72.1504457,19.6847862],[-72.1508591,19.6843492],[-72.1530087,19.6849898],[-72.1546258,19.6854354],[-72.1543103,19.6870694],[-72.1547244,19.6868466],[-72.1548501,19.6877564],[-72.1545814,19.6877982],[-72.1547401,19.6878969]],[[-72.1310601,19.6718929],[-72.1259842,19.6772765],[-72.1255379,19.6776179],[-72.1216891,19.6776442],[-72.1149677,19.672602],[-72.1152745,19.6687152],[-72.1198205,19.6627535],[-72.1227768,19.6625696],[-72.1248965,19.662701],[-72.1285779,19.6645394],[-72.1308091,19.6661677],[-72.1316737,19.668794],[-72.1315621,19.671],[-72.1310601,19.6718929]],[[-71.845795,19.6709758],[-71.8429354,19.6759525],[-71.8410027,19.6759525],[-71.8380249,19.6755254],[-71.8378671,19.6745041],[-71.8390504,19.6743927],[-71.8390109,19.6741141],[-71.8398392,19.673947],[-71.8389123,19.6736127],[-71.8380249,19.67209],[-71.8380052,19.6726285],[-71.8376699,19.6727214],[-71.8376305,19.672545],[-71.8354414,19.6732135],[-71.835333,19.6729999],[-71.8331242,19.6734642],[-71.8326706,19.6716815],[-71.8321579,19.67209],[-71.8307183,19.6694902],[-71.8306009,19.6697594],[-71.8302174,19.6698907],[-71.8291833,19.6672095],[-71.8290749,19.6672095],[-71.8289122,19.6667916],[-71.8289516,19.6666199],[-71.8288333,19.6663506],[-71.8285572,19.6664759],[-71.8288678,19.6672466],[-71.8287593,19.6674138],[-71.8277979,19.6678177],[-71.8277112,19.6678586],[-71.8278263,19.6679637],[-71.8271831,19.6681212],[-71.8271761,19.6680917],[-71.8264405,19.6683921],[-71.8264074,19.6683231],[-71.8261954,19.6684253],[-71.8261806,19.6683556],[-71.8258946,19.6684206],[-71.8258897,19.6686574],[-71.8251551,19.6687549],[-71.8254509,19.6691588],[-71.8229332,19.6695739],[-71.822713,19.6696658],[-71.8227688,19.6697577],[-71.8201751,19.6709855],[-71.8198474,19.6704537],[-71.8197985,19.6706014],[-71.8194674,19.6707557],[-71.8182472,19.6713433],[-71.8181426,19.6711431],[-71.8175813,19.6714254],[-71.816959,19.6707672],[-71.8176388,19.6718965],[-71.8171403,19.6720376],[-71.8158225,19.6718045],[-71.8138354,19.6711874],[-71.8123259,19.6706982],[-71.8121759,19.6704258],[-71.8124304,19.6701467],[-71.8119184,19.6700141],[-71.8118765,19.6705828],[-71.811169,19.6703483],[-71.8095938,19.6698516],[-71.8077992,19.6692829],[-71.8056028,19.668612],[-71.8051443,19.6668942],[-71.8051196,19.6652322],[-71.8052315,19.661979],[-71.8065603,19.6523921],[-71.8073412,19.6482946],[-71.8099686,19.6468292],[-71.8147517,19.6454502],[-71.8147726,19.6455619],[-71.8150027,19.6455093],[-71.8149469,19.6453846],[-71.8159928,19.6450234],[-71.8158882,19.6448855],[-71.8165854,19.6446097],[-71.8190119,19.643802],[-71.8211524,19.643454],[-71.8221564,19.6433292],[-71.8269046,19.643211],[-71.8280481,19.6432241],[-71.8304466,19.6440778],[-71.8306419,19.6448592],[-71.8295263,19.6450365],[-71.8296064,19.6456111],[-71.8299411,19.6455651],[-71.8303699,19.6451744],[-71.830471,19.6453452],[-71.8308092,19.6451974],[-71.8310184,19.6451088],[-71.8312519,19.6458541],[-71.8311125,19.6458245],[-71.831367,19.6465862],[-71.8328939,19.646189],[-71.8344566,19.6457062],[-71.8344664,19.6463052],[-71.834215,19.6461938],[-71.8342002,19.6465513],[-71.8346702,19.6463],[-71.8349118,19.6463905],[-71.8347984,19.6462187],[-71.8354393,19.6458496],[-71.8355034,19.6458032],[-71.8364747,19.6461328],[-71.8376382,19.6472658],[-71.8379143,19.647888],[-71.8390483,19.6508039],[-71.8456942,19.6696203],[-71.845795,19.6709758]],[[-72.098878,18.54843],[-72.096993,18.5501994],[-72.0972888,18.5503209],[-72.0968451,18.5503489],[-72.0955632,18.551854],[-72.0956428,18.5526742],[-72.0959914,18.5533748],[-72.0962145,18.553203],[-72.0962842,18.5535665],[-72.0964446,18.5535533],[-72.0965352,18.5539764],[-72.0965056,18.554173],[-72.0966085,18.5541747],[-72.0965178,18.5542127],[-72.0968769,18.5546588],[-72.0979018,18.5552141],[-72.1006211,18.5555875],[-72.1014926,18.5556206],[-72.1024339,18.5555016],[-72.103417,18.5543515],[-72.1034798,18.5516215],[-72.1030789,18.5516149],[-72.1033752,18.5515224],[-72.1035042,18.5515224],[-72.1035239,18.5502417],[-72.1028701,18.5503062],[-72.1029015,18.55025],[-72.1028457,18.5501773],[-72.1035081,18.5500252],[-72.103491,18.5497396],[-72.1035181,18.5497361],[-72.1035398,18.5489039],[-72.1034317,18.5487056],[-72.102717,18.5481437],[-72.1025601,18.5481536],[-72.10229,18.5482751],[-72.1022891,18.5482569],[-72.1025201,18.5481396],[-72.1023388,18.5481321],[-72.0999082,18.5480901],[-72.09907,18.5483799],[-72.098878,18.54843]],[[-72.2542503,18.568262],[-72.2560252,18.5717765],[-72.2557886,18.5748049],[-72.2535009,18.5755526],[-72.2522782,18.5755526],[-72.2499906,18.5740945],[-72.2473874,18.5698323],[-72.2460069,18.566729],[-72.2458492,18.5629527],[-72.2479396,18.5625414],[-72.2501483,18.5628031],[-72.2519232,18.5650839],[-72.2542503,18.568262]],[[-72.303145,18.5332749],[-72.3031275,18.5331799],[-72.3048311,18.5311081],[-72.3097397,18.5311081],[-72.3164332,18.5324302],[-72.3234056,18.5366083],[-72.3261388,18.5387765],[-72.3261946,18.5426371],[-72.3170468,18.5540596],[-72.3130864,18.5540596],[-72.2987511,18.5453342],[-72.2988627,18.5407333],[-72.2962969,18.5404689],[-72.2954602,18.5395169],[-72.2961853,18.5338582],[-72.2971893,18.5332235],[-72.3007034,18.5332764],[-72.3022652,18.5342284],[-72.3028486,18.5335189],[-72.303104,18.5333361],[-72.303181,18.5334007],[-72.3035793,18.5335614],[-72.3030793,18.5346463],[-72.303715,18.5339873],[-72.3045286,18.5344052],[-72.3044015,18.5345097],[-72.3062747,18.5352571],[-72.3063107,18.5352741],[-72.3061219,18.5357628],[-72.3061219,18.5358196],[-72.30637,18.5358928],[-72.3062726,18.5354869],[-72.3066688,18.5350891],[-72.3061963,18.5349706],[-72.3058869,18.5349385],[-72.3055373,18.5346833],[-72.3054864,18.534613],[-72.3055585,18.5345065],[-72.3046749,18.5342293],[-72.3047617,18.5338817],[-72.3043252,18.5337511],[-72.3042595,18.5336346],[-72.303145,18.5332749]],[[-72.2981405,18.477502],[-72.2935652,18.4948587],[-72.2922242,18.4964297],[-72.2931708,18.4972526],[-72.2892266,18.5057058],[-72.2878067,18.5080996],[-72.2850458,18.5119893],[-72.2840203,18.5113161],[-72.2808649,18.515879],[-72.2773151,18.5175994],[-72.2723454,18.5175246],[-72.2662714,18.5144578],[-72.2665869,18.5066783],[-72.2692643,18.5046154],[-72.2661965,18.5029756],[-72.2688181,18.4965222],[-72.2691528,18.4959403],[-72.2702684,18.4961519],[-72.2702684,18.4955964],[-72.2690691,18.49557],[-72.2692922,18.4937714],[-72.2736988,18.4859951],[-72.2746749,18.4850429],[-72.2751769,18.483403],[-72.2765435,18.4813398],[-72.2773523,18.4814985],[-72.2783006,18.4809694],[-72.2778544,18.4807049],[-72.2771013,18.480123],[-72.2789978,18.4775836],[-72.279723,18.4772927],[-72.2806433,18.4776365],[-72.2813685,18.4771604],[-72.2808386,18.4769752],[-72.2812848,18.4758378],[-72.2823167,18.4751765],[-72.2851615,18.4750971],[-72.2849941,18.4763668],[-72.2854404,18.4769752],[-72.286277,18.4756262],[-72.2869325,18.4754675],[-72.2865978,18.4751897],[-72.2865978,18.4750046],[-72.2909765,18.4747268],[-72.2946579,18.4749384],[-72.2973911,18.476843],[-72.2981405,18.477502]],[[-72.3466657,18.5222375],[-72.346833,18.5244325],[-72.3475303,18.5277645],[-72.3455501,18.5291131],[-72.3403069,18.5292189],[-72.3383267,18.5280289],[-72.3369043,18.530118],[-72.3338086,18.5296684],[-72.3289279,18.5270769],[-72.328649,18.5253316],[-72.3292068,18.5232689],[-72.330406,18.5220524],[-72.3321631,18.5221847],[-72.3322467,18.5191963],[-72.3369183,18.5183633],[-72.3382012,18.5184691],[-72.3381454,18.5181782],[-72.3411993,18.5177947],[-72.3454943,18.5171997],[-72.3492595,18.517279],[-72.3504308,18.5188922],[-72.3503472,18.5206112],[-72.3496778,18.5220392],[-72.3466657,18.5222375]],[[-72.3303078,18.5486462],[-72.3429687,18.5508149],[-72.3433236,18.5530585],[-72.3413121,18.5614341],[-72.3390639,18.5613593],[-72.3384723,18.5638271],[-72.3375257,18.5654348],[-72.3348436,18.5650609],[-72.3311755,18.5638271],[-72.3312149,18.5616211],[-72.3232082,18.5606863],[-72.3212361,18.559602],[-72.3208023,18.5587046],[-72.3208811,18.557882],[-72.3259493,18.5580274],[-72.3266186,18.5581993],[-72.3259214,18.5577498],[-72.3250986,18.5573797],[-72.3233767,18.552263],[-72.3245994,18.5478507],[-72.3288986,18.5483742],[-72.329979,18.5489548],[-72.3303078,18.5486462]],[[-72.3231383,18.5269828],[-72.3223434,18.528067],[-72.3209629,18.5279745],[-72.3207816,18.5271282],[-72.3208513,18.5253697],[-72.3214649,18.5249598],[-72.3225666,18.5248937],[-72.3228454,18.52533],[-72.3232359,18.5264804],[-72.3231383,18.5269828]],[[-72.2160832,18.6457752],[-72.2159649,18.6553795],[-72.2030279,18.6558279],[-72.1947057,18.6553421],[-72.1922208,18.6545573],[-72.1920631,18.6521283],[-72.193483,18.6477559],[-72.201253,18.6385249],[-72.2069327,18.6388239],[-72.2120996,18.6424117],[-72.2118068,18.6430591],[-72.2121693,18.6426892],[-72.2127968,18.6427552],[-72.2134662,18.6431252],[-72.2135638,18.6437462],[-72.2154176,18.6443947],[-72.2158909,18.6450301],[-72.2160832,18.6457752]],[[-72.2867654,18.6482017],[-72.2900977,18.6527446],[-72.28981,18.6536532],[-72.2900738,18.6542664],[-72.290721,18.6537667],[-72.2910327,18.6544709],[-72.2912485,18.654221],[-72.29168,18.6558905],[-72.2912245,18.656606],[-72.2922673,18.65597],[-72.2926869,18.6567536],[-72.2930705,18.6567309],[-72.2941253,18.6581846],[-72.2960192,18.6608421],[-72.2959713,18.6619096],[-72.2932862,18.664567],[-72.2906731,18.6659979],[-72.2895943,18.6661342],[-72.2895943,18.6665657],[-72.2877004,18.6664749],[-72.2875805,18.6676559],[-72.2831214,18.6697227],[-72.2796453,18.6696546],[-72.2784311,18.6690787],[-72.2783972,18.6687736],[-72.277736,18.6691671],[-72.2774394,18.669143],[-72.2770071,18.6683159],[-72.2765575,18.6681125],[-72.2765385,18.6680583],[-72.2752319,18.6685239],[-72.2749292,18.6674649],[-72.2746416,18.6674309],[-72.2734668,18.6682145],[-72.2732271,18.6682712],[-72.2726757,18.6671583],[-72.2719147,18.6674288],[-72.2718808,18.6673405],[-72.2688149,18.6681868],[-72.2688269,18.6671761],[-72.2690786,18.6668241],[-72.2688149,18.66679],[-72.2681077,18.6670739],[-72.2676282,18.6673805],[-72.2675563,18.6666878],[-72.266861,18.666949],[-72.2655904,18.6673578],[-72.2654466,18.6670058],[-72.2647514,18.6674146],[-72.2629893,18.6681868],[-72.2628455,18.6681754],[-72.2626537,18.6676076],[-72.2623001,18.6677098],[-72.2624799,18.6679199],[-72.2624799,18.6682322],[-72.262306,18.6682606],[-72.2620963,18.6679654],[-72.2622761,18.6689193],[-72.2601484,18.6688966],[-72.2542749,18.6687944],[-72.2505388,18.6683476],[-72.2504371,18.669536],[-72.2477926,18.6698893],[-72.2415204,18.669793],[-72.2414187,18.6741933],[-72.2389167,18.6739759],[-72.2387249,18.6734649],[-72.2383653,18.6733059],[-72.2387009,18.6739532],[-72.2375502,18.6738964],[-72.2374183,18.6735103],[-72.237742,18.67334],[-72.2375142,18.6732605],[-72.236843,18.6734876],[-72.2364354,18.6724088],[-72.2355124,18.6726019],[-72.2354045,18.6724202],[-72.2353027,18.6729028],[-72.2345475,18.6726871],[-72.2343077,18.6724599],[-72.2342358,18.6734706],[-72.2334087,18.6734592],[-72.2332889,18.6733003],[-72.2327375,18.6732889],[-72.2327135,18.6735047],[-72.227703,18.6725281],[-72.2265283,18.6716537],[-72.226804,18.6715742],[-72.2274993,18.6715855],[-72.2274873,18.6714493],[-72.2272899,18.6714623],[-72.2272814,18.6712977],[-72.2272094,18.671358],[-72.2261785,18.6713693],[-72.2256032,18.670881],[-72.2255073,18.6694502],[-72.2261066,18.6696886],[-72.2261785,18.6695949],[-72.2259837,18.6695495],[-72.225777,18.6691379],[-72.2253335,18.6694643],[-72.2249739,18.66947],[-72.2245783,18.6678802],[-72.2235525,18.6677046],[-72.2235907,18.6675921],[-72.2224634,18.6676283],[-72.2223659,18.667022],[-72.2223277,18.6670943],[-72.2219209,18.667026],[-72.2208105,18.6669015],[-72.220809,18.6665325],[-72.2208705,18.6663593],[-72.2206023,18.6668107],[-72.2203895,18.6666361],[-72.2184341,18.6650535],[-72.21829,18.6640979],[-72.2183493,18.6608376],[-72.2187223,18.6606541],[-72.2186894,18.660603],[-72.2187253,18.6604525],[-72.2189771,18.6603247],[-72.2187823,18.6601998],[-72.2186984,18.6602367],[-72.2185815,18.6600352],[-72.2186085,18.6600039],[-72.2187823,18.6601345],[-72.218995,18.6600181],[-72.2189111,18.6599131],[-72.2189681,18.6597938],[-72.2183807,18.6595837],[-72.2184728,18.6539662],[-72.2201001,18.6511554],[-72.225796,18.6469472],[-72.2283048,18.6457265],[-72.2379335,18.645855],[-72.237764,18.6446985],[-72.2400355,18.6432529],[-72.2455958,18.6433493],[-72.2482742,18.6450358],[-72.2487488,18.6436705],[-72.2511067,18.6429775],[-72.2512385,18.6433409],[-72.2512625,18.6431592],[-72.2514843,18.6431365],[-72.2513284,18.6429718],[-72.2533602,18.6423471],[-72.253516,18.6426765],[-72.2539535,18.6425402],[-72.2541453,18.642932],[-72.2543851,18.6428696],[-72.2543791,18.6427503],[-72.2564168,18.6423244],[-72.2566925,18.6431365],[-72.2568783,18.6428582],[-72.2568184,18.6425288],[-72.258843,18.6420991],[-72.258885,18.6422467],[-72.2592626,18.6422297],[-72.2596461,18.6424057],[-72.2592206,18.6406907],[-72.2599545,18.6404815],[-72.2601156,18.6406341],[-72.2601156,18.6399393],[-72.2615268,18.6394669],[-72.2626056,18.6391034],[-72.2654465,18.6387286],[-72.2719433,18.6386832],[-72.272201,18.6388649],[-72.2730341,18.6394158],[-72.273166,18.6412558],[-72.2738732,18.6410286],[-72.2742208,18.6416079],[-72.2752187,18.6416987],[-72.2754524,18.6415738],[-72.2755513,18.6416874],[-72.2755394,18.6417527],[-72.2764713,18.6418634],[-72.276753,18.6418975],[-72.2762953,18.6426002],[-72.2774226,18.6429978],[-72.277982,18.6427247],[-72.2785796,18.6431303],[-72.2785669,18.6432307],[-72.2789017,18.6433471],[-72.279851,18.6439655],[-72.2858703,18.6469651],[-72.2867654,18.6482017]],[[-72.5557247,18.5305893],[-72.5555866,18.5367036],[-72.554995,18.537975],[-72.5488026,18.537919],[-72.5486646,18.5372832],[-72.548842,18.5306267],[-72.5493745,18.5301031],[-72.555133,18.5301218],[-72.5557247,18.5305893]],[[-72.6235278,18.5079877],[-72.6234441,18.5095217],[-72.6226074,18.5104341],[-72.6204878,18.511849],[-72.6183403,18.5107514],[-72.6162207,18.5083183],[-72.6162625,18.506467],[-72.618661,18.5044438],[-72.6204041,18.5044967],[-72.6228305,18.506996],[-72.6235278,18.5079877]]]},{"id":"osmim-imagicode-S2A_R119_N09_20160327T050917","name":"imagico.de OSM images for mapping: Adams Bridge","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R119_N09_20160327T050917&z={zoom}&x={x}&y={-y}","description":"Supplementing incomplete coverage in other sources (true color)","scaleExtent":[0,14],"polygon":[[[79.01779174804685,8.827572266651268],[79.01401519775389,9.64678471986339],[80.17642021179198,9.650423231331946],[80.17727851867674,8.831304063493132],[79.01779174804685,8.827572266651268]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80700162014211LGN00","name":"imagico.de OSM images for mapping: Alaska Range","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80700162014211LGN00&z={zoom}&x={x}&y={-y}","description":"Recent summer image of the Alaska Range for mapping natural features (true color)","scaleExtent":[0,12],"polygon":[[[-152.70872943147867,62.30357443926811],[-152.70838610872474,62.58153176976553],[-152.00835101350992,63.54645538851267],[-148.99432055696695,63.53329945446586],[-148.99432055696695,62.30357443926811],[-152.70872943147867,62.30357443926811]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81190582014075LGN00","name":"imagico.de OSM images for mapping: Bakun Reservoir","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81190582014075LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in older pre-2011 images (true color)","scaleExtent":[0,13],"polygon":[[[114.35999506049737,2.028456548619032],[113.5344754987298,2.030000532161949],[113.53619211249934,3.070767124420059],[114.76511591010677,3.067510236472651],[114.76254098945248,2.088156161702156],[114.35999506049737,2.028456548619032]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81250592016107LGN00","name":"imagico.de OSM images for mapping: Batam","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81250592016107LGN00&z={zoom}&x={x}&y={-y}","description":"Missing Islands in OSM (true color)","scaleExtent":[0,13],"polygon":[[[104.00154570197358,-0.000078769115171],[104.00137404059662,1.45099139170518],[104.91014937018647,1.451162998032411],[104.91014937018647,-0.000078769115171],[104.00154570197358,-0.000078769115171]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81800982013291LGN00","name":"imagico.de OSM images for mapping: Bouvet Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81800982013291LGN00&z={zoom}&x={x}&y={-y}","description":"For more accurate coastline and glacier mapping (true color)","scaleExtent":[0,13],"polygon":[[[3.246529403113632,-54.47046993167111],[3.246529403113632,-54.375391687979096],[3.463852706336288,-54.375391687979096],[3.463852706336288,-54.47046993167111],[3.246529403113632,-54.47046993167111]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping","best":true},{"id":"osmim-imagicode-S2A_R065_N47_20160929T102022","name":"imagico.de OSM images for mapping: Cental Alps in late September 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R065_N47_20160929T102022&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping - beware of some fresh snow at higher altitudes (true color)","scaleExtent":[0,13],"polygon":[[[10.559062957763668,45.95484945195885],[7.473964691162107,45.95532682303484],[7.555847167968747,46.27080015119853],[8.05469512939453,47.66469371011084],[11.752452850341793,47.664809318453564],[11.752452850341793,46.813336457338615],[11.38423919677734,45.955088138010865],[10.559062957763668,45.95484945195885]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82050982015344LGN00","name":"imagico.de OSM images for mapping: Clerke Rocks","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82050982015344LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color)","scaleExtent":[0,13],"polygon":[[[-34.17701089820909,-55.29692751183208],[-35.19599283180284,-55.282851769908206],[-35.16663873634385,-54.7209735214882],[-34.12516916236925,-54.73465315976587],[-34.14010370216417,-55.29692751183208],[-34.17701089820909,-55.29692751183208]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-EO1A0040712016264110KF","name":"imagico.de OSM images for mapping: Coropuna","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=EO1A0040712016264110KF&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping (true color)","scaleExtent":[0,14],"polygon":[[[-72.7594470977783,-15.68684010813036],[-72.7594470977783,-15.49570157136026],[-72.74434089660643,-15.426295586903299],[-72.41286277770995,-15.426295586903299],[-72.41286277770995,-15.652957427428944],[-72.42410659790038,-15.686674840407827],[-72.7594470977783,-15.68684010813036]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R022_N06_20151221T103009","name":"imagico.de OSM images for mapping: Cotonou","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R022_N06_20151221T103009&z={zoom}&x={x}&y={-y}","description":"Patchy and partly cloudy coverage in usual sources (true color)","scaleExtent":[0,14],"polygon":[[[1.839749701876779,6.257803795151386],[1.839749701876779,7.114271792431897],[2.549397834200998,7.114271792431897],[2.549397834200998,6.489052510574106],[2.497813590426584,6.258059752887941],[1.839749701876779,6.257803795151386]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R040_N01_20160311T164128","name":"imagico.de OSM images for mapping: Darwin and Wolf islands, Galapagos","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R040_N01_20160311T164128&z={zoom}&x={x}&y={-y}","description":"Recent image, only old and poor images in other sources currently (true color)","scaleExtent":[0,14],"polygon":[[[-92.05216379429558,1.321295617717369],[-92.05216379429558,1.72181118585353],[-91.74849481846549,1.72181118585353],[-91.74849481846549,1.321295617717369],[-92.05216379429558,1.321295617717369]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80360072014245LGN00","name":"imagico.de OSM images for mapping: Eastern Devon Island coast","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80360072014245LGN00&z={zoom}&x={x}&y={-y}","description":"Coastline mostly mapped meanwhile (false color IR)","scaleExtent":[0,11],"polygon":[[[-84.34798733886554,74.38945823827667],[-84.34798733886554,75.89030323920836],[-79.14870755370929,75.89030323920836],[-79.14870755370929,74.38945823827667],[-84.34798733886554,74.38945823827667]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82160152013239LGN00","name":"imagico.de OSM images for mapping: Eastern Iceland","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82160152013239LGN00&z={zoom}&x={x}&y={-y}","description":"Missing islets and inaccurate coast (true color)","scaleExtent":[0,12],"polygon":[[[-13.047005598725303,64.2110895294821],[-15.164963667572959,64.22408122727819],[-15.168053572358117,64.81572800422087],[-13.043572371186242,64.80359943673454],[-13.047005598725303,64.2110895294821]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-AST_L1T_00302052007154424_20150518041444_91492","name":"imagico.de OSM images for mapping: El Altar","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=AST_L1T_00302052007154424_20150518041444_91492&z={zoom}&x={x}&y={-y}","description":"2007 ASTER image offering better glacier coverage than common sources (true color with estimated blue)","scaleExtent":[0,14],"polygon":[[[-78.531997745432,-1.805085317123331],[-78.531997745432,-1.608105565001241],[-78.33561713019762,-1.608105565001241],[-78.33561713019762,-1.805085317123331],[-78.531997745432,-1.805085317123331]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R009_S61_20160109","name":"imagico.de OSM images for mapping: Elephant Island/Clarence Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R009_S61_20160109&z={zoom}&x={x}&y={-y}","description":"Fairly clear up-to-date image for updating glacier edges (true color)","scaleExtent":[0,13],"polygon":[[[-56.13476090727487,-61.63471600102006],[-56.13476090727487,-61.199363166283845],[-55.83263688383738,-60.84015069906498],[-53.72343354521433,-60.83981613078141],[-53.72343354521433,-61.63471600102006],[-56.13476090727487,-61.63471600102006]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-enderby","name":"imagico.de OSM images for mapping: Enderby Land and Kemp Coast","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=enderby&z={zoom}&x={x}&y={-y}","description":"Sentinel-2 images of Enderby Land and Kemp Coast (true color)","scaleExtent":[0,13],"polygon":[[[45.4547,-68.5091],[45.4547,-67.5724],[49.7155,-65.7176],[59.2693,-65.7176],[67.3735,-67.3449],[67.3735,-68.2581],[67.088,-68.5091],[45.4547,-68.5091]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82100502015347LGN00","name":"imagico.de OSM images for mapping: Fogo, Cape Verde","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82100502015347LGN00&z={zoom}&x={x}&y={-y}","description":"Image from after the 2014/2015 eruption (true color)","scaleExtent":[0,14],"polygon":[[[-24.758781955967567,14.748140156641956],[-24.758781955967567,15.092493544965103],[-24.267057941685337,15.092493544965103],[-24.267057941685337,14.748140156641956],[-24.758781955967567,14.748140156641956]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-greenland","name":"imagico.de OSM images for mapping: Greenland mosaic","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=greenland&z={zoom}&x={x}&y={-y}","description":"Landsat mosaic of Greenland (true color)","scaleExtent":[0,12],"polygon":[[[-43.9774,59.7171],[-44.545,59.7302],[-44.9203,59.7672],[-45.3587,59.8218],[-45.763,59.8848],[-46.0859,59.9827],[-46.3381,60.119],[-46.577,60.2652],[-46.8114,60.4418],[-47.2635,60.5314],[-47.6937,60.5549],[-48.1457,60.6192],[-48.5771,60.7015],[-48.8689,60.8506],[-49.0578,61.0555],[-49.396,61.2957],[-49.7601,61.4934],[-50.2064,61.7324],[-50.4699,61.9539],[-50.8647,62.1596],[-51.0631,62.3869],[-51.2121,62.6001],[-51.3005,62.8389],[-51.4238,62.9979],[-51.6767,63.1944],[-51.9465,63.4079],[-52.0253,63.6377],[-52.2255,63.8378],[-52.3658,64.0705],[-52.4829,64.3792],[-52.4988,64.6788],[-52.789,64.9063],[-53.2046,65.1321],[-53.6649,65.4753],[-53.9977,65.8019],[-54.1348,66.1568],[-54.1441,66.5235],[-54.2285,66.8319],[-54.4519,67.303],[-54.5141,67.7648],[-54.604,68.2021],[-54.568,68.5698],[-54.598,68.8347],[-54.7606,69.1207],[-55.0028,69.4125],[-55.2735,69.6187],[-55.3808,69.8283],[-55.3945,70.0838],[-55.3094,70.2573],[-55.4307,70.479],[-55.5501,70.6707],[-55.7654,70.861],[-56.2489,71.2343],[-56.5018,71.5429],[-56.5867,71.9015],[-56.5189,72.2355],[-56.5085,72.5258],[-56.8923,72.8144],[-57.4027,73.1054],[-57.8066,73.4566],[-58.1461,73.7696],[-58.3554,74.0972],[-58.5125,74.3783],[-58.7336,74.6328],[-59.3551,74.8869],[-60.1412,75.102],[-61.0067,75.2763],[-61.911,75.3886],[-62.4706,75.5595],[-62.9776,75.7454],[-64.1463,75.779],[-65.4481,75.7235],[-66.7068,75.6792],[-67.8379,75.6525],[-69.0456,75.6195],[-70.055,75.5344],[-71.0898,75.4705],[-72.1119,75.4476],[-74.2311,76.4102],[-74.5601,76.5328],[-74.5601,82.6959],[-14.4462,82.6959],[-14.3994,82.5997],[-13.5339,82.4379],[-12.0312,82.3426],[-10.7796,82.3196],[-10.7796,80.1902],[-11.2123,80.069],[-11.136,79.8103],[-10.7796,79.5176],[-10.7796,79.0441],[-11.2626,78.7128],[-12.2579,78.3558],[-13.2398,78.1272],[-13.7649,77.9279],[-14.1169,77.6779],[-14.7129,77.5278],[-15.5507,77.3655],[-16.0936,77.0771],[-16.0586,76.5548],[-15.838,75.9611],[-15.6879,75.4726],[-16.253,75.058],[-17.0427,74.6425],[-18.3155,74.2702],[-19.4463,73.9378],[-19.8329,73.632],[-20.2938,73.3524],[-20.7831,73.0446],[-21.01,72.6766],[-20.8774,72.2926],[-20.7672,71.8726],[-20.7765,71.4304],[-20.9411,70.9802],[-21.219,70.6126],[-21.5326,70.3001],[-21.8039,70.0911],[-22.166,69.8947],[-22.4831,69.7539],[-22.9027,69.6585],[-23.3545,69.544],[-23.9177,69.4036],[-24.1794,69.3088],[-24.6745,69.1084],[-25.1222,68.9555],[-25.6659,68.7995],[-26.0994,68.583],[-26.6316,68.4043],[-27.7638,68.2813],[-28.4575,68.0023],[-29.353,67.8135],[-30.6456,67.4911],[-31.7673,67.0005],[-32.9783,66.2596],[-33.9313,66.0156],[-34.8956,65.7403],[-35.5914,65.5208],[-36.1483,65.372],[-36.7532,65.2559],[-37.1858,65.1349],[-37.6032,64.9727],[-38.0624,64.4901],[-38.5304,64.1244],[-39.0545,63.7213],[-39.3131,63.4405],[-39.5739,62.7506],[-39.9532,62.2739],[-40.2757,61.8547],[-40.714,61.3365],[-41.2091,60.8495],[-41.821,60.5526],[-42.4368,60.3264],[-42.8643,60.0299],[-43.1131,59.9147],[-43.3282,59.83],[-43.5459,59.7695],[-43.797,59.7284],[-43.9774,59.7171]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R047_S54_20160411T044330","name":"imagico.de OSM images for mapping: Heard Island coast","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R047_S54_20160411T044330&z={zoom}&x={x}&y={-y}","description":"Recent image of Heard island with interior mostly cloud covered but mostly well visible coast (true color)","scaleExtent":[0,13],"polygon":[[[73.06896521028185,-53.270590689700434],[73.06896521028185,-52.875489636268725],[73.67338491853381,-52.87673289134188],[74.08863378938341,-52.94950473139763],[74.08863378938341,-53.270590689700434],[73.06896521028185,-53.270590689700434]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82280982013259LGN00","name":"imagico.de OSM images for mapping: Isla Londonderry","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82280982013259LGN00&z={zoom}&x={x}&y={-y}","description":"A lot of very coarse coastlines could be improved here, much snow cover though so no use for glacier mapping (false color IR)","scaleExtent":[0,12],"polygon":[[[-69.85679747431641,-55.55949231551995],[-72.26520659296875,-55.149427383391455],[-72.26520659296875,-54.51089432315929],[-72.08530546992188,-54.17909103768387],[-69.49115874140625,-54.17889010631196],[-69.49150206416016,-55.28378528847367],[-69.62230803339844,-55.55910398108892],[-69.85679747431641,-55.55949231551995]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R021_N44_20160807T083013","name":"imagico.de OSM images for mapping: Kerch Strait","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R021_N44_20160807T083013&z={zoom}&x={x}&y={-y}","description":"State of bridge construction in August 2016 (true color)","scaleExtent":[0,14],"polygon":[[[35.932588577270494,44.96236872935039],[35.932588577270494,45.559256426515695],[37.369909286499016,45.559256426515695],[37.369909286499016,44.96236872935039],[35.932588577270494,44.96236872935039]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-ls_polar2","name":"imagico.de OSM images for mapping: Landsat off-nadir July 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=ls_polar2&z={zoom}&x={x}&y={-y}","description":"Latest images north of the regular Landsat limit (true color)","scaleExtent":[0,10],"polygon":[[[-79.05174500251786,81.91484289044183],[-79.05174500251786,83.43338556749623],[-73.60389956385866,83.80224987787145],[-26.424486898081835,83.80224987787145],[-21.492998879371186,83.50352415480617],[-16.888354121159868,83.15094632775453],[-16.888354121159868,81.91484289044183],[-79.05174500251786,81.91484289044183]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-AST_L1T_00311162013112731_20150618142416_109190","name":"imagico.de OSM images for mapping: Leskov Island ASTER","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=AST_L1T_00311162013112731_20150618142416_109190&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color with estimated blue)","scaleExtent":[0,13],"polygon":[[[-28.210747081406492,-56.72108048139938],[-28.210747081406492,-56.624975043089115],[-27.96956284678735,-56.624975043089115],[-27.96956284678735,-56.72108048139938],[-28.210747081406492,-56.72108048139938]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81991002015286LGN00","name":"imagico.de OSM images for mapping: Leskov Island Landsat","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81991002015286LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color)","scaleExtent":[0,13],"polygon":[[[-27.992928409215843,-56.73479060902333],[-28.227761172887714,-56.732624892496354],[-28.2241562839717,-56.600752537318456],[-27.969754123327167,-56.60283135691063],[-27.97318735086623,-56.73479060902333],[-27.992928409215843,-56.73479060902333]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-ls_polar","name":"imagico.de OSM images for mapping: May 2013 off-nadir Landsat","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=ls_polar&z={zoom}&x={x}&y={-y}","description":"First available image north of the regular Landsat limit, mostly with seasonal snow cover so difficult to interpret (true color)","scaleExtent":[0,10],"polygon":[[[-85.76109385682587,81.39333391115835],[-89.83015512094161,82.14951616258433],[-89.83152841195212,82.24404688557661],[-84.99342418195555,82.73098798225534],[-79.95207288240479,83.13107965605444],[-74.55641250214465,83.46266728201661],[-69.35850602739671,83.70450775086888],[-28.207840897721187,83.70450775086888],[-23.06623935440381,83.46532469372944],[-17.96583654140148,83.15518123848051],[-17.96720983241198,82.72386035102944],[-22.781968115230015,81.44190408358111],[-85.76109385682587,81.39333391115835]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R092_S02_20160613T075613","name":"imagico.de OSM images for mapping: Mount Kenya 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R092_S02_20160613T075613&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping (true color)","scaleExtent":[0,14],"polygon":[[[37.20665931701659,-0.266846645776291],[37.20665931701659,-0.011930465612033],[37.5655174255371,-0.011930465612033],[37.5655174255371,-0.266846645776291],[37.20665931701659,-0.266846645776291]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R092_S05_20160802T075556","name":"imagico.de OSM images for mapping: Mount Kilimanjaro 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R092_S05_20160802T075556&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping (true color)","scaleExtent":[0,14],"polygon":[[[37.24768638610839,-3.229213650135676],[37.24768638610839,-2.968155849006605],[37.61581420898436,-2.968155849006605],[37.61581420898436,-3.229213650135676],[37.24768638610839,-3.229213650135676]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80940622015159LGN00","name":"imagico.de OSM images for mapping: New Ireland","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80940622015159LGN00&z={zoom}&x={x}&y={-y}","description":"Many missing islands in OSM (mostly mapped meanwhile) (true color)","scaleExtent":[0,14],"polygon":[[[150.38853376619625,-2.800534349432724],[150.38853376619625,-2.383396178206425],[150.83348005525875,-2.383396178206425],[150.83348005525875,-2.800534349432724],[150.38853376619625,-2.800534349432724]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-northsea_s2_2016","name":"imagico.de OSM images for mapping: North Sea Coast 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=northsea_s2_2016&z={zoom}&x={x}&y={-y}","description":"Up-to-date low tide imagery of the coast for updating mapping of tidalflats and shoals (true color)","scaleExtent":[0,13],"polygon":[[[5.1562,52.8755],[5.1615,53.0325],[6.4155,55.7379],[9.8813,55.7459],[9.8813,53.2428],[9.6846,52.8877],[5.1562,52.8755]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-ural_s2_2016","name":"imagico.de OSM images for mapping: Northern and Polar Ural mountains August 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=ural_s2_2016&z={zoom}&x={x}&y={-y}","description":"Up-to-date late summer imagery with few clouds - caution: not all visible snow is glaciers (true color)","scaleExtent":[0,13],"polygon":[[[59.198977223476454,64.8920468958533],[59.198977223476454,66.91656046303187],[60.733286610683486,68.44289182710118],[67.7329509173241,68.44327026354412],[67.7329509173241,67.748828729217],[64.21646761043934,64.9195663902952],[59.198977223476454,64.8920468958533]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-nellesmere_ast","name":"imagico.de OSM images for mapping: Northern Ellesmere Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=nellesmere_ast&z={zoom}&x={x}&y={-y}","description":"Assembled from July 2012 ASTER imagery (true color with estimated blue)","scaleExtent":[0,10],"polygon":[[[-81.62923243782096,82.45969864814401],[-83.03136255954291,82.47985512217643],[-83.03136255954291,83.05876272004272],[-72.80309111332822,83.09567468670448],[-65.65785798568925,83.03232446260982],[-65.8116665788654,82.45969864814401],[-81.62923243782096,82.45969864814401]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-nellesmere_ast_2016","name":"imagico.de OSM images for mapping: Northern Ellesmere Island July 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=nellesmere_ast_2016&z={zoom}&x={x}&y={-y}","description":"Assembled from July 2016 ASTER imagery (true color with estimated blue)","scaleExtent":[0,10],"polygon":[[[-78.89729497133754,82.17577067162792],[-82.64500613899595,82.19425721404356],[-82.64500613899595,83.08067098163464],[-66.58986093522367,83.08497116318647],[-63.78010752773773,82.98907949583335],[-63.78010752773773,82.72198178031782],[-65.0092029821365,82.17577067162792],[-78.89729497133754,82.17577067162792]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81960222015233LGN00vis","name":"imagico.de OSM images for mapping: Northern German west coast tidalflats","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81960222015233LGN00vis&z={zoom}&x={x}&y={-y}","description":"Up-to-date low tide imagery of the coast for updating mapping of tidalflats and shoals (true color)","scaleExtent":[0,12],"polygon":[[[7.63567991501593,53.28027339774928],[7.63567991501593,53.66770140276793],[8.49433012253546,55.502457780526],[9.207754805152648,55.48106268908912],[9.207754805152648,53.28027339774928],[7.63567991501593,53.28027339774928]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81960222015233LGN00ir","name":"imagico.de OSM images for mapping: Northern German west coast tidalflats (infrared)","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81960222015233LGN00ir&z={zoom}&x={x}&y={-y}","description":"Up-to-date low tide imagery of the coast for updating mapping of tidalflats and shoals (false color IR)","scaleExtent":[0,12],"polygon":[[[7.63567991501593,53.28027339774928],[7.63567991501593,53.66810821588294],[8.49433012253546,55.502457780526],[9.207754805152648,55.48106268908912],[9.207754805152648,53.28027339774928],[7.63567991501593,53.28027339774928]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-ngreenland_ast","name":"imagico.de OSM images for mapping: Northern Greenland ASTER","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=ngreenland_ast&z={zoom}&x={x}&y={-y}","description":"Assembled from mostly 2012 ASTER imagery, some 2005 images mainly in the northeast (true color with estimated blue)","scaleExtent":[0,10],"polygon":[[[-52.49221819430999,82.48971755550389],[-52.49221819430999,82.94294978186194],[-49.28695697579964,83.47311821807558],[-44.52850362441216,83.7321400994933],[-29.525299334683975,83.7321400994933],[-25.263977329098022,83.58271128961059],[-21.183929736898254,83.39775984253468],[-21.183929736898254,82.74312310369845],[-23.404541300879075,82.48971755550389],[-52.49221819430999,82.48971755550389]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-EO1A1350972013086110KF","name":"imagico.de OSM images for mapping: Northwest Heard Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=EO1A1350972013086110KF&z={zoom}&x={x}&y={-y}","description":"Glaciers of Northwest Heard Island (mapped meanwhile) (false color IR)","scaleExtent":[0,13],"polygon":[[[73.22790413350113,-53.20333324999222],[73.22790413350113,-53.01072925838941],[73.2594898268605,-52.94943913810479],[73.78992348164566,-52.94943913810479],[73.78992348164566,-53.06048282358537],[73.71782570332533,-53.20333324999222],[73.22790413350113,-53.20333324999222]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R111_N09_20160604T154554","name":"imagico.de OSM images for mapping: Panama Canal","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R111_N09_20160604T154554&z={zoom}&x={x}&y={-y}","description":"Images of the new locks (but partly cloudy) (true color)","scaleExtent":[0,14],"polygon":[[[-80.01653561766223,8.848981570244637],[-80.01653561766223,9.41480707574399],[-79.46859250242785,9.41480707574399],[-79.46859250242785,8.848981570244637],[-80.01653561766223,8.848981570244637]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-EO1A0120532016364110KF","name":"imagico.de OSM images for mapping: Panama Canal - Pacific side","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=EO1A0120532016364110KF&z={zoom}&x={x}&y={-y}","description":"New locks with less clouds than in the Sentinel-2 image - make sure to check image alignment (true color)","scaleExtent":[0,14],"polygon":[[[-79.62538719177245,8.770827350748924],[-79.68684196472167,8.821974500616129],[-79.6866703033447,8.93705081902936],[-79.65362548828124,9.0929436313527],[-79.268159866333,9.0929436313527],[-79.32832717895505,8.770827350748924],[-79.62538719177245,8.770827350748924]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R078_N68_20160930T081002","name":"imagico.de OSM images for mapping: Pechora Sea Coast","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R078_N68_20160930T081002&z={zoom}&x={x}&y={-y}","description":"Sentinel-2 image of the Pechora Sea coast in autumn 2016 (true color)","scaleExtent":[0,13],"polygon":[[[53.1802,67.5344],[53.1821,68.414],[54.2107,69.3367],[55.3584,70.2786],[59.004,70.2786],[60.6947,69.977],[61.9837,69.7161],[61.9823,68.9395],[59.9153,67.5344],[53.1802,67.5344]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81511242016033LGN00","name":"imagico.de OSM images for mapping: Pensacola Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81511242016033LGN00&z={zoom}&x={x}&y={-y}","description":"Outside regular Landsat coverage and therefore not in LIMA and Bing/Mapbox (true color)","scaleExtent":[0,10],"polygon":[[[-53.20921946177197,-84.12524693598144],[-60.615377881406225,-83.78609327915953],[-60.615377881406225,-82.29968785439104],[-48.72405102147429,-82.29987186164387],[-44.52178052933989,-82.43683433550413],[-44.51354078327688,-84.12524693598144],[-53.20921946177197,-84.12524693598144]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R136_N41_20150831T093006","name":"imagico.de OSM images for mapping: Prokletije Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R136_N41_20150831T093006&z={zoom}&x={x}&y={-y}","description":"Late summer imagery where usual sources are severely limited by clouds and snow (true color)","scaleExtent":[0,14],"polygon":[[[19.112325688609005,42.1531576323006],[19.08425905347717,43.08073531915633],[20.63298799634826,43.09602978090892],[20.637880345591427,42.167791043253985],[19.112325688609005,42.1531576323006]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-DMS_1142622_03746_20110415_17533956","name":"imagico.de OSM images for mapping: Qasigiannguit","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=DMS_1142622_03746_20110415_17533956&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS image of the settlement - alignment might be poor","scaleExtent":[0,15],"polygon":[[[-51.238571767352376,68.79971882076842],[-51.243335370562825,68.85302612951142],[-51.151668195269856,68.85302612951142],[-51.14038145973519,68.80116208175376],[-51.238571767352376,68.79971882076842]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81510432015030LGN00","name":"imagico.de OSM images for mapping: Rann of Kutch","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81510432015030LGN00&z={zoom}&x={x}&y={-y}","description":"Land/water distinction difficult to properly map based on Bing/Mapbox images (false color IR)","scaleExtent":[0,12],"polygon":[[[67.96839858817646,22.36264542957619],[67.86231185721942,22.38391650007107],[67.86231185721942,24.886930816927297],[71.48986007499286,24.886930816927297],[71.48986007499286,22.36264542957619],[67.96839858817646,22.36264542957619]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R093_N41_20150828T092005","name":"imagico.de OSM images for mapping: Rila and Pirin Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R093_N41_20150828T092005&z={zoom}&x={x}&y={-y}","description":"Late summer imagery where usual sources are severely limited by clouds and snow (true color)","scaleExtent":[0,14],"polygon":[[[23.808114560320394,41.584878805945024],[22.992379697039144,41.6019534981177],[23.011863263323328,42.29983747360261],[23.99402383156063,42.283393175568236],[23.965613873674886,41.584878805945024],[23.808114560320394,41.584878805945024]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81730602015040LGN00","name":"imagico.de OSM images for mapping: Rwenzori Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81730602015040LGN00&z={zoom}&x={x}&y={-y}","description":"Recent image of most of the remaining Rwenzori Mountains glaciers (false color IR)","scaleExtent":[0,13],"polygon":[[[29.766296776846374,0.206886934953159],[29.766296776846374,0.509176367154027],[30.034603509024116,0.509176367154027],[30.034603509024116,0.206886934953159],[29.766296776846374,0.206886934953159]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R078_N01_20160702T082522","name":"imagico.de OSM images for mapping: Rwenzori Mountains 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R078_N01_20160702T082522&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping (true color)","scaleExtent":[0,14],"polygon":[[[29.8051357269287,0.235862065771959],[29.8051357269287,0.467085433008179],[30.02503395080565,0.467085433008179],[30.02503395080565,0.235862065771959],[29.8051357269287,0.235862065771959]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80611072014036LGN00","name":"imagico.de OSM images for mapping: Scott Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80611072014036LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color)","scaleExtent":[0,13],"polygon":[[[-180,-67.4263452007858],[-180,-67.32544337276457],[-179.8247337341308,-67.3253771978419],[-179.8247337341308,-67.4263452007858],[-180,-67.4263452007858]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82100972015347LGN00","name":"imagico.de OSM images for mapping: Shag Rocks","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82100972015347LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color)","scaleExtent":[0,13],"polygon":[[[-42.12874872458635,-53.72050213468143],[-42.14625818503558,-53.45782244664258],[-41.67573435080706,-53.445862233424414],[-41.6558216310805,-53.70871763480476],[-42.12874872458635,-53.72050213468143]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81130622013270LGN00","name":"imagico.de OSM images for mapping: Southeastern Sulawesi","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81130622013270LGN00&z={zoom}&x={x}&y={-y}","description":"Missing islands and coarse coastline due to cloud cover in Bing, lakes could also use additional detail (true color)","scaleExtent":[0,13],"polygon":[[[120.84382442048364,-3.595452324350203],[120.84382442048364,-3.159848173206955],[120.98184016755395,-2.514681686347053],[122.62618449738794,-2.514681686347053],[122.62618449738794,-3.002148034113534],[122.5007000308352,-3.595452324350203],[120.84382442048364,-3.595452324350203]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80281222016035LGN00","name":"imagico.de OSM images for mapping: Southern Transantarctic Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80281222016035LGN00&z={zoom}&x={x}&y={-y}","description":"Outside regular Landsat coverage and therefore not in LIMA and Bing/Mapbox (true color)","scaleExtent":[0,10],"polygon":[[[156.96951345925345,-84.50097988272655],[154.50857596843485,-84.46255082580927],[154.50857596843485,-82.60681485793681],[175.46774337070775,-82.58504749645738],[177.00582930246938,-83.52806548607914],[177.00582930246938,-84.19262083779002],[171.93838547371908,-84.34632646581997],[166.83798266071676,-84.44370142483508],[161.67028858819987,-84.50045345467909],[156.96951345925345,-84.50097988272655]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-s2sval","name":"imagico.de OSM images for mapping: Svalbard mosaic","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=s2sval&z={zoom}&x={x}&y={-y}","description":"Sentinel-2 mosaic of Svalbard (true color)","scaleExtent":[0,13],"polygon":[[[16.6108,76.4137],[16.4731,76.4268],[16.3788,76.4589],[14.4124,77.1324],[14.0784,77.2536],[10.9875,78.4054],[10.631,78.5605],[10.2314,78.8392],[10.3952,79.6074],[10.516,79.7731],[10.9632,79.8707],[20.2294,80.849],[20.4702,80.8493],[25.1752,80.6817],[33.4391,80.3438],[33.7809,80.3016],[34.0395,80.239],[33.977,80.1527],[25.5722,76.5917],[25.2739,76.481],[25.1416,76.4327],[24.937,76.4176],[16.6108,76.4137]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-DMS_1142636_160xx_20110507_1822xxxx","name":"imagico.de OSM images for mapping: Thule Air Base","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=DMS_1142636_160xx_20110507_1822xxxx&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS image - alignment might be poor","scaleExtent":[0,15],"polygon":[[[-68.93976917529807,76.51132557714853],[-68.93976917529807,76.54990046497333],[-68.76634826923117,76.55175699880375],[-68.50992908740743,76.55175699880375],[-68.50743999744161,76.51611959755911],[-68.67897262836203,76.51193618208278],[-68.93976917529807,76.51132557714853]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-dms_thule2_2015.09.25","name":"imagico.de OSM images for mapping: Thule Airbase DMS low altitude overflight September 2015","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=dms_thule2_2015.09.25&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS aerial images from Thule Airbase - alignment might be poor","scaleExtent":[0,17],"polygon":[[[-68.74291885235837,76.52635852412212],[-68.74446380475094,76.52840070669755],[-68.74806869366695,76.54938731810256],[-68.7461482320123,76.56016657973251],[-68.72275936940244,76.56022393334496],[-68.72017371991207,76.5577475347327],[-68.71853220799495,76.5292079974043],[-68.71977675297786,76.52636602351234],[-68.74291885235837,76.52635852412212]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-dms_thule_2015.10.06","name":"imagico.de OSM images for mapping: Thule Airbase DMS overflight October 2015","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=dms_thule_2015.10.06&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS aerial images from Thule Airbase - alignment might be poor","scaleExtent":[0,16],"polygon":[[[-68.81923965911197,76.52510098413808],[-68.82651380996036,76.54176603738404],[-68.77344898680974,76.5439032956252],[-68.7021022270136,76.54544610909097],[-68.59176687697696,76.54560088014632],[-68.59183124999333,76.52793072237704],[-68.65970186690618,76.52510098413808],[-68.81923965911197,76.52510098413808]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-dms_thule_2015.09.25","name":"imagico.de OSM images for mapping: Thule Airbase DMS overflight September 2015","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=dms_thule_2015.09.25&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS aerial images from Thule Airbase - alignment might be poor","scaleExtent":[0,16],"polygon":[[[-68.7777130980429,76.50687742381471],[-68.77661875676482,76.57064446843503],[-68.68115357350676,76.57065443536027],[-68.67630413960784,76.55384487076157],[-68.67619685124725,76.5307435998188],[-68.6852305312094,76.50688243050337],[-68.7777130980429,76.50687742381471]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R094_N79_20160812T105622","name":"imagico.de OSM images for mapping: Ushakov Island August 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R094_N79_20160812T105622&z={zoom}&x={x}&y={-y}","description":"Up-to-date late summer imagery with few clouds (true color)","scaleExtent":[0,12],"polygon":[[[78.45885691499899,80.72643412860921],[78.45885691499899,80.9098976404357],[80.48892435884663,80.9098976404357],[80.48892435884663,80.72643412860921],[78.45885691499899,80.72643412860921]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80910682014358LGN00","name":"imagico.de OSM images for mapping: Vanatinai","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80910682014358LGN00&z={zoom}&x={x}&y={-y}","description":"Coarse coastline due to cloud cover in Bing/Mapbox (true color)","scaleExtent":[0,13],"polygon":[[[153.0613810625655,-11.789228234021259],[153.0613810625655,-11.288690822294749],[153.10927458673538,-11.072292520575749],[154.41201277643268,-11.072292520575749],[154.41201277643268,-11.789228234021259],[153.0613810625655,-11.789228234021259]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82330892016031LGN00","name":"imagico.de OSM images for mapping: Volcán Calbuco","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82330892016031LGN00&z={zoom}&x={x}&y={-y}","description":"Image from after the 2015 eruption (true color)","scaleExtent":[0,13],"polygon":[[[-72.8669610523419,-41.51741123877955],[-72.8669610523419,-41.045274923011036],[-72.23181395761533,-41.045274923011036],[-71.87510161630674,-41.10829439141359],[-72.00007109872861,-41.51741123877955],[-72.8669610523419,-41.51741123877955]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R089_N52_20160623T024048","name":"imagico.de OSM images for mapping: Vostochny Cosmodrome","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R089_N52_20160623T024048&z={zoom}&x={x}&y={-y}","description":"Recent image showing newest features (true color)","scaleExtent":[0,13],"polygon":[[[126.36143429881301,51.375528375017275],[126.34804471141064,52.33932231282816],[128.60762341624462,52.340895519845674],[128.6117432892915,51.375528375017275],[126.36143429881301,51.375528375017275]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81490352013282LGN00","name":"imagico.de OSM images for mapping: Western Karakoram","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81490352013282LGN00&z={zoom}&x={x}&y={-y}","description":"Represents approximately minimum snow cover so can be well used for glacier mapping (true color)","scaleExtent":[0,13],"polygon":[[[75.98364343730569,34.97850982318471],[73.96164407817483,35.36957188964085],[74.44281091777444,37.09391400468158],[76.50600900737405,36.7026732100855],[75.98364343730569,34.97850982318471]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R039_S15_20160510T145731","name":"imagico.de OSM images for mapping: Willkanuta Mountains and Quelccaya Ice Cap","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R039_S15_20160510T145731&z={zoom}&x={x}&y={-y}","description":"Poor and outdated imagery in other sources (true color)","scaleExtent":[0,14],"polygon":[[[-71.18070648306262,-14.4978507264954],[-71.17976234548938,-13.710292880050797],[-70.5563740550841,-13.71262765059222],[-70.5563740550841,-14.4978507264954],[-71.18070648306262,-14.4978507264954]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"IPR-orotofoto-last-tms","name":"IPR ortofoto LAST (tmsproxy)","type":"tms","template":"http://osm-{switch:a,b,c}.zby.cz/tiles_ipr_last.php/{zoom}/{x}/{y}.jpg","scaleExtent":[1,18],"polygon":[[[14.81231552124,49.93089301941],[14.18754582291,49.87687266984],[14.12025456314,50.19881542327],[14.74502426147,50.25247461226],[14.81231552124,49.93089301941]]]},{"id":"IPR-orotofoto-vege-tms","name":"IPR ortofoto Low-Vegetation (tmsproxy)","type":"tms","template":"http://osm-{switch:a,b,c}.zby.cz/tiles_ipr_vege.php/{zoom}/{x}/{y}.jpg","scaleExtent":[1,20],"polygon":[[[14.30454236984,49.99538124382],[14.3160436821,49.94205148763],[14.3499983888,49.94508261663],[14.35383872175,49.92726356386],[14.42385321818,49.93351545169],[14.4200902288,49.95097343212],[14.48865449494,49.95709281879],[14.48479036398,49.9750111737],[14.55385989188,49.98117257481],[14.55011770159,49.99851689993],[14.58455395868,50.0015874108],[14.58829614897,49.98424419323],[14.69168128485,49.99346468175],[14.67633637226,50.06452744171],[14.71278864961,50.06777324036],[14.70115373952,50.12158114828],[14.66470146217,50.11833899243],[14.6610031918,50.13543086714],[14.62755290441,50.13245658485],[14.61965341283,50.16894659259],[14.58542741996,50.16590546732],[14.58162921725,50.18344165464],[14.40776267983,50.167995553],[14.41156088254,50.15045369625],[14.37764851321,50.14743927281],[14.37379555571,50.16523508727],[14.33892816423,50.16213672855],[14.34278112173,50.14433976066],[14.27367931007,50.13819641038],[14.27749028245,50.12058459573],[14.20879964298,50.11447476994],[14.21288816219,50.09557069695],[14.24656290855,50.09856724424],[14.25417384067,50.06335893014],[14.21987061144,50.0603042129],[14.22369648177,50.04259477081],[14.257999711,50.04565061557],[14.26952647673,49.99225864496],[14.30454236984,49.99538124382]]]},{"id":"bartholomew_qi1940","name":"Ireland Bartholomew Quarter-Inch 1940","type":"tms","template":"http://geo.nls.uk/maps/ireland/bartholomew/{zoom}/{x}/{-y}.png","scaleExtent":[5,13],"polygon":[[[-8.8312773,55.3963337],[-7.3221271,55.398605],[-7.2891331,55.4333162],[-7.2368042,55.4530757],[-7.18881,55.4497995],[-7.1528144,55.3968384],[-6.90561,55.394903],[-6.9047153,55.3842114],[-5.8485282,55.3922956],[-5.8378629,55.248676],[-5.3614762,55.2507024],[-5.3899172,53.8466464],[-5.8734141,53.8487436],[-5.8983,52.8256258],[-6.0191742,52.8256258],[-6.0262844,51.7712367],[-8.1131422,51.7712367],[-8.1273627,51.3268839],[-10.6052842,51.3091083],[-10.6271879,52.0328254],[-10.6469845,52.0322454],[-10.6469845,52.0440365],[-10.6271879,52.0448095],[-10.6290733,52.0745627],[-10.6699234,52.0743695],[-10.6702376,52.0876941],[-10.6312729,52.0898179],[-10.6393128,52.4147202],[-10.3137689,52.4185533],[-10.3166401,53.3341342],[-10.3699669,53.3330727],[-10.385965,54.3534472],[-8.8163777,54.3586265],[-8.8173427,54.6595721],[-8.8413398,54.6616284],[-8.8422286,54.6929749],[-8.8315632,54.7145436],[-8.8151208,54.7145436],[-8.8312773,55.3963337]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"GSGS3906","name":"Ireland British War Office 1:25k GSGS 3906","type":"tms","template":"http://mapwarper.net/layers/tile/101/{zoom}/{x}/{y}.png","scaleExtent":[0,18],"polygon":[[[-10.71,51.32],[-10.71,55.46],[-5.37,55.46],[-5.37,51.32],[-10.71,51.32]]],"terms_url":"http://wiki.openstreetmap.org/wiki/WikiProject_Ireland#Trinity_College_Dublin","terms_text":"Glucksman Map Library, Trinity College Dublin"},{"id":"GSGS4136","name":"Ireland British War Office One-Inch 1941-43 GSGS 4136","type":"tms","template":"http://geo.nls.uk/maps/ireland/gsgs4136/{zoom}/{x}/{-y}.png","scaleExtent":[5,15],"polygon":[[[-10.0847426,51.4147902],[-10.0906535,51.5064103],[-10.4564222,51.5003961],[-10.5005905,52.3043019],[-10.0837522,52.312741],[-10.0840973,52.3404698],[-10.055802,52.3408915],[-10.0768509,52.7628238],[-9.7780248,52.7684611],[-9.7818205,52.8577261],[-9.6337877,52.8596012],[-9.6449626,53.1294502],[-10.0919663,53.1227152],[-10.1051422,53.3912913],[-10.4052593,53.3866349],[-10.4530828,54.193502],[-10.2998523,54.1974988],[-10.3149801,54.4669592],[-8.9276095,54.4853897],[-8.9339534,54.7546562],[-8.7773069,54.755501],[-8.7826749,55.0252208],[-8.9402974,55.0238221],[-8.9451773,55.2934155],[-7.528039,55.2970274],[-7.525599,55.3874955],[-7.0541955,55.3841691],[-7.0556595,55.2939712],[-6.3241545,55.2859128],[-6.3217146,55.3253556],[-6.1035807,55.3223016],[-6.1045566,55.2828557],[-5.7985836,55.2772968],[-5.8117595,55.0087135],[-5.656577,55.0056351],[-5.6721928,54.7355021],[-5.3618278,54.729585],[-5.3964755,54.1917889],[-5.855679,54.2017807],[-5.9220464,52.8524504],[-6.070885,52.8551025],[-6.1030927,52.1373337],[-6.8331336,52.1463183],[-6.8355736,52.0578908],[-7.5641506,52.0617913],[-7.5661026,51.7921593],[-8.147305,51.792763],[-8.146329,51.7033331],[-8.2912636,51.7027283],[-8.2897996,51.5227274],[-9.1174397,51.516958],[-9.1179277,51.4625685],[-9.3692452,51.4616564],[-9.3672933,51.4254613],[-10.0847426,51.4147902]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"gsi.go.jp","name":"Japan GSI ortho Imagery","type":"tms","template":"http://cyberjapandata.gsi.go.jp/xyz/ort/{zoom}/{x}/{y}.jpg","scaleExtent":[12,19],"polygon":[[[141.85546875,44.64911632343077],[140.2294921875,43.96909818325174],[138.955078125,41.80407814427237],[139.482421875,40.17887331434696],[138.8671875,38.30718056188316],[136.31835937499997,37.19533058280065],[132.1435546875,35.137879119634185],[128.935546875,33.35806161277885],[129.5068359375,32.47269502206151],[129.77050781249997,31.690781806136822],[130.2099609375,30.90222470517144],[131.220703125,30.78903675126116],[131.66015625,32.32427558887655],[132.71484375,32.879587173066305],[133.76953125,33.17434155100208],[136.7578125,33.87041555094183],[139.306640625,35.06597313798418],[140.888671875,35.17380831799959],[141.15234374999997,36.56260003738548],[142.11914062499997,39.9434364619742],[141.767578125,42.68243539838623],[141.85546875,44.64911632343077]]]},{"id":"Aargau-AGIS-2011","name":"Kanton Aargau 25cm (AGIS 2011)","type":"tms","template":"http://tiles.poole.ch/AGIS/OF2011/{zoom}/{x}/{y}.png","scaleExtent":[14,19],"polygon":[[[7.7,47.12],[7.7,47.63],[8.5,47.63],[8.5,47.12],[7.7,47.12]]],"terms_text":"AGIS OF2011"},{"id":"Aargau-AGIS-2014","name":"Kanton Aargau 25cm (AGIS 2014)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/AGIS2014/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,20],"polygon":[[[8.222923278808594,47.604774168947614],[8.244209289550781,47.613569753973955],[8.294334411621094,47.60986653003798],[8.300857543945312,47.58625231278527],[8.329353332519531,47.569808674020344],[8.382568359375,47.56702895728551],[8.398017883300781,47.57490443821351],[8.424797058105469,47.56795554592218],[8.415184020996094,47.54663986006874],[8.389778137207031,47.5262428287156],[8.372268676757812,47.51233121261258],[8.358535766601562,47.503286684046664],[8.36402893066406,47.48078455918],[8.371238708496094,47.481016589036074],[8.373985290527344,47.47011007802331],[8.368148803710938,47.46825342516445],[8.387031555175781,47.44852243794931],[8.380851745605469,47.447593738482304],[8.384284973144531,47.4355191531953],[8.376388549804688,47.431803338643334],[8.377761840820312,47.42808726171425],[8.389434814453125,47.42739046807988],[8.391494750976562,47.41902822496511],[8.380165100097656,47.40462347023052],[8.364715576171875,47.4016026187529],[8.367118835449219,47.39881398671558],[8.380851745605469,47.39788440990287],[8.39424133300781,47.39439835079049],[8.399734497070312,47.372314620566925],[8.40728759765625,47.37068703239024],[8.404197692871094,47.34417352612498],[8.416213989257812,47.33416935720614],[8.414497375488281,47.32602502961836],[8.452606201171875,47.33254059215931],[8.444023132324219,47.31927592106609],[8.427543640136719,47.29925625338924],[8.390121459960938,47.28854494625744],[8.41175079345703,47.247076403108416],[8.393898010253906,47.227728840642065],[8.404884338378906,47.194845099780174],[8.401451110839844,47.17757880776958],[8.409690856933594,47.17314466448546],[8.412437438964844,47.13976002139446],[8.379478454589844,47.13929295458033],[8.361968994140625,47.14559801038333],[8.342742919921875,47.177112073280966],[8.3056640625,47.24987305653909],[8.295021057128906,47.26268916206698],[8.300514221191406,47.26991141830738],[8.278884887695312,47.28225686421767],[8.259315490722656,47.285983225286174],[8.243522644042969,47.280859411143915],[8.240432739257812,47.27130916053537],[8.228759765625,47.27270686584952],[8.219146728515625,47.25336866567523],[8.204727172851562,47.245444953748034],[8.203353881835938,47.22679624955806],[8.180007934570312,47.22143353240336],[8.171768188476562,47.2279619858493],[8.155975341796875,47.23961793870555],[8.175888061523436,47.24218190428504],[8.17657470703125,47.25406775981567],[8.136062622070312,47.24730946320093],[8.12164306640625,47.24218190428504],[8.10791015625,47.2447457457832],[8.097267150878906,47.259427174956194],[8.077354431152344,47.2603591917818],[8.059844970703125,47.25569894358661],[8.062591552734375,47.24614415248379],[8.016586303710938,47.242881146090085],[8.015899658203125,47.258961160390896],[7.997016906738281,47.2796948387185],[7.951698303222655,47.274337475394645],[7.960968017578125,47.25430078914495],[7.933845520019531,47.237053849043896],[7.911529541015624,47.24381345414034],[7.859344482421875,47.23425651880584],[7.83977508544922,47.23425651880584],[7.826042175292968,47.24427960201268],[7.828102111816407,47.25966018070071],[7.82398223876953,47.26548499105541],[7.8408050537109375,47.273405704663965],[7.848701477050781,47.28551744450745],[7.860374450683594,47.30461109337307],[7.871704101562499,47.31136207506936],[7.8888702392578125,47.31136207506936],[7.897453308105469,47.31904317780638],[7.895393371582031,47.327653995607086],[7.908439636230469,47.340451266106996],[7.9259490966796875,47.332773275955894],[7.94757843017578,47.331609846720866],[7.94757843017578,47.316715688820764],[8.007316589355467,47.33905535093827],[8.004913330078125,47.34533667855891],[8.011093139648438,47.35719936945847],[8.024139404296875,47.36719917429931],[8.032722473144531,47.38393878966209],[8.026885986328125,47.39602520707679],[8.010749816894531,47.3955603961201],[8.004570007324219,47.40671472747142],[7.975730895996094,47.41507892620099],[7.9657745361328125,47.42181578692778],[7.985343933105469,47.425764580393924],[7.971954345703124,47.46105827584221],[7.957534790039062,47.457344265054225],[7.940711975097656,47.46221885041022],[7.946891784667968,47.48403288391224],[7.907066345214844,47.48588897929538],[7.8936767578125,47.50653361720931],[7.873420715332031,47.51325876844644],[7.875480651855468,47.52253342509336],[7.865180969238281,47.51975120023913],[7.856254577636718,47.533660849056794],[7.833251953125,47.5325018525392],[7.834281921386719,47.51465007145751],[7.789649963378906,47.49377665301097],[7.789649963378906,47.518128167602484],[7.7515411376953125,47.52461999690649],[7.731285095214843,47.53203824675999],[7.708969116210937,47.54015075619555],[7.740898132324219,47.54362716173679],[7.761497497558593,47.54895720250044],[7.781410217285156,47.55289644950155],[7.797546386718749,47.55915229204993],[7.805442810058593,47.56563904359584],[7.814369201660155,47.575136052077276],[7.819175720214843,47.58648387645128],[7.8325653076171875,47.586715439092906],[7.843208312988281,47.581620824334166],[7.859344482421875,47.58602074809481],[7.8847503662109375,47.58764167941513],[7.903633117675781,47.58092606572345],[7.911872863769532,47.56749225365282],[7.90740966796875,47.55776216936179],[7.917709350585938,47.545712894408624],[7.929382324218749,47.54640812019053],[7.941741943359374,47.54432241518175],[7.9520416259765625,47.54965238525127],[7.9561614990234375,47.55683540041267],[7.9767608642578125,47.55544521625339],[7.997360229492187,47.556603705614094],[8.019676208496094,47.54965238525127],[8.049888610839844,47.55637200979099],[8.058815002441406,47.56285910557121],[8.072891235351562,47.56355410390809],[8.086967468261719,47.557067094186735],[8.100700378417969,47.56216409801383],[8.105506896972656,47.57976811421671],[8.113059997558594,47.583473468887405],[8.133659362792969,47.58301031389572],[8.138809204101562,47.59042030203756],[8.15185546875,47.59551406038282],[8.166275024414062,47.5941249027327],[8.177261352539062,47.6017648134425],[8.193740844726562,47.616346999837226],[8.2012939453125,47.62120682516921],[8.219490051269531,47.61958693358351],[8.223953247070312,47.61102381568743],[8.222923278808594,47.604774168947614]]],"terms_text":"AGIS OF2014"},{"id":"Aargau-AGIS-2016","name":"Kanton Aargau 25cm (AGIS 2016)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/AGIS2016/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,20],"polygon":[[[8.222923278808594,47.604774168947614],[8.244209289550781,47.613569753973955],[8.294334411621094,47.60986653003798],[8.300857543945312,47.58625231278527],[8.329353332519531,47.569808674020344],[8.382568359375,47.56702895728551],[8.398017883300781,47.57490443821351],[8.424797058105469,47.56795554592218],[8.415184020996094,47.54663986006874],[8.389778137207031,47.5262428287156],[8.372268676757812,47.51233121261258],[8.358535766601562,47.503286684046664],[8.36402893066406,47.48078455918],[8.371238708496094,47.481016589036074],[8.373985290527344,47.47011007802331],[8.368148803710938,47.46825342516445],[8.387031555175781,47.44852243794931],[8.380851745605469,47.447593738482304],[8.384284973144531,47.4355191531953],[8.376388549804688,47.431803338643334],[8.377761840820312,47.42808726171425],[8.389434814453125,47.42739046807988],[8.391494750976562,47.41902822496511],[8.380165100097656,47.40462347023052],[8.364715576171875,47.4016026187529],[8.367118835449219,47.39881398671558],[8.380851745605469,47.39788440990287],[8.39424133300781,47.39439835079049],[8.399734497070312,47.372314620566925],[8.40728759765625,47.37068703239024],[8.404197692871094,47.34417352612498],[8.416213989257812,47.33416935720614],[8.414497375488281,47.32602502961836],[8.452606201171875,47.33254059215931],[8.444023132324219,47.31927592106609],[8.427543640136719,47.29925625338924],[8.390121459960938,47.28854494625744],[8.41175079345703,47.247076403108416],[8.393898010253906,47.227728840642065],[8.404884338378906,47.194845099780174],[8.401451110839844,47.17757880776958],[8.409690856933594,47.17314466448546],[8.412437438964844,47.13976002139446],[8.379478454589844,47.13929295458033],[8.361968994140625,47.14559801038333],[8.342742919921875,47.177112073280966],[8.3056640625,47.24987305653909],[8.295021057128906,47.26268916206698],[8.300514221191406,47.26991141830738],[8.278884887695312,47.28225686421767],[8.259315490722656,47.285983225286174],[8.243522644042969,47.280859411143915],[8.240432739257812,47.27130916053537],[8.228759765625,47.27270686584952],[8.219146728515625,47.25336866567523],[8.204727172851562,47.245444953748034],[8.203353881835938,47.22679624955806],[8.180007934570312,47.22143353240336],[8.171768188476562,47.2279619858493],[8.155975341796875,47.23961793870555],[8.175888061523436,47.24218190428504],[8.17657470703125,47.25406775981567],[8.136062622070312,47.24730946320093],[8.12164306640625,47.24218190428504],[8.10791015625,47.2447457457832],[8.097267150878906,47.259427174956194],[8.077354431152344,47.2603591917818],[8.059844970703125,47.25569894358661],[8.062591552734375,47.24614415248379],[8.016586303710938,47.242881146090085],[8.015899658203125,47.258961160390896],[7.997016906738281,47.2796948387185],[7.951698303222655,47.274337475394645],[7.960968017578125,47.25430078914495],[7.933845520019531,47.237053849043896],[7.911529541015624,47.24381345414034],[7.859344482421875,47.23425651880584],[7.83977508544922,47.23425651880584],[7.826042175292968,47.24427960201268],[7.828102111816407,47.25966018070071],[7.82398223876953,47.26548499105541],[7.8408050537109375,47.273405704663965],[7.848701477050781,47.28551744450745],[7.860374450683594,47.30461109337307],[7.871704101562499,47.31136207506936],[7.8888702392578125,47.31136207506936],[7.897453308105469,47.31904317780638],[7.895393371582031,47.327653995607086],[7.908439636230469,47.340451266106996],[7.9259490966796875,47.332773275955894],[7.94757843017578,47.331609846720866],[7.94757843017578,47.316715688820764],[8.007316589355467,47.33905535093827],[8.004913330078125,47.34533667855891],[8.011093139648438,47.35719936945847],[8.024139404296875,47.36719917429931],[8.032722473144531,47.38393878966209],[8.026885986328125,47.39602520707679],[8.010749816894531,47.3955603961201],[8.004570007324219,47.40671472747142],[7.975730895996094,47.41507892620099],[7.9657745361328125,47.42181578692778],[7.985343933105469,47.425764580393924],[7.971954345703124,47.46105827584221],[7.957534790039062,47.457344265054225],[7.940711975097656,47.46221885041022],[7.946891784667968,47.48403288391224],[7.907066345214844,47.48588897929538],[7.8936767578125,47.50653361720931],[7.873420715332031,47.51325876844644],[7.875480651855468,47.52253342509336],[7.865180969238281,47.51975120023913],[7.856254577636718,47.533660849056794],[7.833251953125,47.5325018525392],[7.834281921386719,47.51465007145751],[7.789649963378906,47.49377665301097],[7.789649963378906,47.518128167602484],[7.7515411376953125,47.52461999690649],[7.731285095214843,47.53203824675999],[7.708969116210937,47.54015075619555],[7.740898132324219,47.54362716173679],[7.761497497558593,47.54895720250044],[7.781410217285156,47.55289644950155],[7.797546386718749,47.55915229204993],[7.805442810058593,47.56563904359584],[7.814369201660155,47.575136052077276],[7.819175720214843,47.58648387645128],[7.8325653076171875,47.586715439092906],[7.843208312988281,47.581620824334166],[7.859344482421875,47.58602074809481],[7.8847503662109375,47.58764167941513],[7.903633117675781,47.58092606572345],[7.911872863769532,47.56749225365282],[7.90740966796875,47.55776216936179],[7.917709350585938,47.545712894408624],[7.929382324218749,47.54640812019053],[7.941741943359374,47.54432241518175],[7.9520416259765625,47.54965238525127],[7.9561614990234375,47.55683540041267],[7.9767608642578125,47.55544521625339],[7.997360229492187,47.556603705614094],[8.019676208496094,47.54965238525127],[8.049888610839844,47.55637200979099],[8.058815002441406,47.56285910557121],[8.072891235351562,47.56355410390809],[8.086967468261719,47.557067094186735],[8.100700378417969,47.56216409801383],[8.105506896972656,47.57976811421671],[8.113059997558594,47.583473468887405],[8.133659362792969,47.58301031389572],[8.138809204101562,47.59042030203756],[8.15185546875,47.59551406038282],[8.166275024414062,47.5941249027327],[8.177261352539062,47.6017648134425],[8.193740844726562,47.616346999837226],[8.2012939453125,47.62120682516921],[8.219490051269531,47.61958693358351],[8.223953247070312,47.61102381568743],[8.222923278808594,47.604774168947614]]],"terms_text":"AGIS OF2016","best":true},{"id":"Basel-Landschaft-2015","name":"Kanton Basel-Landschaft 10cm (2015)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/KTBASELLANDSCHAFT2015/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[18,21],"polygon":[[[7.370281219482422,47.413684985326796],[7.357578277587891,47.41507892620101],[7.357921600341797,47.41827323486739],[7.353544235229492,47.4196089792119],[7.344875335693359,47.42402250214274],[7.339725494384765,47.42971307765559],[7.332687377929687,47.430235650685475],[7.32685089111328,47.4319194618196],[7.325280543317693,47.43489176778178],[7.33050406703179,47.44175856152086],[7.338990092194756,47.44109169292469],[7.344964876980962,47.43607806019703],[7.352656881264292,47.43435807026775],[7.38119797480828,47.432081698142134],[7.375988960266113,47.414309359238985],[7.378145456314087,47.41399717320828],[7.382040023803711,47.41330745332341],[7.388391494750976,47.41397539271845],[7.413708184603623,47.410929293287566],[7.420743520414262,47.411098781635985],[7.427483310496426,47.41448047082256],[7.438105529405026,47.412739349590474],[7.448396898794484,47.41507114537187],[7.455576414208223,47.42792319548619],[7.45061852232364,47.43534476535272],[7.437842682352891,47.446323188615104],[7.425422575234655,47.443283894442736],[7.420904049355535,47.44594415975335],[7.422417620777747,47.45071647996838],[7.428795928789581,47.45387944195848],[7.430028776685507,47.459491697398036],[7.445765194338128,47.46197276972992],[7.44717015944249,47.456958090215814],[7.456512189239691,47.44925575541638],[7.492356675875099,47.458972279610066],[7.530679075390223,47.46118857622267],[7.527445320030451,47.473906165741866],[7.536326693749955,47.48383279861684],[7.536231113003725,47.49105266753894],[7.532603895549507,47.490968962664795],[7.531789123586811,47.49739885661967],[7.520038351186771,47.49678264400428],[7.512226152318425,47.49891674929323],[7.509348758631863,47.508884893812876],[7.499082452238831,47.51627805213703],[7.497870355425969,47.52124757864722],[7.502278119030558,47.514906577969604],[7.517459288006065,47.51728104695845],[7.522200236749534,47.514091442409054],[7.530955756497733,47.52904526885427],[7.519353655277215,47.53471778813415],[7.510751927105658,47.528989768842564],[7.50229842095598,47.52840455858729],[7.4980383403841,47.536152181750076],[7.505454651706732,47.54438188661593],[7.516758242758337,47.545408295649786],[7.527317399933993,47.552778846515565],[7.554658254426867,47.564368052237306],[7.5645783501094,47.55703599040843],[7.561243624111692,47.55172275211291],[7.558752685660356,47.55235329499035],[7.555882119169953,47.54433555917895],[7.564785321950861,47.54568625396918],[7.587263056821628,47.54190064304111],[7.582688476068778,47.53246814131337],[7.589482524394103,47.5279230654027],[7.590248428005343,47.51978966346127],[7.594781326929009,47.51929395578897],[7.613780785019665,47.53925099543145],[7.622303281783164,47.53977428916004],[7.622854488041502,47.550040256825795],[7.617740918118178,47.554366555487356],[7.617617220103555,47.558648485827725],[7.632727781497729,47.5614887674157],[7.639973682410965,47.55816478484801],[7.648995462809379,47.548295861439875],[7.661308760240334,47.544832242956765],[7.665860164458853,47.53745814872834],[7.674674254363578,47.5337535789565],[7.694938989531916,47.532496041115465],[7.71346844906592,47.53978344629896],[7.715956243413761,47.53582195507857],[7.723622825374551,47.536754165368905],[7.727157067196862,47.53293048764033],[7.733221863174538,47.53275465944404],[7.737974130690588,47.52732498381306],[7.749022330706917,47.5249849998809],[7.757861753102653,47.52605097450287],[7.787633628417415,47.52011695778467],[7.790143521321244,47.51864117486466],[7.788870069574476,47.50682929074843],[7.792799480290271,47.500684271209245],[7.786625359342518,47.49312139201968],[7.798890147748131,47.49565149600841],[7.798162871694108,47.49939947973339],[7.799400121334925,47.497477088945935],[7.807418124234862,47.4971384859743],[7.814709929059118,47.504801278976316],[7.831976267472122,47.51473657456054],[7.833207588232065,47.53382387257594],[7.846527268275818,47.53266095290337],[7.852330295179702,47.53523506225097],[7.862569292788096,47.52692027402488],[7.86395674074442,47.519309183202445],[7.876658649367283,47.52269034821798],[7.87567113137545,47.51319304945735],[7.893993798731052,47.50605656803392],[7.904769180395594,47.49217505264052],[7.904821911502771,47.48490926161113],[7.93328835504665,47.48140776210853],[7.947015241408695,47.48488995686335],[7.940027875634228,47.462021295570224],[7.948854362289874,47.46377967418039],[7.957614193951437,47.45880646812721],[7.957849013566705,47.451279351685564],[7.946784554043733,47.44319336966537],[7.950032053627354,47.431716361052416],[7.96183169437885,47.421834282667845],[7.956570351591289,47.41968057428149],[7.955037646053525,47.415605646331336],[7.948388855309641,47.4162657867356],[7.934927870271696,47.41176694218953],[7.936722434714782,47.408057452805856],[7.932661510641391,47.40527495151619],[7.909737672400531,47.398520997340924],[7.890221593189976,47.407141074214024],[7.883331964118422,47.40609724771633],[7.883443085719068,47.4012049891245],[7.877702761222016,47.401257097623],[7.869136696167237,47.3955142728722],[7.879434713089799,47.38799354849815],[7.878812180597903,47.38351047538804],[7.862650230995195,47.38198499163919],[7.840119046365023,47.374763282921705],[7.830547227518145,47.36512144155488],[7.80216648325237,47.36109584064414],[7.796366151294341,47.3534705803715],[7.793560892325092,47.33905227137494],[7.78528803737905,47.3378822997136],[7.768963133383802,47.33891408469915],[7.766419194330703,47.342734660857005],[7.751518928544542,47.3443274446774],[7.734153146629586,47.35776074638933],[7.727913718160677,47.36885889855421],[7.701953574259492,47.37244716296033],[7.644203220263186,47.36720838530677],[7.641761060331779,47.38046937860509],[7.635580022356337,47.38059279713257],[7.633316986492583,47.38291397270416],[7.633305398225418,47.38533959871929],[7.637251158279386,47.38606854199808],[7.63272275093214,47.41003108104519],[7.664054730400831,47.41001995588381],[7.679802017668389,47.41751395224505],[7.686578998003315,47.43366406703297],[7.682972441800632,47.43872228466388],[7.684853783500164,47.447843589969715],[7.692273418589347,47.45421309996921],[7.698831030331891,47.45585888435835],[7.699930658071183,47.46190517358485],[7.709877972706822,47.469384739707586],[7.699760966314013,47.48063247960835],[7.668326578902932,47.48634665620256],[7.666120855554305,47.49686816039971],[7.65217109717027,47.49581439933043],[7.648646287658441,47.49183004211102],[7.655389581170213,47.49020559719241],[7.650513795302598,47.48826095607083],[7.655925875394832,47.48739459757455],[7.644422678687097,47.485637798180356],[7.640965961473804,47.482734093980326],[7.607299799570857,47.48939839412024],[7.608850381582776,47.48352506892989],[7.605631268762133,47.47935909729055],[7.608148977008936,47.475213682276376],[7.604494899927722,47.47044546774548],[7.618872436050056,47.4674530520825],[7.626072253389216,47.462913883669614],[7.62217338539308,47.46195224188912],[7.616464591762502,47.445234574416695],[7.615798850305441,47.432747890966844],[7.592069133423196,47.43271179535717],[7.581206884670679,47.42878068945942],[7.578423275099778,47.434906655087865],[7.568904367023134,47.43689695884281],[7.56829539909203,47.42233486107083],[7.58074128785892,47.414703988151935],[7.525235194936931,47.41163289737562],[7.531172340312734,47.40352507464003],[7.518616677418122,47.38822295597742],[7.511295677347134,47.38974369796625],[7.502255661148456,47.384806980223004],[7.492327480628366,47.385231761698726],[7.478410241257615,47.39055778320416],[7.47746817801916,47.401277162725364],[7.464484018734026,47.40251498235377],[7.460919593518167,47.40068414452088],[7.450020783333588,47.40392739156406],[7.44951323519806,47.39975827367453],[7.443401098004909,47.40231427489849],[7.441311347159463,47.40017886074712],[7.443566657511773,47.38890284041263],[7.437324174770898,47.3808884773088],[7.411692544769116,47.38057235919037],[7.416276198506335,47.384788794341716],[7.414494030814171,47.39429988358522],[7.398935569419335,47.39683906243558],[7.395920463999715,47.40338304393273],[7.388693876865087,47.403019088497395],[7.384054886906365,47.4123601395877],[7.379679679870605,47.4128137535428],[7.375844120979309,47.41401169352981],[7.370281219482422,47.413684985326796]]],"terms_url":"http://www.geo.bl.ch/fileadmin/user_upload/Geodaten/Nutzungsbedingungen_GBD_BL_V3p1.pdf","terms_text":"Geodaten des Kantons Basel-Landschaft 2015","best":true},{"id":"KTBASELSTADT2015","name":"Kanton Basel-Stadt 2015","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/KTBASELSTADT2015/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,21],"polygon":[[[7.492,47.4817],[7.492,47.6342],[7.784,47.6342],[7.784,47.4817],[7.492,47.4817]]],"terms_text":"Kanton Basel-Stadt OF 2015"},{"id":"Solothurn-sogis2014-tms","name":"Kanton Solothurn 25cm (SOGIS 2014-2015)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/sogis2014/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[15,19],"polygon":[[[7.3404127,47.2175697],[7.4154818,47.2402115],[7.4173645,47.2537956],[7.4658424,47.2646513],[7.4946766,47.2882287],[7.5328638,47.294534],[7.5483333,47.3163566],[7.5709479,47.3263111],[7.5604584,47.342492],[7.5388991,47.3476266],[7.5396485,47.3601134],[7.5217459,47.3651488],[7.5237238,47.3720704],[7.4634937,47.3702566],[7.4361035,47.3781317],[7.4434011,47.4023143],[7.4774682,47.4012772],[7.4792364,47.3897076],[7.5022557,47.384807],[7.5213659,47.3912021],[7.5311724,47.4035251],[7.5252352,47.4116329],[7.5807413,47.414704],[7.5682954,47.4223349],[7.5689044,47.436897],[7.5812069,47.4287807],[7.6157989,47.4327479],[7.6260723,47.4629139],[7.6044949,47.4704455],[7.6072998,47.4893984],[7.640966,47.4827341],[7.6559259,47.4873946],[7.6521711,47.4958144],[7.6661209,47.4968682],[7.6683266,47.4863467],[7.699761,47.4806325],[7.709878,47.4693848],[7.6848538,47.4478436],[7.6798021,47.417514],[7.6327228,47.4100311],[7.633317,47.382914],[7.6417611,47.3804694],[7.6442033,47.3672084],[7.7279138,47.3688589],[7.751519,47.3443275],[7.7935609,47.3390523],[7.8021665,47.3610959],[7.8788122,47.3835105],[7.8691367,47.3955143],[7.883332,47.4060973],[7.9097377,47.398521],[7.9550377,47.4156057],[7.9618317,47.4218343],[7.9467846,47.4431934],[7.9682836,47.4628082],[7.9872707,47.4287435],[7.9854653,47.4227641],[7.9827035,47.4283325],[7.9631993,47.4223547],[8.0072617,47.4065858],[8.0100022,47.395418],[8.0265612,47.3956224],[8.0313669,47.3836856],[8.0038366,47.3453146],[8.0051906,47.3367516],[7.9479701,47.3171432],[7.9478307,47.3325169],[7.9192088,47.3339507],[7.9078055,47.341719],[7.889098,47.3114878],[7.8611018,47.3061239],[7.8418057,47.2744707],[7.8166423,47.2616706],[7.8028241,47.2684079],[7.7861469,47.256098],[7.7746009,47.267869],[7.7568187,47.258095],[7.7326672,47.2591133],[7.684769,47.2939919],[7.6482742,47.2819898],[7.5801066,47.2763483],[7.5936981,47.2662199],[7.5959384,47.245569],[7.6261802,47.2263143],[7.6405558,47.2297944],[7.6484666,47.2189525],[7.6472258,47.2017823],[7.6715278,47.1949714],[7.6711002,47.1845216],[7.6779881,47.1819259],[7.6728612,47.1683945],[7.6600808,47.1684026],[7.6451021,47.1489207],[7.6155322,47.1565739],[7.5861404,47.1475453],[7.5810534,47.16013],[7.5634674,47.1683541],[7.5257686,47.162205],[7.5203336,47.1588879],[7.5297508,47.1487369],[7.5097234,47.1255457],[7.4613252,47.1082327],[7.4750945,47.0867101],[7.454461,47.074927],[7.4354156,47.0801664],[7.4340002,47.1005003],[7.3820271,47.0957398],[7.3704914,47.1209312],[7.4401788,47.1237276],[7.4217922,47.1358605],[7.447783,47.1550805],[7.4728074,47.1525609],[7.4970383,47.1700873],[7.4804964,47.171738],[7.4708545,47.181324],[7.4757226,47.1906485],[7.4497638,47.1895691],[7.4476258,47.1810839],[7.4332849,47.1847269],[7.4118135,47.1624212],[7.3842442,47.1601249],[7.3821749,47.1651186],[7.391911,47.1662739],[7.3835137,47.1803011],[7.3654609,47.1944525],[7.3544799,47.1915316],[7.3404127,47.2175697]],[[7.420816,47.4803666],[7.4349836,47.4981011],[7.4707584,47.480734],[7.487277,47.4820136],[7.5116652,47.5026958],[7.5317892,47.4973989],[7.5366964,47.4850517],[7.5274454,47.4739062],[7.5306791,47.4611886],[7.4565122,47.4492558],[7.445214,47.4623781],[7.4557367,47.4733767],[7.420816,47.4803666]],[[7.3759458,47.4140995],[7.3821514,47.4330266],[7.4209041,47.4459442],[7.4378427,47.4463232],[7.4555765,47.4279232],[7.4437574,47.413444],[7.3759458,47.4140995]],[[7.6744234,47.1539707],[7.6853662,47.1662986],[7.7007985,47.1617746],[7.6901531,47.1525567],[7.6744234,47.1539707]]],"terms_text":"Orthofoto WMS Solothurn","best":true},{"id":"KTZUERICH2015","name":"Kanton Zürich 2015  10cm","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/KTZUERICH2015/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,21],"polygon":[[[8.807601928710938,47.66608099332474],[8.808631896972656,47.65475043477393],[8.830604553222656,47.648506014952225],[8.805885314941406,47.597597727711346],[8.749580383300781,47.61565270219988],[8.751983642578125,47.59505101193038],[8.807945251464844,47.585789182379905],[8.811721801757812,47.57467282332527],[8.840904235839844,47.57467282332527],[8.854637145996094,47.56216409801383],[8.8330078125,47.55382328811835],[8.845024108886719,47.53458802782819],[8.899612426757812,47.52786561031842],[8.895835876464844,47.491224888201955],[8.902702331542969,47.48588897929538],[8.887252807617188,47.475911695481756],[8.911285400390625,47.43969913094723],[8.934288024902344,47.43807362350206],[8.935317993164062,47.43017758727173],[8.917121887207031,47.42808726171425],[8.909912109375,47.404855836246135],[8.944587707519531,47.38905261221537],[8.945274353027344,47.379521907289295],[8.963127136230469,47.357664518690434],[8.973083496093748,47.35580389715929],[8.989906311035156,47.31857768821123],[8.973426818847656,47.30367985581531],[8.9593505859375,47.300653220457775],[8.941154479980469,47.2873805430142],[8.950080871582031,47.28458587064588],[8.940467834472656,47.259194168186234],[8.876266479492188,47.24847474828181],[8.876609802246092,47.243114224640834],[8.850173950195312,47.23961793870555],[8.849830627441406,47.247076403108416],[8.825111389160156,47.24824169331652],[8.800048828125,47.24031721435106],[8.804855346679688,47.23425651880584],[8.815155029296875,47.217702626593784],[8.793525695800781,47.21886856286133],[8.71490478515625,47.20021050593422],[8.685722351074219,47.18154588528182],[8.697395324707031,47.163108130899104],[8.660659790039062,47.15633823511178],[8.6572265625,47.16684287656919],[8.618087768554688,47.172444502751944],[8.622550964355469,47.17991241867412],[8.607101440429688,47.201376826785406],[8.595085144042969,47.19834433924206],[8.575859069824219,47.21513747655813],[8.541183471679688,47.2186353776589],[8.471488952636719,47.2053421258966],[8.441619873046875,47.22120035848172],[8.417243957519531,47.22120035848172],[8.383941650390625,47.292270864380086],[8.422050476074219,47.302282968719936],[8.442306518554688,47.32439601339355],[8.413810729980469,47.32299967378833],[8.408660888671875,47.33067908487908],[8.378448486328125,47.39718721653071],[8.360939025878906,47.39695481668995],[8.359222412109375,47.4053205652024],[8.379135131835938,47.40764414848437],[8.377418518066406,47.41624051540972],[8.384284973144531,47.42274494145051],[8.372611999511719,47.42808726171425],[8.372955322265625,47.437376962080776],[8.379478454589844,47.45037978769006],[8.36402893066406,47.46198673754625],[8.352012634277344,47.5079250985124],[8.373985290527344,47.517200697839414],[8.392181396484375,47.5366741201253],[8.417587280273436,47.56610235225701],[8.430290222167967,47.5693453981427],[8.491744995117188,47.581620824334166],[8.487625122070312,47.58648387645128],[8.463935852050781,47.58301031389572],[8.453292846679688,47.60315376826432],[8.479385375976562,47.617504142079596],[8.505821228027344,47.61958693358351],[8.513717651367188,47.635783590864854],[8.542213439941406,47.632776019724375],[8.545646667480469,47.627685889602006],[8.564186096191406,47.6256034207548],[8.566932678222656,47.61935551640258],[8.576202392578125,47.613569753973955],[8.564872741699219,47.60037582174319],[8.535346984863281,47.586715439092906],[8.550109863281248,47.5714301073211],[8.555259704589844,47.55498181333744],[8.581008911132812,47.59551406038282],[8.598861694335936,47.61449551898437],[8.59130859375,47.64642437575518],[8.609848022460938,47.65521295468833],[8.620834350585938,47.646886969413],[8.618431091308594,47.65660048985082],[8.602981567382812,47.666312203609145],[8.610877990722656,47.67856488312544],[8.62323760986328,47.67856488312544],[8.621864318847656,47.69312564683551],[8.64898681640625,47.697516190510555],[8.667526245117188,47.68665469810477],[8.671646118164062,47.67602211074509],[8.692245483398438,47.65197522925437],[8.734817504882812,47.64526787368664],[8.777389526367188,47.65313158281113],[8.785629272460938,47.667930646923494],[8.807601928710938,47.66608099332474]]],"terms_text":"Kanton Zürich OF 2015","best":true},{"id":"kelowna_2012","name":"Kelowna 2012","type":"tms","template":"http://{switch:a,b,c,d}.tile.paulnorman.ca/kelowna2012/{zoom}/{x}/{y}.png","description":"High quality aerial imagery taken for the City of Kelowna","scaleExtent":[9,20],"polygon":[[[-119.5867318,49.7928087],[-119.5465655,49.7928097],[-119.5465661,49.8013837],[-119.5343374,49.8013841],[-119.5343376,49.8047321],[-119.5296211,49.8047322],[-119.5296216,49.8119555],[-119.5104463,49.811956],[-119.5115683,49.8744325],[-119.5108946,49.8744904],[-119.5114111,49.8843312],[-119.5114115,49.9221763],[-119.49386,49.9223477],[-119.4940505,49.9313031],[-119.4803936,49.9317529],[-119.4804572,49.9407474],[-119.4666732,49.9409927],[-119.4692775,49.9913717],[-119.4551337,49.9916078],[-119.4556736,50.0121242],[-119.4416673,50.0123895],[-119.4417308,50.0136345],[-119.4221492,50.0140377],[-119.4221042,50.0119306],[-119.4121303,50.012165],[-119.4126082,50.0216913],[-119.4123387,50.0216913],[-119.4124772,50.0250773],[-119.4120917,50.0250821],[-119.4121954,50.0270769],[-119.4126083,50.0270718],[-119.4128328,50.0321946],[-119.3936313,50.0326418],[-119.393529,50.0307781],[-119.3795727,50.0310116],[-119.3795377,50.0287584],[-119.3735764,50.0288621],[-119.371544,49.9793618],[-119.3573506,49.9793618],[-119.3548353,49.9256081],[-119.3268079,49.9257238],[-119.3256573,49.8804068],[-119.3138893,49.8806528],[-119.3137097,49.8771651],[-119.3132156,49.877223],[-119.3131482,49.8749652],[-119.312452,49.8749073],[-119.3122275,49.87236],[-119.3117558,49.872331],[-119.3115986,49.8696098],[-119.3112169,49.8694217],[-119.3109199,49.8632417],[-119.3103721,49.8632724],[-119.3095139,49.8512388],[-119.3106368,49.8512316],[-119.3103859,49.8462564],[-119.3245344,49.8459957],[-119.3246018,49.8450689],[-119.3367018,49.844875],[-119.3367467,49.8435136],[-119.337937,49.8434702],[-119.3378023,49.8382055],[-119.3383637,49.8381041],[-119.3383749,49.8351202],[-119.3390936,49.8351058],[-119.3388016,49.8321217],[-119.3391497,49.8320565],[-119.3391722,49.8293331],[-119.3394641,49.8293331],[-119.3395879,49.8267878],[-119.3500053,49.8265829],[-119.3493701,49.8180588],[-119.4046964,49.8163785],[-119.4045694,49.8099022],[-119.4101592,49.8099022],[-119.4102862,49.8072787],[-119.4319467,49.8069098],[-119.4322643,49.7907965],[-119.4459847,49.7905504],[-119.445286,49.7820201],[-119.4967376,49.7811587],[-119.4966105,49.7784927],[-119.5418371,49.7775082],[-119.5415892,49.7718277],[-119.5560296,49.7714941],[-119.5561194,49.7718422],[-119.5715704,49.7715086],[-119.5716153,49.7717262],[-119.5819235,49.7714941],[-119.5820133,49.7717697],[-119.5922991,49.7715231],[-119.592344,49.7718132],[-119.6003839,49.7715957],[-119.6011924,49.7839081],[-119.5864365,49.7843863],[-119.5867318,49.7928087]]]},{"id":"kelowna_roads","name":"Kelowna Roads overlay","type":"tms","template":"http://{switch:a,b,c,d}.tile.paulnorman.ca/kelowna_overlay/{zoom}/{x}/{y}.png","scaleExtent":[9,20],"polygon":[[[-119.5867318,49.7928087],[-119.5465655,49.7928097],[-119.5465661,49.8013837],[-119.5343374,49.8013841],[-119.5343376,49.8047321],[-119.5296211,49.8047322],[-119.5296216,49.8119555],[-119.5104463,49.811956],[-119.5115683,49.8744325],[-119.5108946,49.8744904],[-119.5114111,49.8843312],[-119.5114115,49.9221763],[-119.49386,49.9223477],[-119.4940505,49.9313031],[-119.4803936,49.9317529],[-119.4804572,49.9407474],[-119.4666732,49.9409927],[-119.4692775,49.9913717],[-119.4551337,49.9916078],[-119.4556736,50.0121242],[-119.4416673,50.0123895],[-119.4417308,50.0136345],[-119.4221492,50.0140377],[-119.4221042,50.0119306],[-119.4121303,50.012165],[-119.4126082,50.0216913],[-119.4123387,50.0216913],[-119.4124772,50.0250773],[-119.4120917,50.0250821],[-119.4121954,50.0270769],[-119.4126083,50.0270718],[-119.4128328,50.0321946],[-119.3936313,50.0326418],[-119.393529,50.0307781],[-119.3795727,50.0310116],[-119.3795377,50.0287584],[-119.3735764,50.0288621],[-119.371544,49.9793618],[-119.3573506,49.9793618],[-119.3548353,49.9256081],[-119.3268079,49.9257238],[-119.3256573,49.8804068],[-119.3138893,49.8806528],[-119.3137097,49.8771651],[-119.3132156,49.877223],[-119.3131482,49.8749652],[-119.312452,49.8749073],[-119.3122275,49.87236],[-119.3117558,49.872331],[-119.3115986,49.8696098],[-119.3112169,49.8694217],[-119.3109199,49.8632417],[-119.3103721,49.8632724],[-119.3095139,49.8512388],[-119.3106368,49.8512316],[-119.3103859,49.8462564],[-119.3245344,49.8459957],[-119.3246018,49.8450689],[-119.3367018,49.844875],[-119.3367467,49.8435136],[-119.337937,49.8434702],[-119.3378023,49.8382055],[-119.3383637,49.8381041],[-119.3383749,49.8351202],[-119.3390936,49.8351058],[-119.3388016,49.8321217],[-119.3391497,49.8320565],[-119.3391722,49.8293331],[-119.3394641,49.8293331],[-119.3395879,49.8267878],[-119.3500053,49.8265829],[-119.3493701,49.8180588],[-119.4046964,49.8163785],[-119.4045694,49.8099022],[-119.4101592,49.8099022],[-119.4102862,49.8072787],[-119.4319467,49.8069098],[-119.4322643,49.7907965],[-119.4459847,49.7905504],[-119.445286,49.7820201],[-119.4967376,49.7811587],[-119.4966105,49.7784927],[-119.5418371,49.7775082],[-119.5415892,49.7718277],[-119.5560296,49.7714941],[-119.5561194,49.7718422],[-119.5715704,49.7715086],[-119.5716153,49.7717262],[-119.5819235,49.7714941],[-119.5820133,49.7717697],[-119.5922991,49.7715231],[-119.592344,49.7718132],[-119.6003839,49.7715957],[-119.6011924,49.7839081],[-119.5864365,49.7843863],[-119.5867318,49.7928087]]],"overlay":true},{"id":"landsat_233055","name":"Landsat 233055","type":"tms","template":"http://{switch:a,b,c,d}.tile.paulnorman.ca/landsat_233055/{zoom}/{x}/{y}.png","description":"Recent Landsat imagery","scaleExtent":[5,14],"polygon":[[[-60.8550011,6.1765004],[-60.4762612,7.9188291],[-62.161689,8.2778675],[-62.5322549,6.5375488],[-60.8550011,6.1765004]]]},{"id":"landsat_047026","name":"Latest southwest British Columbia Landsat","type":"tms","template":"http://{switch:a,b,c,d}.tile.paulnorman.ca/landsat_047026/{zoom}/{x}/{y}.png","description":"Recent lower-resolution landsat imagery for southwest British Columbia","scaleExtent":[5,13],"polygon":[[[-121.9355512,47.7820648],[-121.5720582,48.6410125],[-121.2015461,49.4846247],[-121.8375516,49.6023246],[-122.4767046,49.7161735],[-123.118912,49.8268824],[-123.760228,49.9335836],[-124.0887706,49.0870469],[-124.4128889,48.2252567],[-123.792772,48.1197334],[-123.1727942,48.0109592],[-122.553553,47.8982299],[-121.9355512,47.7820648]]]},{"id":"ORT10LT","name":"Lithuania - NŽT ORT10LT","type":"tms","template":"http://mapproxy.openmap.lt/ort10lt/g/{zoom}/{x}/{y}.jpeg","scaleExtent":[4,18],"polygon":[[[26.2138385,55.850748],[26.3858298,55.7045315],[26.6303618,55.6806692],[26.6205349,55.5689227],[26.5242191,55.5099228],[26.5541476,55.388833],[26.4399286,55.3479351],[26.7919694,55.3212027],[26.8291304,55.2763488],[26.7434625,55.2539863],[26.6764846,55.158828],[26.4611191,55.1285624],[26.3577434,55.1505399],[26.2296342,55.1073177],[26.2713814,55.0775905],[26.2085126,54.997414],[26.0619117,54.9416094],[25.8578176,54.9276001],[25.7429827,54.8150641],[25.7626083,54.5769013],[25.5319352,54.3418175],[25.6771618,54.3238109],[25.7857293,54.2336242],[25.7858844,54.1550594],[25.5550843,54.1461918],[25.5109462,54.1750267],[25.5896725,54.2285838],[25.5136246,54.3078472],[25.2689287,54.2744706],[25.0705963,54.1336282],[24.9573726,54.1720575],[24.8133801,54.144862],[24.7790172,54.0999054],[24.8712786,54.034904],[24.819568,53.9977218],[24.6845912,53.9621091],[24.697865,54.0171421],[24.6259068,54.0105048],[24.4342619,53.9014424],[24.3520594,53.8967893],[24.2016059,53.9700069],[23.9683341,53.9266977],[23.9130177,53.9696842],[23.7781192,53.8989169],[23.7097655,53.9394502],[23.5370435,53.9430702],[23.4822428,53.9893848],[23.5273356,54.0473482],[23.4858579,54.1532339],[23.3867851,54.224838],[23.0421216,54.3159745],[23.0102115,54.3827959],[22.8546899,54.4104029],[22.7919963,54.3633227],[22.7023421,54.4528985],[22.6838586,54.585972],[22.7489713,54.6319792],[22.7429727,54.7268221],[22.8866837,54.8135001],[22.8204005,54.9119829],[22.6424041,54.9713362],[22.5892361,55.070243],[22.080597,55.0244812],[22.0324081,55.084098],[21.9130671,55.0816838],[21.6491949,55.1808113],[21.5015124,55.1868198],[21.3843708,55.2936996],[21.2709829,55.2450059],[21.0983616,55.2563884],[20.9421741,55.282453],[21.0863466,55.5618266],[21.0399547,55.8363584],[21.0640261,56.0699542],[21.2047804,56.0811668],[21.2307958,56.1623302],[21.5021038,56.2954952],[21.7235874,56.3138211],[21.8356623,56.37162],[21.9695397,56.3766515],[22.0153001,56.4242811],[22.4372717,56.406405],[22.6800028,56.3515884],[22.9191739,56.3790184],[22.9466759,56.4146477],[23.0932498,56.3046383],[23.1703443,56.3667721],[23.3064522,56.3830535],[23.5571715,56.3338187],[23.7647953,56.3733238],[23.7666897,56.3238079],[24.0189971,56.3297615],[24.1214631,56.2488984],[24.2857421,56.3006367],[24.4541496,56.2581579],[24.5794651,56.2882389],[24.6284061,56.3753322],[24.9023767,56.4805317],[25.1277405,56.2059091],[25.5771398,56.182414],[25.6731232,56.1493667],[26.2138385,55.850748]]],"terms_url":"http://www.geoportal.lt","terms_text":"NŽT ORT10LT","best":true},{"id":"mapbox_locator_overlay","name":"Locator Overlay","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/openstreetmap.map-inh76ba2/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJncjlmd0t3In0.DmZsIeOW-3x-C5eX-wAqTw","description":"Shows major features to help orient you.","scaleExtent":[0,16],"overzoom":false,"terms_url":"http://www.mapbox.com/about/maps/","terms_text":"Terms & Feedback","default":true,"overlay":true},{"id":"londrina2011","name":"Londrina Ortofoto 2011","type":"tms","template":"https://siglon.londrina.pr.gov.br/arcgis/rest/services/Imagens/Ortofotos_2011_Paranacidade/MapServer/WMTS/tile/1.0.0/Imagens_Ortofotos_2011_Paranacidade/default/GoogleMapsCompatible/{zoom}/{y}/{x}","polygon":[[[-51.10903142008701,-23.392750890870328],[-51.110147219037096,-23.39111628244602],[-51.111981850003126,-23.389599820448623],[-51.11358044657587,-23.38976722295012],[-51.120999436701226,-23.38592675938185],[-51.12224934611127,-23.385109415587607],[-51.12483499560139,-23.383504255873166],[-51.12538216624037,-23.38186953335707],[-51.12482426676533,-23.37770385409619],[-51.12445948633935,-23.375054689723584],[-51.124373655650885,-23.372297138974446],[-51.12244246516032,-23.37032742475139],[-51.12302182230749,-23.366427304263887],[-51.128557901713755,-23.36548180323493],[-51.12832186732048,-23.358843408308623],[-51.12477062258506,-23.35475580404945],[-51.12703440699343,-23.35091432623551],[-51.12411616358548,-23.34679692655685],[-51.12025378260435,-23.347811512977742],[-51.1176466754421,-23.33969460448754],[-51.11264703783877,-23.341290443649072],[-51.109396200513004,-23.33488726938344],[-51.10756156954697,-23.334089313725826],[-51.10485790286019,-23.333980949007543],[-51.10252974543546,-23.334187827029368],[-51.09986899409291,-23.331015661953632],[-51.09801290545476,-23.329360589233605],[-51.09998701128955,-23.32830645478855],[-51.10322711977927,-23.325321337105603],[-51.10472915682748,-23.323193291476684],[-51.104664783811145,-23.321291814470847],[-51.10514758143378,-23.318444474199904],[-51.1063599399084,-23.3157547161216],[-51.10660670313775,-23.31467091543279],[-51.11050127062705,-23.311665785493048],[-51.111584883068964,-23.30842411016493],[-51.099504213666904,-23.309468549142686],[-51.09740136179941,-23.308631027972474],[-51.09511611971892,-23.307448636164267],[-51.09201548609798,-23.3049360186679],[-51.09036324534495,-23.3037141796735],[-51.09204767260616,-23.29874787986134],[-51.09269140276969,-23.297496421894902],[-51.09407542262125,-23.292953629109174],[-51.10073802981369,-23.293318240761657],[-51.10101697955121,-23.28870632248831],[-51.10068438563339,-23.28837126237015],[-51.10084531817427,-23.28777997775132],[-51.09937546763423,-23.28663682004102],[-51.09631774935752,-23.277914991984613],[-51.10285161051725,-23.273016720553397],[-51.10835550341534,-23.27033590016574],[-51.11309764895328,-23.268404099092194],[-51.13160489115448,-23.265338785827712],[-51.13188384089201,-23.262007272160396],[-51.1317336371872,-23.255058136908826],[-51.13290308031759,-23.254683563301587],[-51.132956724497895,-23.250750476893938],[-51.13473771128364,-23.2512729236245],[-51.13533852610292,-23.25133206840842],[-51.13516686472599,-23.24359373640034],[-51.13534925493897,-23.24117849627157],[-51.137516479822814,-23.24219388826517],[-51.13884685549409,-23.243495156026544],[-51.14108918223035,-23.24521044413634],[-51.1471724322756,-23.243179698340864],[-51.14761231455401,-23.23828015040167],[-51.149082165094036,-23.235884531292832],[-51.14976881060179,-23.236811236789336],[-51.15138886484666,-23.23853646924079],[-51.15289090189487,-23.238842079520833],[-51.15383503946804,-23.238950521710013],[-51.15820167574391,-23.238142132361276],[-51.16045473131624,-23.238161849232945],[-51.160347442955654,-23.24658068718069],[-51.15912435564498,-23.2478326235554],[-51.16131303820094,-23.247773477219496],[-51.166591625541805,-23.245939927797],[-51.17193458589902,-23.245821633420345],[-51.17205260309565,-23.249557713480034],[-51.174241285651625,-23.248404370116877],[-51.17514250788055,-23.2493211310392],[-51.176859121649926,-23.248157927934038],[-51.179466228812196,-23.251686936561047],[-51.18135450395853,-23.253806268366073],[-51.18273852381009,-23.253628837227893],[-51.18378994974384,-23.253264116924615],[-51.18495939287424,-23.253303546194683],[-51.18626831087339,-23.252150235227905],[-51.18665454897149,-23.247477745146526],[-51.191182117788244,-23.249143693933142],[-51.19141815218154,-23.252859966234126],[-51.19369266542598,-23.252781107419985],[-51.1938428691308,-23.26073575534214],[-51.20096681627374,-23.26054847664639],[-51.20126722368338,-23.24259807127726],[-51.209936123218775,-23.242775517090898],[-51.21090171846407,-23.26988252079656],[-51.21968863519614,-23.27221839365197],[-51.225965004290465,-23.2745345140599],[-51.22934458764894,-23.27860487489667],[-51.234515886629225,-23.28160089636689],[-51.23497722657975,-23.283246708422755],[-51.235073786104266,-23.285444377831148],[-51.23371122392482,-23.285897704227196],[-51.232155542696304,-23.28801649191402],[-51.22870085748543,-23.292293383844925],[-51.227402668322334,-23.294599300809004],[-51.22679112466699,-23.295476327114592],[-51.225600223864475,-23.29657013833941],[-51.22392652543933,-23.297210654251764],[-51.220482569064515,-23.30072850975029],[-51.21863720926242,-23.301300029310937],[-51.21668456109974,-23.30211788923888],[-51.21423838647836,-23.30441378240661],[-51.210966091480465,-23.306965823153238],[-51.22328279527583,-23.318296686707587],[-51.224387865389886,-23.31459209321986],[-51.22521398576639,-23.312887551432937],[-51.22511742624187,-23.312582111000477],[-51.22521398576639,-23.312513140483127],[-51.2255251220121,-23.312532846348883],[-51.22595427545445,-23.312385052284572],[-51.22616885217561,-23.31183328632629],[-51.22935531648505,-23.314887676277397],[-51.22802494081377,-23.31661189768144],[-51.227885465945,-23.31901591762422],[-51.22767088922384,-23.320227763653186],[-51.22723100694544,-23.321508564518947],[-51.2273919394863,-23.322227778055023],[-51.22725246461755,-23.322848466059934],[-51.230331640566384,-23.325577488448165],[-51.23046038659909,-23.326710459617892],[-51.229537706698046,-23.32789268010374],[-51.229162197436,-23.330503379743732],[-51.229290943468705,-23.33178408156439],[-51.22681258233914,-23.334473515196468],[-51.2260186484708,-23.336571826694826],[-51.22473118814376,-23.33839427691611],[-51.22210262330938,-23.340226553005806],[-51.22257469209598,-23.34196029634743],[-51.22380850824271,-23.343388647432523],[-51.22384069475089,-23.345309509145306],[-51.22440932306201,-23.347003784611864],[-51.2245380690947,-23.348294177581966],[-51.22404454263601,-23.34968305981433],[-51.22350810083308,-23.35010661675208],[-51.22381923707877,-23.35076657486812],[-51.22304676088255,-23.35174173085325],[-51.22259614976809,-23.35296312824164],[-51.22586844476598,-23.35480505304304],[-51.22650144609346,-23.36705763453823],[-51.22354028734128,-23.369145582171885],[-51.22366903337377,-23.37968330666716],[-51.220375280703756,-23.381633186264455],[-51.216469984378406,-23.38170212087667],[-51.21416328462579,-23.379949201028825],[-51.2092816642191,-23.37395167630701],[-51.20738266023672,-23.368141007697016],[-51.20628831895872,-23.36723491438801],[-51.20472190889416,-23.366269721227162],[-51.198230963078665,-23.366683376299132],[-51.19297383340994,-23.366506095711998],[-51.18986247095292,-23.3654424072124],[-51.18806002649507,-23.36464463523902],[-51.18718026193825,-23.3645264463904],[-51.18579624208668,-23.363738518041337],[-51.183038931219606,-23.36359078095478],[-51.18071077379488,-23.3637582163071],[-51.179069261877906,-23.361581540240305],[-51.177642326682125,-23.35836078207346],[-51.16683838877106,-23.356262814974126],[-51.166141014427254,-23.358538073547532],[-51.16475699457568,-23.360389770338585],[-51.16076586756186,-23.359217688669915],[-51.15983245882475,-23.36660458495632],[-51.162042599052846,-23.36861374957437],[-51.16276143106877,-23.374158492021696],[-51.158448438973174,-23.37580315788644],[-51.155047397942575,-23.376305417047273],[-51.15396378550066,-23.37903334042617],[-51.15298746141932,-23.381052164536694],[-51.15118501696147,-23.382076336717283],[-51.149167995782435,-23.382509637949354],[-51.14721534761976,-23.382155118864866],[-51.14517686876862,-23.382588419839323],[-51.14410398516276,-23.38376029492248],[-51.14512322458833,-23.388083341091015],[-51.141797285410156,-23.389402876058366],[-51.14030597719799,-23.38880219385971],[-51.14068148646006,-23.391608636504017],[-51.14127157244328,-23.393538646762796],[-51.14093897852546,-23.394434713394368],[-51.140456180902824,-23.39536031431835],[-51.13939402613302,-23.395104297688697],[-51.13738773379004,-23.393154616350518],[-51.13608954462695,-23.389796764546077],[-51.13428710016909,-23.389757375749994],[-51.132162790629465,-23.390072485790583],[-51.13172290835106,-23.39285920758337],[-51.12259266886514,-23.38864463742227],[-51.12228153261944,-23.391657871809155],[-51.11882684740854,-23.393174310244916],[-51.115683298443365,-23.393351555162592],[-51.10903142008701,-23.392750890870328]],[[-51.13829432042955,-23.41600741009485],[-51.133310776080314,-23.418665600378624],[-51.132087688769644,-23.416440600302334],[-51.13002238782791,-23.418291487939495],[-51.12868664773901,-23.419010176689888],[-51.12824140104259,-23.42102839134528],[-51.12696466955051,-23.421860280620358],[-51.12532852205271,-23.422692164660027],[-51.1244541219139,-23.420969322085504],[-51.1215144208339,-23.424109801147612],[-51.12063465627703,-23.423268081315832],[-51.11970661195797,-23.423120410617486],[-51.11977098497433,-23.42156985833077],[-51.1188000253111,-23.421545246243184],[-51.11643431696008,-23.420836416154565],[-51.11942766222045,-23.419167696990424],[-51.11787198099193,-23.416775337218567],[-51.116546969738685,-23.41730697646229],[-51.115699391690086,-23.415702207051474],[-51.115120034542905,-23.413088261827834],[-51.119078975048524,-23.411114231305813],[-51.119599323597356,-23.41169512115064],[-51.12052200349841,-23.41489489238112],[-51.12147686990764,-23.417139608782644],[-51.12308619531643,-23.418626220171642],[-51.12754939111684,-23.41653905242448],[-51.12803218873949,-23.417395582795194],[-51.13119719537679,-23.415574218468866],[-51.13080022844262,-23.414766903017576],[-51.13278506311348,-23.41264029239725],[-51.13521514448077,-23.411055157619415],[-51.13585887464424,-23.410956701416854],[-51.13682446988958,-23.411188073376714],[-51.137205343569626,-23.411576974270133],[-51.13730190309418,-23.41324086645236],[-51.137430649126884,-23.414707830961888],[-51.13829432042955,-23.41600741009485]],[[-51.18929065852,-23.61469318354],[-51.18868716149,-23.61385268133],[-51.18817754178,-23.61338573333],[-51.18731118826,-23.61301708899],[-51.18628926663,-23.61314488581],[-51.18401743559,-23.61395590119],[-51.18348904042,-23.61396573165],[-51.18183143525,-23.61283522407],[-51.18140496401,-23.61344471632],[-51.18062980561,-23.61313505529],[-51.18001021533,-23.61409352754],[-51.17865838198,-23.61328742827],[-51.18064589886,-23.61060367181],[-51.17972321896,-23.61018095058],[-51.18061639456,-23.60849005203],[-51.1821157494,-23.60850479833],[-51.18260927586,-23.60775273479],[-51.18319936184,-23.60804274673],[-51.18415154605,-23.60627808786],[-51.18511177687,-23.60666149766],[-51.18649043231,-23.60469528171],[-51.18902243762,-23.60610112912],[-51.18821241049,-23.60741848294],[-51.18918873458,-23.60801816947],[-51.188899056,-23.60953211999],[-51.18962325244,-23.60992535103],[-51.1911896625,-23.6111935131],[-51.1901489654,-23.61244691705],[-51.19054056792,-23.6127565797],[-51.19029380469,-23.61377895281],[-51.18929065852,-23.61469318354]],[[-51.08005769639,-23.52984412096],[-51.07962317853,-23.52205317842],[-51.08468182473,-23.52194496764],[-51.08581908135,-23.52404030606],[-51.0858941832,-23.52703569673],[-51.08579494147,-23.52777346722],[-51.08530141501,-23.52806365581],[-51.08513511805,-23.52856533627],[-51.08512438922,-23.52981952906],[-51.08470864682,-23.53023759067],[-51.08343459754,-23.53023759067],[-51.08329512267,-23.52978018202],[-51.08005769639,-23.52984412096]]],"terms_url":"http://siglon.londrina.pr.gov.br/","terms_text":"Prefeitura do Londrinas, PR"},{"id":"NSW_LPI_BaseMap","name":"LPI NSW Base Map","type":"tms","template":"https://maps.six.nsw.gov.au/arcgis/rest/services/public/NSW_Base_Map/MapServer/tile/{zoom}/{y}/{x}","scaleExtent":[0,19],"polygon":[[[140.9948644,-28.952966],[148.9611382,-28.8997729],[148.9870097,-28.4862285],[151.013609,-28.4786485],[151.1084711,-28.7032909],[151.8759917,-28.683118],[151.9334839,-28.4078753],[152.25544,-28.2332683],[153.0660798,-28.2104723],[153.1408196,-28.1090981],[153.4735137,-28.1164808],[153.3576523,-27.693606],[159.4938303,-27.699252],[159.4856997,-37.8474137],[149.5256879,-37.8281502],[149.9159578,-37.4869999],[148.0485886,-36.8131741],[147.9680996,-36.1567945],[146.7147701,-36.2866613],[145.3004625,-36.1567945],[144.5300673,-36.1475101],[142.8397973,-35.0254303],[142.356863,-34.7802471],[141.9774146,-34.4016159],[140.9950258,-34.1371824],[140.9948644,-28.952966]]],"terms_url":"http://spatialservices.finance.nsw.gov.au/mapping_and_imagery/lpi_web_services","terms_text":"© Land and Property Information 2016"},{"id":"NSW_LPI_Imagery","name":"LPI NSW Imagery","type":"tms","template":"https://maps.six.nsw.gov.au/arcgis/rest/services/public/NSW_Imagery/MapServer/tile/{zoom}/{y}/{x}","scaleExtent":[0,21],"polygon":[[[140.9868688,-28.9887829],[148.9951472,-28.9727491],[148.9966717,-28.4915066],[151.0029027,-28.4930697],[151.0029027,-28.7261663],[151.4915093,-28.7323921],[151.4918687,-28.7155337],[151.9228213,-28.719635],[151.9251607,-28.4897139],[151.9955886,-28.4898718],[151.9989947,-28.1192742],[152.4967606,-28.122091],[152.4968241,-28.1146398],[153.0044563,-28.1154389],[153.0044563,-28.120397],[153.5038629,-28.119345],[153.5039264,-28.1227063],[153.5919395,-28.1223619],[153.5926582,-28.1776872],[153.6111186,-28.1757867],[153.6113881,-28.1825173],[153.7426846,-28.2162084],[153.7787253,-28.710911],[152.6237954,-32.5877239],[152.3123961,-32.6328837],[151.4141942,-33.5790388],[150.8929925,-35.2648721],[150.4620695,-35.7777256],[150.0156501,-37.5103569],[149.9918121,-37.5126787],[149.519778,-37.5130704],[149.5199577,-37.5216919],[149.4462958,-37.5353701],[149.063344,-37.5357975],[148.9836635,-37.5217631],[148.9816872,-37.5191982],[148.9863847,-37.2584972],[148.4875376,-37.265846],[148.4824774,-37.0092669],[147.994386,-37.014339],[147.988288,-36.5332184],[147.9529707,-36.5260725],[147.9486513,-36.0685992],[147.5034997,-36.0716798],[147.5047701,-36.2651047],[146.4919996,-36.266129],[146.4922536,-36.2565],[145.9929826,-36.2534267],[145.9965866,-36.0188147],[145.9831568,-36.0187058],[145.9624506,-36.0219026],[145.946236,-36.0120936],[145.9454275,-36.0060259],[145.5041534,-36.0013564],[145.5037941,-36.0109125],[145.0072008,-36.0036213],[145.0035404,-36.1520424],[144.4860806,-36.1423149],[144.4874127,-36.0137522],[143.9874676,-36.0024134],[143.9932853,-35.5723753],[143.4971691,-35.5837101],[143.4917967,-35.4065648],[143.4613438,-35.3674934],[143.4585591,-35.3555888],[143.4897755,-35.3396522],[143.4895509,-35.332214],[143.4316994,-35.2570613],[143.2505542,-35.2606556],[143.2438356,-35.0132729],[142.9933305,-35.0177207],[142.9919767,-34.7961882],[142.4971375,-34.8032323],[142.4973172,-34.8007613],[142.4211401,-34.8017571],[142.4209155,-34.7838306],[142.2330892,-34.7859191],[142.2307707,-34.7807542],[142.2269959,-34.5061271],[141.9975302,-34.5083733],[141.9945959,-34.2526687],[141.4982345,-34.2556921],[141.498171,-34.2522794],[140.9945397,-34.2528411],[140.9868688,-28.9887829]]],"terms_url":"http://spatialservices.finance.nsw.gov.au/mapping_and_imagery/lpi_web_services","terms_text":"© Land and Property Information 2016","best":true},{"id":"NSW_LPI_TopographicMap","name":"LPI NSW Topographic Map","type":"tms","template":"https://maps.six.nsw.gov.au/arcgis/rest/services/public/NSW_Topo_Map/MapServer/tile/{zoom}/{y}/{x}","scaleExtent":[0,16],"polygon":[[[140.9988422,-28.9992444],[148.9502438,-28.9993736],[148.9498845,-28.9665265],[148.9998308,-28.9665265],[149.0000917,-28.8165829],[149.1000729,-28.8165829],[149.0997046,-28.7488533],[148.9998504,-28.7497444],[148.9998169,-28.5000304],[151.0000514,-28.5005192],[151.0005904,-28.7325849],[151.0239466,-28.7327424],[151.0241262,-28.7418794],[151.0329297,-28.7418794],[151.033828,-28.7505431],[151.999984,-28.7495314],[151.999984,-28.7164478],[152.0334014,-28.7166053],[152.0332217,-28.683196],[152.0000739,-28.6833537],[151.9998769,-28.6416273],[151.9829886,-28.6413908],[151.9831683,-28.624912],[151.9331321,-28.6247543],[151.9334122,-28.500071],[151.9998875,-28.5002289],[151.9998556,-28.3749591],[152.2499739,-28.3750718],[152.2499356,-28.2500066],[152.9997192,-28.2498563],[152.9998989,-28.2832447],[153.1165002,-28.2834029],[153.11659,-28.2498563],[153.1666262,-28.2500146],[153.166716,-28.2331582],[153.2499898,-28.2332373],[153.2500265,-28.1249689],[153.6249628,-28.1250833],[153.6248398,-28.4999134],[153.7497955,-28.4999924],[153.7495877,-28.7497976],[153.6248117,-28.7501127],[153.6249745,-28.9999333],[153.4997672,-29.0000612],[153.4998417,-29.4995077],[153.3747962,-29.500055],[153.3754111,-29.8750302],[153.4999113,-29.8751403],[153.4999113,-30.0000922],[153.2498947,-29.9997621],[153.250025,-30.1917704],[153.2748185,-30.1916151],[153.2748185,-30.2168467],[153.2166077,-30.2166139],[153.2166077,-30.250065],[153.250025,-30.250065],[153.2497502,-30.3751935],[153.1243608,-30.3749743],[153.1246457,-30.6250359],[153.0331676,-30.6250482],[153.0333884,-30.8750837],[153.1249214,-30.8750291],[153.1249344,-31.1250505],[153.0082433,-31.1249736],[153.0082914,-31.2499759],[153.0000019,-31.250003],[152.9999392,-31.6249919],[152.8749386,-31.6250491],[152.8749572,-31.749954],[152.7832899,-31.7500034],[152.7831966,-31.8748579],[152.749914,-31.8750105],[152.7500397,-32.0000207],[152.6249044,-31.9999446],[152.6249078,-32.5000047],[152.4999757,-32.4999569],[152.5000336,-32.5666443],[152.4166699,-32.5663415],[152.4167598,-32.6249954],[152.3498477,-32.624991],[152.3498477,-32.6332294],[152.2830786,-32.6332218],[152.2832583,-32.6249755],[152.2494816,-32.6249755],[152.2498101,-32.874906],[151.8745693,-32.8750443],[151.8748535,-33.0000091],[151.7497706,-33.0001533],[151.7504669,-33.2500398],[151.6252418,-33.2497393],[151.6250828,-33.3751621],[151.499585,-33.3751442],[151.5003127,-33.6249385],[151.3741466,-33.6243658],[151.3727902,-34.001962],[151.2477819,-34.0011194],[151.2477819,-34.2493114],[150.9957327,-34.2501515],[151.0008143,-34.62483],[150.8717407,-34.6265026],[150.872757,-35.1242738],[150.7670589,-35.1234425],[150.7690916,-35.2463774],[150.6257894,-35.2496974],[150.6280314,-35.3751485],[150.4999742,-35.3751485],[150.4959088,-35.6275034],[150.3719169,-35.6250251],[150.3749658,-35.7537957],[150.2672351,-35.7513213],[150.2652024,-35.8741232],[150.2479249,-35.870829],[150.2458922,-36.374885],[150.1229166,-36.374885],[150.1259656,-36.6224345],[150.0253491,-36.6240658],[150.0283981,-36.7471337],[149.9928266,-36.7495768],[150.0040062,-37.1224477],[150.0588879,-37.1273097],[150.0568553,-37.37809],[149.9979083,-37.3732441],[149.9999409,-37.4830073],[149.987745,-37.4846202],[149.9857123,-37.5080043],[148.0684571,-36.80624],[147.9930603,-36.1379955],[147.8148345,-36.0055567],[147.3893924,-36.0113701],[147.3822059,-36.1310306],[146.9972549,-36.1275479],[146.9886311,-36.2528271],[146.4956356,-36.2447132],[146.5042595,-36.126387],[145.0011817,-36.0079505],[145.0154103,-36.2542074],[144.5072465,-36.2476506],[144.4991158,-36.0211037],[143.9965422,-35.9810531],[143.3382568,-35.2331794],[142.4097581,-34.7669434],[142.0361436,-34.3758837],[140.9965216,-34.1385805],[140.9988422,-28.9992444]]],"terms_url":"http://spatialservices.finance.nsw.gov.au/mapping_and_imagery/lpi_web_services","terms_text":"© Land and Property Information 2016"},{"id":"Mapbox","name":"Mapbox Satellite","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/openstreetmap.map-inh7ifmo/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJncjlmd0t3In0.DmZsIeOW-3x-C5eX-wAqTw","description":"Satellite and aerial imagery.","scaleExtent":[0,19],"terms_url":"http://www.mapbox.com/about/maps/","terms_text":"Terms & Feedback","default":true},{"id":"geodata.md.gov-MD_SixInchImagery","name":"MD Latest 6 Inch Aerial Imagery","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/MD_SixInchImagery/http://geodata.md.gov/imap/services/Imagery/MD_SixInchImagery/MapServer/WmsServer","description":"Six Inch resolution aerial imagery for the State of Maryland","scaleExtent":[0,20],"polygon":[[[-76.234131,37.920368],[-76.598053,38.158317],[-76.940002,38.270532],[-77.038193,38.413786],[-77.23526,38.33627],[-77.312164,38.410558],[-77.262726,38.566422],[-77.042999,38.713376],[-77.049866,38.793697],[-76.92627,38.892503],[-77.040939,38.984499],[-77.12162,38.925229],[-77.150116,38.955137],[-77.252426,38.975425],[-77.259293,39.024252],[-77.34581,39.054918],[-77.461853,39.070379],[-77.537384,39.139647],[-77.474213,39.224807],[-77.572746,39.304284],[-77.723465,39.328986],[-77.777023,39.463234],[-77.861481,39.516225],[-77.840881,39.608862],[-77.956238,39.59299],[-78.166351,39.695564],[-78.270035,39.621557],[-78.338699,39.640066],[-78.466415,39.523641],[-78.662796,39.540058],[-78.798752,39.606217],[-78.9814,39.446799],[-79.06723,39.476486],[-79.485054,39.199536],[-79.485569,39.72158],[-75.788359,39.721811],[-75.690994,38.460579],[-75.049238,38.458159],[-75.049839,38.402218],[-75.081511,38.323208],[-75.097733,38.309066],[-75.186996,38.097551],[-75.23798,38.022402],[-75.61821,37.989669],[-75.863686,37.909534],[-76.234131,37.920368]]],"terms_url":"http://imap.maryland.gov/Pages/imagery-products.aspx","terms_text":"DoIT, MD iMap, MDP"},{"id":"geodata.md.gov-MD_ColorBasemap","name":"MD Transportation Basemap","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/MD_ColorBasemap/http://geodata.md.gov/imap/services/Transportation/MD_ColorBasemap/MapServer/WmsServer","description":"Maryland State Highway Administration road features and additional Maryland focused landmarks","polygon":[[[-76.234131,37.920368],[-76.598053,38.158317],[-76.940002,38.270532],[-77.038193,38.413786],[-77.23526,38.33627],[-77.312164,38.410558],[-77.262726,38.566422],[-77.042999,38.713376],[-77.049866,38.793697],[-76.92627,38.892503],[-77.040939,38.984499],[-77.12162,38.925229],[-77.150116,38.955137],[-77.252426,38.975425],[-77.259293,39.024252],[-77.34581,39.054918],[-77.461853,39.070379],[-77.537384,39.139647],[-77.474213,39.224807],[-77.572746,39.304284],[-77.723465,39.328986],[-77.777023,39.463234],[-77.861481,39.516225],[-77.840881,39.608862],[-77.956238,39.59299],[-78.166351,39.695564],[-78.270035,39.621557],[-78.338699,39.640066],[-78.466415,39.523641],[-78.662796,39.540058],[-78.798752,39.606217],[-78.9814,39.446799],[-79.06723,39.476486],[-79.485054,39.199536],[-79.485569,39.72158],[-75.788359,39.721811],[-75.690994,38.460579],[-75.049238,38.458159],[-75.049839,38.402218],[-75.081511,38.323208],[-75.097733,38.309066],[-75.186996,38.097551],[-75.23798,38.022402],[-75.61821,37.989669],[-75.863686,37.909534],[-76.234131,37.920368]]],"terms_url":"http://imap.maryland.gov/Pages/imagery-products.aspx","terms_text":"DoIT, MD iMap, MDP"},{"id":"New_and_Misaligned_TIGER_Roads-2013","name":"New & Misaligned TIGER Roads","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/enf.e0b8291e/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJhNVlHd29ZIn0.ti6wATGDWOmCnCYen-Ip7Q","description":"At zoom level 16+, public domain map data from the US Census. At lower zooms, only changes since 2006 minus changes already incorporated into OpenStreetMap","scaleExtent":[0,22],"polygon":[[[-124.7617886,48.4130148],[-124.6059492,45.90245],[-124.9934269,40.0557614],[-122.5369737,36.8566086],[-119.9775867,33.0064099],[-117.675935,32.4630223],[-114.8612307,32.4799891],[-111.0089311,31.336015],[-108.1992687,31.3260016],[-108.1871123,31.7755116],[-106.5307225,31.7820947],[-106.4842052,31.7464455],[-106.429317,31.7520583],[-106.2868855,31.5613291],[-106.205248,31.446704],[-105.0205259,30.5360988],[-104.5881916,29.6997856],[-103.2518856,28.8908685],[-102.7173632,29.3920567],[-102.1513983,29.7475702],[-101.2552871,29.4810523],[-100.0062436,28.0082173],[-99.2351068,26.4475962],[-98.0109067,25.9928035],[-97.435024,25.8266009],[-96.9555259,25.9821589],[-96.8061741,27.7978168],[-95.5563349,28.5876066],[-93.7405308,29.4742093],[-90.9028456,28.8564513],[-88.0156706,28.9944338],[-88.0162494,30.0038862],[-86.0277506,30.0047454],[-84.0187909,28.9961781],[-81.9971976,25.9826768],[-81.9966618,25.0134917],[-84.0165592,25.0125783],[-84.0160068,24.0052745],[-80.0199985,24.007096],[-79.8901116,26.8550713],[-80.0245309,32.0161282],[-75.4147385,35.0531894],[-74.0211163,39.5727927],[-72.002019,40.9912464],[-69.8797398,40.9920457],[-69.8489304,43.2619916],[-66.9452845,44.7104937],[-67.7596632,47.0990024],[-69.2505131,47.5122328],[-70.4614886,46.2176574],[-71.412273,45.254878],[-72.0222508,45.0059846],[-75.0798841,44.9802854],[-76.9023061,43.8024568],[-78.7623935,43.6249578],[-79.15798,43.4462589],[-79.0060087,42.8005317],[-82.662475,41.6889458],[-82.1761642,43.588535],[-83.2813977,46.138853],[-87.5064535,48.0142702],[-88.3492194,48.2963271],[-89.4353148,47.9837822],[-93.9981078,49.0067142],[-95.1105379,49.412004],[-96.0131199,49.0060547],[-123.3228926,49.0042878],[-123.2275233,48.1849927],[-124.7617886,48.4130148]],[[-160.5787616,22.5062947],[-160.5782192,21.4984647],[-158.7470604,21.2439843],[-157.5083185,20.995803],[-155.9961942,18.7790194],[-154.6217803,18.7586966],[-154.6890176,19.8805722],[-156.2927622,21.2225888],[-157.5047384,21.9984962],[-159.0093692,22.5070181],[-160.5787616,22.5062947]],[[-167.1571546,68.721974],[-164.8553982,67.0255078],[-168.002195,66.0017503],[-169.0087448,66.001546],[-169.0075381,64.9987675],[-172.5143281,63.8767267],[-173.8197023,59.74014],[-162.5018149,58.0005815],[-160.0159024,58.0012389],[-160.0149725,57.000035],[-160.5054788,56.9999017],[-165.8092575,54.824847],[-178.000097,52.2446469],[-177.9992996,51.2554252],[-171.4689067,51.8215329],[-162.40251,53.956664],[-159.0075717,55.002502],[-158.0190709,55.0027849],[-151.9963213,55.9991902],[-151.500341,57.9987853],[-151.5012894,58.9919816],[-138.5159989,58.9953194],[-138.5150471,57.9986434],[-133.9948193,54.0031685],[-130.0044418,54.0043387],[-130.0070826,57.0000507],[-131.975877,56.9995156],[-135.1229873,59.756601],[-138.0071813,59.991805],[-139.1715881,60.4127229],[-140.9874011,61.0118551],[-140.9683975,69.9535069],[-156.176891,71.5633329],[-160.413634,70.7397728],[-163.0218273,69.9707435],[-164.9717003,68.994689],[-167.1571546,68.721974]]],"overlay":true},{"id":"geodata.state.nj.us-Infrared2015","name":"NJ 2015 Aerial Imagery (Infrared)","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/Infrared2015/http://geodata.state.nj.us/imagerywms/Infrared2015","description":"Digital orthophotography of New Jersey, Near Infrared, 1 foot resolution","scaleExtent":[0,20],"polygon":[[[-74.86599,40.085427],[-74.840927,40.107225],[-74.822903,40.130329],[-74.788055,40.124685],[-74.726086,40.149488],[-74.729176,40.16392],[-74.763336,40.191725],[-74.775524,40.214276],[-74.844017,40.247957],[-74.868393,40.291573],[-74.944611,40.33817],[-74.967098,40.395195],[-75.002632,40.406046],[-75.026836,40.402516],[-75.06134,40.416502],[-75.074215,40.455046],[-75.069065,40.536503],[-75.102367,40.567024],[-75.135927,40.573609],[-75.16777,40.559069],[-75.197639,40.573674],[-75.203733,40.618318],[-75.205064,40.691312],[-75.198326,40.753889],[-75.172405,40.780671],[-75.1367,40.777292],[-75.090179,40.822383],[-75.100994,40.839269],[-75.096874,40.850956],[-75.068464,40.850372],[-75.057049,40.867574],[-75.13773,40.973094],[-75.135155,40.994411],[-75.039024,41.03819],[-74.981518,41.112598],[-74.905472,41.170384],[-74.84024,41.278645],[-74.798012,41.322685],[-74.757156,41.347691],[-74.695702,41.360576],[-74.041054,41.059088],[-74.041051,41.059087],[-74.04105,41.059087],[-74.04105,41.059086],[-74.041049,41.059086],[-73.890266,40.998039],[-73.933406,40.882078],[-73.933407,40.882077],[-73.933408,40.882076],[-73.933408,40.882075],[-74.011459,40.75558],[-74.024543,40.709436],[-74.066048,40.651732],[-74.152222,40.638967],[-74.183121,40.644568],[-74.200459,40.631281],[-74.199257,40.598444],[-74.21505,40.558026],[-74.246807,40.548113],[-74.24715,40.519541],[-74.267578,40.489651],[-74.26054,40.469282],[-74.199257,40.445641],[-74.181061,40.460401],[-74.136429,40.459095],[-73.997555,40.413496],[-74.026566,40.47777],[-74.003906,40.484037],[-73.977814,40.452042],[-73.964767,40.33189],[-74.088364,39.756824],[-74.356842,39.383406],[-74.609528,39.215231],[-74.776382,38.998909],[-74.863586,38.931639],[-74.931221,38.920688],[-74.980316,38.930304],[-74.960747,39.00798],[-74.905472,39.100226],[-74.899979,39.164141],[-75.101166,39.201398],[-75.135498,39.171062],[-75.425949,39.378099],[-75.475044,39.43195],[-75.543365,39.457403],[-75.552292,39.482845],[-75.538902,39.541911],[-75.519676,39.56997],[-75.571175,39.608069],[-75.577698,39.625524],[-75.539932,39.656456],[-75.472984,39.747454],[-75.466253,39.750761],[-75.466252,39.750762],[-75.466252,39.750763],[-75.466251,39.750764],[-75.466251,39.750765],[-75.46625,39.750767],[-75.466249,39.750768],[-75.466249,39.750769],[-75.465088,39.764478],[-75.415041,39.801786],[-75.324669,39.858891],[-75.246048,39.864689],[-75.143738,39.900255],[-75.142365,39.957912],[-75.07061,39.987117],[-75.056534,40.008683],[-74.935341,40.072555],[-74.86599,40.085427]]],"terms_url":"https://njgin.state.nj.us/NJ_NJGINExplorer/ShowMetadata.jsp?docId={E30775F2-6370-4525-8E68-C371ED29BBB3}","terms_text":"NJ Office of Information Technology (NJOIT), Office of Geographic Information Systems (OGIS)"},{"id":"geodata.state.nj.us-Natural2015","name":"NJ 2015 Aerial Imagery (Natural Color)","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/Natural2015/http://geodata.state.nj.us/imagerywms/Natural2015","description":"Digital orthophotography of New Jersey, Natural Color, 1 foot resolution","scaleExtent":[0,20],"polygon":[[[-74.86599,40.085427],[-74.840927,40.107225],[-74.822903,40.130329],[-74.788055,40.124685],[-74.726086,40.149488],[-74.729176,40.16392],[-74.763336,40.191725],[-74.775524,40.214276],[-74.844017,40.247957],[-74.868393,40.291573],[-74.944611,40.33817],[-74.967098,40.395195],[-75.002632,40.406046],[-75.026836,40.402516],[-75.06134,40.416502],[-75.074215,40.455046],[-75.069065,40.536503],[-75.102367,40.567024],[-75.135927,40.573609],[-75.16777,40.559069],[-75.197639,40.573674],[-75.203733,40.618318],[-75.205064,40.691312],[-75.198326,40.753889],[-75.172405,40.780671],[-75.1367,40.777292],[-75.090179,40.822383],[-75.100994,40.839269],[-75.096874,40.850956],[-75.068464,40.850372],[-75.057049,40.867574],[-75.13773,40.973094],[-75.135155,40.994411],[-75.039024,41.03819],[-74.981518,41.112598],[-74.905472,41.170384],[-74.84024,41.278645],[-74.798012,41.322685],[-74.757156,41.347691],[-74.695702,41.360576],[-74.041054,41.059088],[-74.041051,41.059087],[-74.04105,41.059087],[-74.04105,41.059086],[-74.041049,41.059086],[-73.890266,40.998039],[-73.933406,40.882078],[-73.933407,40.882077],[-73.933408,40.882076],[-73.933408,40.882075],[-74.011459,40.75558],[-74.024543,40.709436],[-74.066048,40.651732],[-74.152222,40.638967],[-74.183121,40.644568],[-74.200459,40.631281],[-74.199257,40.598444],[-74.21505,40.558026],[-74.246807,40.548113],[-74.24715,40.519541],[-74.267578,40.489651],[-74.26054,40.469282],[-74.199257,40.445641],[-74.181061,40.460401],[-74.136429,40.459095],[-73.997555,40.413496],[-74.026566,40.47777],[-74.003906,40.484037],[-73.977814,40.452042],[-73.964767,40.33189],[-74.088364,39.756824],[-74.356842,39.383406],[-74.609528,39.215231],[-74.776382,38.998909],[-74.863586,38.931639],[-74.931221,38.920688],[-74.980316,38.930304],[-74.960747,39.00798],[-74.905472,39.100226],[-74.899979,39.164141],[-75.101166,39.201398],[-75.135498,39.171062],[-75.425949,39.378099],[-75.475044,39.43195],[-75.543365,39.457403],[-75.552292,39.482845],[-75.538902,39.541911],[-75.519676,39.56997],[-75.571175,39.608069],[-75.577698,39.625524],[-75.539932,39.656456],[-75.472984,39.747454],[-75.466253,39.750761],[-75.466252,39.750762],[-75.466252,39.750763],[-75.466251,39.750764],[-75.466251,39.750765],[-75.46625,39.750767],[-75.466249,39.750768],[-75.466249,39.750769],[-75.465088,39.764478],[-75.415041,39.801786],[-75.324669,39.858891],[-75.246048,39.864689],[-75.143738,39.900255],[-75.142365,39.957912],[-75.07061,39.987117],[-75.056534,40.008683],[-74.935341,40.072555],[-74.86599,40.085427]]],"terms_url":"https://njgin.state.nj.us/NJ_NJGINExplorer/ShowMetadata.jsp?docId={CDC67AB8-ADA1-4B4B-9087-67A82CB9151C}","terms_text":"NJ Office of Information Technology (NJOIT), Office of Geographic Information Systems (OGIS)"},{"id":"NLS-Bartholomew-hfinch-hist","name":"NLS - Bartholomew Half Inch, 1897-1907","type":"tms","template":"http://geo.nls.uk/mapdata2/bartholomew/great_britain/{zoom}/{x}/{-y}.png","scaleExtent":[0,15],"polygon":[[[-6.4585407,49.9044128],[-6.3872009,49.9841116],[-6.2296827,49.9896159],[-6.2171269,49.8680087],[-6.4551164,49.8591793],[-6.4585407,49.9044128]],[[-1.4495137,60.8634056],[-0.7167114,60.8545122],[-0.7349744,60.4359756],[-0.6938826,60.4168218],[-0.7258429,60.3942735],[-0.7395401,60.0484714],[-0.9267357,60.0461918],[-0.9381501,59.8266157],[-1.4586452,59.831205],[-1.4455187,60.0535999],[-1.463211,60.0535999],[-1.4643524,60.0630002],[-1.5716475,60.0638546],[-1.5693646,60.1790005],[-1.643558,60.1807033],[-1.643558,60.1892162],[-1.8216221,60.1894999],[-1.8204807,60.3615507],[-1.8415973,60.3697345],[-1.8216221,60.3832755],[-1.8179852,60.5934321],[-1.453168,60.5934321],[-1.4495137,60.8634056]],[[-4.9089213,54.4242078],[-4.282598,54.4429861],[-4.2535417,54.029769],[-4.8766366,54.0221831],[-4.9089213,54.4242078]],[[-5.8667408,59.1444603],[-5.7759966,59.1470945],[-5.7720016,59.1014052],[-5.8621751,59.0990605],[-5.8667408,59.1444603]],[[-1.7065887,59.5703599],[-1.5579165,59.5693481],[-1.5564897,59.4965695],[-1.7054472,59.4975834],[-1.7065887,59.5703599]],[[-7.6865827,58.2940975],[-7.5330594,58.3006957],[-7.5256401,58.2646905],[-7.6797341,58.2577853],[-7.6865827,58.2940975]],[[-4.5338281,59.0359871],[-4.481322,59.0371616],[-4.4796099,59.0186583],[-4.5332574,59.0180707],[-4.5338281,59.0359871]],[[-8.6710698,57.8769896],[-8.4673234,57.8897332],[-8.4467775,57.7907],[-8.6510947,57.7779213],[-8.6710698,57.8769896]],[[-5.2395519,50.3530581],[-5.7920073,50.3384899],[-5.760047,49.9317027],[-4.6551363,49.9581461],[-4.677965,50.2860073],[-4.244219,50.2801723],[-4.2487848,50.2042525],[-3.3812929,50.2042525],[-3.4223846,50.5188201],[-3.1164796,50.5246258],[-3.1210453,50.6579592],[-2.6736357,50.6619495],[-2.5953453,50.6394325],[-2.5905026,50.5728419],[-2.4791203,50.5733545],[-2.4758919,50.5066704],[-2.3967943,50.5056438],[-2.401637,50.5723293],[-1.0400296,50.5718167],[-1.0335726,50.7059289],[-0.549302,50.7038843],[-0.5460736,50.7886618],[-0.0924734,50.7856002],[-0.0876307,50.7181949],[0.4789659,50.7120623],[0.487037,50.8182467],[0.9761503,50.8049868],[0.9922927,51.0126311],[1.4491213,51.0004424],[1.4781775,51.4090372],[1.0229632,51.4271576],[1.035877,51.7640881],[1.6105448,51.7500992],[1.646058,52.1560003],[1.7267698,52.1540195],[1.749369,52.4481811],[1.7870672,52.4811624],[1.759102,52.522505],[1.7933451,52.9602749],[0.3798147,52.9958468],[0.3895238,53.2511239],[0.3478614,53.2511239],[0.3238912,53.282186],[0.3461492,53.6538501],[0.128487,53.6575466],[0.116582,53.6674703],[0.1350586,54.0655731],[-0.0609831,54.065908],[-0.0414249,54.4709448],[-0.5662701,54.4771794],[-0.5592078,54.6565127],[-1.1665638,54.6623485],[-1.1637389,54.842611],[-1.3316194,54.843909],[-1.3257065,55.2470842],[-1.529453,55.2487108],[-1.524178,55.6540122],[-1.7638798,55.6540122],[-1.7733693,55.9719116],[-2.1607858,55.9682981],[-2.1543289,56.0621387],[-2.4578051,56.0585337],[-2.4190635,56.641717],[-2.0962164,56.641717],[-2.0833025,57.0021322],[-1.9283359,57.0126802],[-1.9180966,57.3590895],[-1.7502161,57.3625721],[-1.7695869,57.7608634],[-3.6937554,57.7574187],[-3.7066693,57.9806386],[-3.5969013,57.9772149],[-3.6033582,58.1207277],[-3.0222335,58.1309566],[-3.0286905,58.5410788],[-2.8478961,58.530968],[-2.86081,58.8430508],[-2.679624,58.8414991],[-2.6841897,58.885175],[-2.6339665,58.9052239],[-2.679624,58.9335083],[-2.6887555,59.0229231],[-2.3668703,59.0229231],[-2.3702946,59.2652861],[-2.3429001,59.2821989],[-2.3714361,59.2996861],[-2.3737189,59.3707083],[-2.3429001,59.385825],[-2.3725775,59.400354],[-2.3714361,59.4259098],[-3.0734196,59.4230067],[-3.0711368,59.3433649],[-3.103097,59.3311405],[-3.0745611,59.3136695],[-3.0722782,59.232603],[-3.3850319,59.1484167],[-3.3747589,58.9352753],[-3.5653789,58.9323303],[-3.554829,58.69759],[-5.2808579,58.6667732],[-5.2534159,58.3514125],[-5.5068508,58.3437887],[-5.4761804,58.0323557],[-5.8974958,58.0212436],[-5.8522972,57.6171758],[-6.1396311,57.6137174],[-6.1541592,57.7423183],[-6.2913692,57.7380102],[-6.3365678,58.1398784],[-6.1121891,58.1466944],[-6.1473778,58.5106285],[-6.2934817,58.5416182],[-6.8413713,58.2977321],[-7.0057382,58.2929331],[-7.1016189,58.2064403],[-7.2573132,58.1793148],[-7.2531092,58.1004928],[-7.4070698,58.0905566],[-7.391347,57.7911354],[-7.790991,57.7733151],[-7.7624215,57.5444165],[-7.698501,57.1453194],[-7.7943817,57.1304547],[-7.716764,56.7368628],[-7.0122067,56.7654359],[-6.979922,56.5453858],[-7.0638622,56.5453858],[-7.0444914,56.3562587],[-6.500676,56.3812917],[-6.4491433,55.9793649],[-6.563287,55.9691456],[-6.5393742,55.7030135],[-6.5595521,55.6907321],[-6.5345315,55.6761713],[-6.5216176,55.5704434],[-5.8912587,55.5923416],[-5.8560127,55.2320733],[-5.2293639,55.2515958],[-5.1837064,54.6254139],[-3.6655956,54.6518373],[-3.6496155,54.4320023],[-3.5400375,54.4306744],[-3.530906,54.0290181],[-3.0697656,54.030359],[-3.0675737,53.8221388],[-3.0804876,53.7739911],[-3.0619239,53.7477488],[-3.0611168,53.6737049],[-3.2144691,53.6708361],[-3.2057699,53.4226163],[-3.2799632,53.355224],[-3.2896655,53.3608441],[-3.3327547,53.364931],[-3.3761293,53.3540318],[-4.0888976,53.3433102],[-4.0945474,53.4612036],[-4.697412,53.4448624],[-4.6882805,53.3318598],[-4.7202407,53.2895771],[-4.6837148,53.2486184],[-4.6768661,53.1542644],[-4.8480816,53.1446807],[-4.8178336,52.7440299],[-4.2545751,52.7558939],[-4.228876,52.254876],[-4.2607571,52.2536408],[-4.2724603,52.2432637],[-4.8136263,52.230095],[-4.8079191,52.1138892],[-5.3889104,52.0991668],[-5.3717888,51.9129667],[-5.4208706,51.9101502],[-5.414022,51.8453218],[-5.3683645,51.8474373],[-5.3466772,51.5595332],[-4.773676,51.5758518],[-4.7656859,51.4885146],[-4.1915432,51.4970427],[-4.1869775,51.4344663],[-3.6151177,51.4444274],[-3.6105519,51.3746543],[-3.1494115,51.3789292],[-3.1494115,51.2919281],[-4.3038735,51.2745907],[-4.2861169,51.0508721],[-4.8543277,51.0366633],[-4.8372201,50.7212787],[-5.2618345,50.7082694],[-5.2395519,50.3530581]],[[-2.1502671,60.171318],[-2.0030218,60.1696146],[-2.0013096,60.0997023],[-2.148555,60.1011247],[-2.1502671,60.171318]],[[-6.2086011,59.1163488],[-6.1229934,59.1166418],[-6.121852,59.0714985],[-6.2097426,59.0714985],[-6.2086011,59.1163488]],[[-4.4159559,59.0889036],[-4.4212022,59.0770848],[-4.3971904,59.0779143],[-4.3913388,59.0897328],[-4.4159559,59.0889036]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLS-OS-7th_Series","name":"NLS - OS 1-inch 7th Series 1955-61","type":"tms","template":"http://geo.nls.uk/mapdata2/os/seventh/{zoom}/{x}/{-y}.png","scaleExtent":[5,16],"polygon":[[[-6.4585407,49.9044128],[-6.3872009,49.9841116],[-6.2296827,49.9896159],[-6.2171269,49.8680087],[-6.4551164,49.8591793],[-6.4585407,49.9044128]],[[-1.4495137,60.8634056],[-0.7167114,60.8545122],[-0.7349744,60.4359756],[-0.6938826,60.4168218],[-0.7258429,60.3942735],[-0.7395401,60.0484714],[-0.9267357,60.0461918],[-0.9381501,59.8266157],[-1.4586452,59.831205],[-1.4455187,60.0535999],[-1.463211,60.0535999],[-1.4643524,60.0630002],[-1.5716475,60.0638546],[-1.5693646,60.1790005],[-1.643558,60.1807033],[-1.643558,60.1892162],[-1.8216221,60.1894999],[-1.8204807,60.3615507],[-1.8415973,60.3697345],[-1.8216221,60.3832755],[-1.8179852,60.5934321],[-1.453168,60.5934321],[-1.4495137,60.8634056]],[[-4.9089213,54.4242078],[-4.282598,54.4429861],[-4.2535417,54.029769],[-4.8766366,54.0221831],[-4.9089213,54.4242078]],[[-5.8667408,59.1444603],[-5.7759966,59.1470945],[-5.7720016,59.1014052],[-5.8621751,59.0990605],[-5.8667408,59.1444603]],[[-1.7065887,59.5703599],[-1.5579165,59.5693481],[-1.5564897,59.4965695],[-1.7054472,59.4975834],[-1.7065887,59.5703599]],[[-7.6865827,58.2940975],[-7.5330594,58.3006957],[-7.5256401,58.2646905],[-7.6797341,58.2577853],[-7.6865827,58.2940975]],[[-4.5338281,59.0359871],[-4.481322,59.0371616],[-4.4796099,59.0186583],[-4.5332574,59.0180707],[-4.5338281,59.0359871]],[[-8.6710698,57.8769896],[-8.4673234,57.8897332],[-8.4467775,57.7907],[-8.6510947,57.7779213],[-8.6710698,57.8769896]],[[-5.2395519,50.3530581],[-5.7920073,50.3384899],[-5.760047,49.9317027],[-4.6551363,49.9581461],[-4.677965,50.2860073],[-4.244219,50.2801723],[-4.2487848,50.2042525],[-3.3812929,50.2042525],[-3.4223846,50.5188201],[-3.1164796,50.5246258],[-3.1210453,50.6579592],[-2.6736357,50.6619495],[-2.5953453,50.6394325],[-2.5905026,50.5728419],[-2.4791203,50.5733545],[-2.4758919,50.5066704],[-2.3967943,50.5056438],[-2.401637,50.5723293],[-1.0400296,50.5718167],[-1.0335726,50.7059289],[-0.549302,50.7038843],[-0.5460736,50.7886618],[-0.0924734,50.7856002],[-0.0876307,50.7181949],[0.4789659,50.7120623],[0.487037,50.8182467],[0.9761503,50.8049868],[0.9922927,51.0126311],[1.4491213,51.0004424],[1.4781775,51.4090372],[1.0229632,51.4271576],[1.035877,51.7640881],[1.6105448,51.7500992],[1.646058,52.1560003],[1.7267698,52.1540195],[1.749369,52.4481811],[1.7870672,52.4811624],[1.759102,52.522505],[1.7933451,52.9602749],[0.3798147,52.9958468],[0.3895238,53.2511239],[0.3478614,53.2511239],[0.3238912,53.282186],[0.3461492,53.6538501],[0.128487,53.6575466],[0.116582,53.6674703],[0.1350586,54.0655731],[-0.0609831,54.065908],[-0.0414249,54.4709448],[-0.5662701,54.4771794],[-0.5592078,54.6565127],[-1.1665638,54.6623485],[-1.1637389,54.842611],[-1.3316194,54.843909],[-1.3257065,55.2470842],[-1.529453,55.2487108],[-1.524178,55.6540122],[-1.7638798,55.6540122],[-1.7733693,55.9719116],[-2.1607858,55.9682981],[-2.1543289,56.0621387],[-2.4578051,56.0585337],[-2.4190635,56.641717],[-2.0962164,56.641717],[-2.0833025,57.0021322],[-1.9283359,57.0126802],[-1.9180966,57.3590895],[-1.7502161,57.3625721],[-1.7695869,57.7608634],[-3.6937554,57.7574187],[-3.7066693,57.9806386],[-3.5969013,57.9772149],[-3.6033582,58.1207277],[-3.0222335,58.1309566],[-3.0286905,58.5410788],[-2.8478961,58.530968],[-2.86081,58.8430508],[-2.679624,58.8414991],[-2.6841897,58.885175],[-2.6339665,58.9052239],[-2.679624,58.9335083],[-2.6887555,59.0229231],[-2.3668703,59.0229231],[-2.3702946,59.2652861],[-2.3429001,59.2821989],[-2.3714361,59.2996861],[-2.3737189,59.3707083],[-2.3429001,59.385825],[-2.3725775,59.400354],[-2.3714361,59.4259098],[-3.0734196,59.4230067],[-3.0711368,59.3433649],[-3.103097,59.3311405],[-3.0745611,59.3136695],[-3.0722782,59.232603],[-3.3850319,59.1484167],[-3.3747589,58.9352753],[-3.5653789,58.9323303],[-3.554829,58.69759],[-5.2808579,58.6667732],[-5.2534159,58.3514125],[-5.5068508,58.3437887],[-5.4761804,58.0323557],[-5.8974958,58.0212436],[-5.8522972,57.6171758],[-6.1396311,57.6137174],[-6.1541592,57.7423183],[-6.2913692,57.7380102],[-6.3365678,58.1398784],[-6.1121891,58.1466944],[-6.1473778,58.5106285],[-6.2934817,58.5416182],[-6.8413713,58.2977321],[-7.0057382,58.2929331],[-7.1016189,58.2064403],[-7.2573132,58.1793148],[-7.2531092,58.1004928],[-7.4070698,58.0905566],[-7.391347,57.7911354],[-7.790991,57.7733151],[-7.7624215,57.5444165],[-7.698501,57.1453194],[-7.7943817,57.1304547],[-7.716764,56.7368628],[-7.0122067,56.7654359],[-6.979922,56.5453858],[-7.0638622,56.5453858],[-7.0444914,56.3562587],[-6.500676,56.3812917],[-6.4491433,55.9793649],[-6.563287,55.9691456],[-6.5393742,55.7030135],[-6.5595521,55.6907321],[-6.5345315,55.6761713],[-6.5216176,55.5704434],[-5.8912587,55.5923416],[-5.8560127,55.2320733],[-5.2293639,55.2515958],[-5.1837064,54.6254139],[-3.6655956,54.6518373],[-3.6496155,54.4320023],[-3.5400375,54.4306744],[-3.530906,54.0290181],[-3.0697656,54.030359],[-3.0675737,53.8221388],[-3.0804876,53.7739911],[-3.0619239,53.7477488],[-3.0611168,53.6737049],[-3.2144691,53.6708361],[-3.2057699,53.4226163],[-3.2799632,53.355224],[-3.2896655,53.3608441],[-3.3327547,53.364931],[-3.3761293,53.3540318],[-4.0888976,53.3433102],[-4.0945474,53.4612036],[-4.697412,53.4448624],[-4.6882805,53.3318598],[-4.7202407,53.2895771],[-4.6837148,53.2486184],[-4.6768661,53.1542644],[-4.8480816,53.1446807],[-4.8178336,52.7440299],[-4.2545751,52.7558939],[-4.228876,52.254876],[-4.2607571,52.2536408],[-4.2724603,52.2432637],[-4.8136263,52.230095],[-4.8079191,52.1138892],[-5.3889104,52.0991668],[-5.3717888,51.9129667],[-5.4208706,51.9101502],[-5.414022,51.8453218],[-5.3683645,51.8474373],[-5.3466772,51.5595332],[-4.773676,51.5758518],[-4.7656859,51.4885146],[-4.1915432,51.4970427],[-4.1869775,51.4344663],[-3.6151177,51.4444274],[-3.6105519,51.3746543],[-3.1494115,51.3789292],[-3.1494115,51.2919281],[-4.3038735,51.2745907],[-4.2861169,51.0508721],[-4.8543277,51.0366633],[-4.8372201,50.7212787],[-5.2618345,50.7082694],[-5.2395519,50.3530581]],[[-2.1502671,60.171318],[-2.0030218,60.1696146],[-2.0013096,60.0997023],[-2.148555,60.1011247],[-2.1502671,60.171318]],[[-6.2086011,59.1163488],[-6.1229934,59.1166418],[-6.121852,59.0714985],[-6.2097426,59.0714985],[-6.2086011,59.1163488]],[[-4.4159559,59.0889036],[-4.4212022,59.0770848],[-4.3971904,59.0779143],[-4.3913388,59.0897328],[-4.4159559,59.0889036]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLS-OS-1st_Series","name":"NLS - OS 1:25k 1st Series 1937-61","type":"tms","template":"http://geo.nls.uk/mapdata2/os/25000/{zoom}/{x}/{-y}.png","scaleExtent":[5,16],"polygon":[[[-4.7157244,54.6796556],[-4.6850662,54.6800268],[-4.6835779,54.6623245],[-4.7148782,54.6615818],[-4.7157244,54.6796556]],[[-3.7085748,58.3371151],[-3.5405937,58.3380684],[-3.5315137,58.1608002],[-3.3608086,58.1622372],[-3.3653486,58.252173],[-3.1610473,58.2536063],[-3.1610473,58.3261509],[-3.0275704,58.3271045],[-3.0366505,58.6139001],[-3.0021463,58.614373],[-3.0030543,58.7036341],[-3.4180129,58.7003322],[-3.4171049,58.6290293],[-3.7240109,58.6266658],[-3.7231029,58.606806],[-4.2361262,58.5992374],[-4.2334022,58.5092347],[-3.88836,58.5144516],[-3.8829119,58.4261327],[-3.7158389,58.4270836],[-3.7085748,58.3371151]],[[-6.46676,49.9943621],[-6.1889102,50.004868],[-6.1789222,49.8967815],[-6.3169391,49.8915171],[-6.312399,49.8200979],[-6.4504159,49.8159968],[-6.46676,49.9943621]],[[-5.6453263,50.2029809],[-5.7801329,50.2014076],[-5.7637888,50.0197267],[-5.3479221,50.0290604],[-5.3388421,49.9414854],[-5.024672,49.9473287],[-5.0355681,50.0383923],[-5.0010639,50.0453901],[-4.9974319,50.1304478],[-4.855783,50.13394],[-4.861231,50.206057],[-4.6546085,50.2140172],[-4.6558926,50.3018616],[-4.5184924,50.3026818],[-4.51464,50.325642],[-4.2488284,50.3264618],[-4.2488284,50.3100631],[-4.10886,50.3141633],[-4.1062917,50.2411267],[-3.9648088,50.2432047],[-3.9640778,50.2254158],[-3.8522287,50.2273626],[-3.8503757,50.1552563],[-3.6921809,50.1572487],[-3.5414602,50.1602198],[-3.5465781,50.3226814],[-3.4068012,50.3241013],[-3.4165761,50.5892711],[-3.2746691,50.5962721],[-3.2749172,50.6106323],[-2.9971742,50.613972],[-2.9896008,50.688537],[-2.7120266,50.690565],[-2.710908,50.6195964],[-2.5695473,50.6157538],[-2.5651019,50.5134083],[-2.4014463,50.513379],[-2.3940583,50.6160348],[-2.2894123,50.6147436],[-2.2876184,50.6008549],[-2.1477855,50.6048506],[-2.1451013,50.5325437],[-1.9335117,50.5347477],[-1.9362139,50.6170445],[-1.8573025,50.6228094],[-1.8554865,50.709139],[-1.6066929,50.709139],[-1.6085089,50.6239615],[-1.4450678,50.6228094],[-1.4432518,50.5317039],[-1.1545059,50.5293951],[-1.1472419,50.6170485],[-1.011041,50.6205051],[-1.011041,50.7056889],[-0.704135,50.7045388],[-0.700503,50.7769401],[-0.5860943,50.7723465],[-0.5879103,50.7907181],[-0.0149586,50.7798108],[-0.0185906,50.7625836],[0.0967261,50.7620093],[0.0921861,50.6913106],[0.3046595,50.6890096],[0.3101075,50.7757917],[0.5511831,50.7726336],[0.5529991,50.8432096],[0.695556,50.8403428],[0.696464,50.8592608],[0.9852099,50.8523824],[0.9906579,50.9417226],[1.0160821,50.9411504],[1.0215301,51.0303204],[1.2812198,51.0240383],[1.2848518,51.0948044],[1.4277848,51.0948044],[1.4386809,51.2882859],[1.4713691,51.2871502],[1.4804492,51.3994534],[1.1590151,51.4073836],[1.1590151,51.3869889],[1.0191822,51.3903886],[1.0228142,51.4798247],[0.8793493,51.4843484],[0.8829813,51.5566675],[1.0264462,51.5544092],[1.0373423,51.7493319],[1.2607117,51.7482076],[1.2661598,51.8279642],[1.3351682,51.8335756],[1.3478803,51.9199021],[1.4840812,51.9199021],[1.4986093,52.0038271],[1.6438902,52.0027092],[1.6656823,52.270221],[1.7310588,52.270221],[1.7528509,52.4465637],[1.8254914,52.4476705],[1.8345714,52.624408],[1.7690346,52.6291402],[1.7741711,52.717904],[1.6996925,52.721793],[1.706113,52.8103687],[1.559724,52.8165777],[1.5648605,52.9034116],[1.4184715,52.9103818],[1.4223238,52.9281894],[1.3439928,52.9289635],[1.3491293,53.0001194],[0.4515789,53.022589],[0.4497629,52.9351139],[0.3789384,52.9351139],[0.3716744,52.846365],[0.2227614,52.8496552],[0.2336575,52.9329248],[0.3062979,52.9351139],[0.308114,53.022589],[0.3807544,53.0236813],[0.3993708,53.2933729],[0.3248922,53.2987454],[0.3274604,53.3853782],[0.2504136,53.38691],[0.2581183,53.4748924],[0.1862079,53.4779494],[0.1913443,53.6548777],[0.1502527,53.6594436],[0.1528209,53.7666003],[0.0012954,53.7734308],[0.0025796,53.8424326],[-0.0282392,53.841675],[-0.0226575,53.9311501],[-0.1406983,53.9322193],[-0.1416063,54.0219323],[-0.1706625,54.0235326],[-0.1679384,54.0949482],[-0.0126694,54.0912206],[-0.0099454,54.1811226],[-0.1615824,54.1837795],[-0.1606744,54.2029038],[-0.2405789,54.2034349],[-0.2378549,54.2936234],[-0.3894919,54.2941533],[-0.3857497,54.3837321],[-0.461638,54.3856364],[-0.4571122,54.4939066],[-0.6105651,54.4965434],[-0.6096571,54.5676704],[-0.7667421,54.569776],[-0.7640181,54.5887213],[-0.9192871,54.5908258],[-0.9148116,54.6608348],[-1.1485204,54.6634343],[-1.1472363,54.7528316],[-1.2268514,54.7532021],[-1.2265398,54.8429879],[-1.2991803,54.8435107],[-1.2991803,54.9333391],[-1.3454886,54.9354258],[-1.3436726,55.0234878],[-1.3772688,55.0255698],[-1.3754528,55.1310877],[-1.4997441,55.1315727],[-1.4969272,55.2928323],[-1.5296721,55.2942946],[-1.5258198,55.6523803],[-1.7659492,55.6545537],[-1.7620968,55.7435626],[-1.9688392,55.7435626],[-1.9698023,55.8334505],[-2.0019051,55.8336308],[-2.0015841,55.9235526],[-2.1604851,55.9240613],[-2.1613931,55.9413549],[-2.3202942,55.9408463],[-2.3212022,56.0145126],[-2.5627317,56.0124824],[-2.5645477,56.1022207],[-2.9658863,56.0991822],[-2.9667943,56.1710304],[-2.4828272,56.1755797],[-2.4882752,56.2856078],[-2.5645477,56.2835918],[-2.5681798,56.3742075],[-2.7261728,56.3732019],[-2.7316208,56.4425301],[-2.6190281,56.4425301],[-2.6153961,56.5317671],[-2.453771,56.5347715],[-2.4534686,56.6420248],[-2.4062523,56.6440218],[-2.3953562,56.7297964],[-2.2936596,56.7337811],[-2.2972916,56.807423],[-2.1629067,56.8113995],[-2.1592747,56.9958425],[-1.9922016,57.0017771],[-2.0067297,57.2737477],[-1.9195612,57.2757112],[-1.9304572,57.3482876],[-1.8106005,57.3443682],[-1.7997044,57.4402728],[-1.6616875,57.4285429],[-1.6689516,57.5398256],[-1.7452241,57.5398256],[-1.7524881,57.6313302],[-1.8287606,57.6332746],[-1.8287606,57.7187255],[-3.1768526,57.7171219],[-3.1794208,57.734264],[-3.5134082,57.7292105],[-3.5129542,57.7112683],[-3.7635638,57.7076303],[-3.7598539,57.635713],[-3.8420372,57.6343382],[-3.8458895,57.6178365],[-3.9794374,57.6157733],[-3.9794374,57.686544],[-3.8150708,57.689976],[-3.817639,57.7968899],[-3.6853753,57.7989429],[-3.6892276,57.8891567],[-3.9383458,57.8877915],[-3.9421981,57.9750592],[-3.6943641,57.9784638],[-3.6969323,58.0695865],[-4.0372226,58.0641528],[-4.0346543,57.9730163],[-4.2003051,57.9702923],[-4.1832772,57.7012869],[-4.518752,57.6951111],[-4.5122925,57.6050682],[-4.6789116,57.6016628],[-4.666022,57.4218334],[-3.6677696,57.4394729],[-3.671282,57.5295384],[-3.3384979,57.5331943],[-3.3330498,57.4438859],[-2.8336466,57.4485275],[-2.8236396,56.9992706],[-2.3305398,57.0006693],[-2.3298977,56.9113932],[-2.6579889,56.9092901],[-2.6559637,56.8198406],[-2.8216747,56.8188467],[-2.8184967,56.7295397],[-3.1449248,56.7265508],[-3.1435628,56.6362749],[-3.4679089,56.6350265],[-3.474265,56.7238108],[-3.8011471,56.7188284],[-3.785711,56.4493026],[-3.946428,56.4457896],[-3.9428873,56.2659777],[-4.423146,56.2588459],[-4.4141572,56.0815506],[-4.8944159,56.0708008],[-4.8791072,55.8896994],[-5.1994158,55.8821374],[-5.1852906,55.7023791],[-5.0273445,55.7067203],[-5.0222081,55.6879046],[-4.897649,55.6907999],[-4.8880181,55.6002822],[-4.7339244,55.6046348],[-4.7275038,55.5342082],[-4.773732,55.5334815],[-4.7685955,55.4447227],[-4.8494947,55.4418092],[-4.8405059,55.3506535],[-4.8700405,55.3513836],[-4.8649041,55.2629462],[-4.9920314,55.2592875],[-4.9907473,55.1691779],[-5.0600894,55.1655105],[-5.0575212,55.0751884],[-5.2141831,55.0722477],[-5.1991766,54.8020337],[-5.0466316,54.8062205],[-5.0502636,54.7244996],[-4.9703591,54.7203043],[-4.9776232,54.6215905],[-4.796022,54.6342056],[-4.796022,54.7307917],[-4.8977186,54.7265971],[-4.9086147,54.8145928],[-4.8069181,54.8166856],[-4.8105501,54.7915648],[-4.6943253,54.7978465],[-4.6761652,54.7244996],[-4.5744686,54.7244996],[-4.5599405,54.6426135],[-4.3093309,54.6384098],[-4.3333262,54.8229889],[-4.2626999,54.8274274],[-4.2549952,54.7348587],[-3.8338058,54.7400481],[-3.836374,54.8141105],[-3.7118149,54.8133706],[-3.7143831,54.8318654],[-3.5346072,54.8355633],[-3.5271039,54.9066228],[-3.4808758,54.9084684],[-3.4776655,54.7457328],[-3.5874573,54.744621],[-3.5836049,54.6546166],[-3.7107322,54.6531308],[-3.6991752,54.4550407],[-3.5746161,54.4572801],[-3.5759002,54.3863042],[-3.539945,54.3855564],[-3.5386609,54.297224],[-3.46033,54.2957252],[-3.4590458,54.2079507],[-3.3807149,54.2102037],[-3.381999,54.1169788],[-3.302878,54.1160656],[-3.300154,54.0276224],[-3.1013007,54.0292224],[-3.093596,53.6062158],[-3.2065981,53.6016441],[-3.2091663,53.4917753],[-3.2451215,53.4887193],[-3.2348486,53.4045934],[-3.5276266,53.3999999],[-3.5343966,53.328481],[-3.6488053,53.3252272],[-3.6527308,53.3057716],[-3.7271873,53.3046865],[-3.7315003,53.3945257],[-3.9108315,53.3912769],[-3.9071995,53.3023804],[-3.9521457,53.3015665],[-3.9566724,53.3912183],[-4.1081979,53.3889209],[-4.1081979,53.4072967],[-4.2622916,53.4065312],[-4.2635757,53.4753707],[-4.638537,53.4677274],[-4.6346847,53.3812621],[-4.7091633,53.3774321],[-4.7001745,53.1954965],[-4.5499332,53.1962658],[-4.5435126,53.1092488],[-4.3919871,53.1100196],[-4.3855666,53.0236002],[-4.6115707,53.0205105],[-4.603866,52.9284932],[-4.7566756,52.9261709],[-4.7476868,52.8370555],[-4.8208813,52.8331768],[-4.8208813,52.7446476],[-4.3701572,52.7539749],[-4.3765778,52.8401583],[-4.2314728,52.8455875],[-4.2237682,52.7586379],[-4.1056297,52.7570836],[-4.1015192,52.6714874],[-4.1487355,52.6703862],[-4.1305754,52.4008596],[-4.1995838,52.3986435],[-4.2050319,52.3110195],[-4.3466808,52.303247],[-4.3484968,52.2365693],[-4.4901457,52.2332328],[-4.4883297,52.2098702],[-4.6572188,52.2098702],[-4.6590348,52.1385939],[-4.7788916,52.13525],[-4.7807076,52.1162967],[-4.9259885,52.1140663],[-4.9187245,52.0392855],[-5.2365265,52.0314653],[-5.2347105,51.9442339],[-5.3473032,51.9408755],[-5.3473032,51.9195995],[-5.4925842,51.9162392],[-5.4853201,51.8265386],[-5.1983903,51.8321501],[-5.1893102,51.7625177],[-5.335825,51.7589528],[-5.3281204,51.6686495],[-5.1836575,51.6730296],[-5.1836575,51.6539134],[-5.0674452,51.6578966],[-5.0603825,51.5677905],[-4.5974594,51.5809588],[-4.60388,51.6726314],[-4.345773,51.6726314],[-4.3355001,51.4962964],[-3.9528341,51.5106841],[-3.9425611,51.5905333],[-3.8809237,51.5953198],[-3.8706508,51.5074872],[-3.7679216,51.4978952],[-3.7550805,51.4242895],[-3.5855774,51.41468],[-3.5778727,51.3329177],[-3.0796364,51.3329177],[-3.0770682,51.2494018],[-3.7216935,51.2381477],[-3.7216935,51.2558315],[-3.8706508,51.2558315],[-3.8680825,51.2365398],[-4.2944084,51.2252825],[-4.289272,51.0496352],[-4.5692089,51.0431767],[-4.5624122,50.9497388],[-4.5905604,50.9520269],[-4.5896524,50.8627065],[-4.6296046,50.8592677],[-4.6226411,50.7691513],[-4.6952816,50.7680028],[-4.6934655,50.6967379],[-4.8342064,50.6938621],[-4.8296664,50.6046231],[-4.9676833,50.6000126],[-4.9685913,50.5821427],[-5.1084242,50.5786832],[-5.1029762,50.4892254],[-5.1311244,50.48807],[-5.1274923,50.4163798],[-5.2664172,50.4117509],[-5.2609692,50.3034214],[-5.5124868,50.2976214],[-5.5061308,50.2256428],[-5.6468717,50.2209953],[-5.6453263,50.2029809]],[[-5.1336607,55.2630226],[-5.1021999,55.2639372],[-5.0999527,55.2458239],[-5.1322161,55.2446343],[-5.1336607,55.2630226]],[[-5.6431878,55.5095745],[-5.4861028,55.5126594],[-5.4715747,55.3348829],[-5.6277517,55.3302345],[-5.6431878,55.5095745]],[[-4.7213517,51.2180246],[-4.5804201,51.2212417],[-4.5746416,51.1306736],[-4.7174993,51.1280545],[-4.7213517,51.2180246]],[[-5.1608796,55.4153626],[-5.0045387,55.4190069],[-5.0184798,55.6153521],[-5.1755648,55.6138137],[-5.1608796,55.4153626]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLS-OS-25inch-hist","name":"NLS - OS 25-inch (Scotland), 1892-1905","type":"tms","template":"http://geo.nls.uk/mapdata2/os/25_inch/scotland_1/{zoom}/{x}/{y}.png","scaleExtent":[0,18],"polygon":[[[-5.2112173,54.8018593],[-5.0642752,54.8026508],[-5.0560354,54.6305176],[-4.3158316,54.6297227],[-4.3117117,54.7448258],[-3.8530325,54.7464112],[-3.8530325,54.8034424],[-3.5522818,54.8034424],[-3.5522818,54.8374644],[-3.468511,54.8406277],[-3.4657644,54.8983158],[-3.3847403,54.8991055],[-3.3888601,54.9559214],[-3.0920786,54.9539468],[-3.0392359,54.9923274],[-3.0212713,55.0493881],[-2.9591232,55.0463283],[-2.9202807,55.0666294],[-2.7857081,55.068652],[-2.7852225,55.0914426],[-2.7337562,55.0922761],[-2.737616,55.151204],[-2.7648395,55.1510672],[-2.7013114,55.1722505],[-2.6635459,55.2192808],[-2.6460364,55.2188891],[-2.629042,55.2233933],[-2.6317886,55.2287781],[-2.6235488,55.2446345],[-2.6197723,55.2454663],[-2.6099017,55.2454174],[-2.6099876,55.2486466],[-2.6408121,55.2590039],[-2.6247896,55.2615631],[-2.6045186,55.2823081],[-2.5693176,55.296132],[-2.5479542,55.3121617],[-2.5091116,55.3234891],[-2.4780376,55.3494471],[-2.4421083,55.3533118],[-2.4052079,55.3439256],[-2.3726772,55.3447539],[-2.3221819,55.3687665],[-2.3241241,55.3999337],[-2.2576062,55.425015],[-2.1985547,55.4273529],[-2.1484296,55.4717466],[-2.1944348,55.484199],[-2.2040479,55.529306],[-2.2960584,55.6379722],[-2.2177808,55.6379722],[-2.1059266,55.7452498],[-1.9716874,55.7462161],[-1.9697453,55.9190951],[-2.1201694,55.9207115],[-2.1242893,55.9776133],[-2.3440159,55.9783817],[-2.3440159,56.0390349],[-2.5046909,56.0413363],[-2.500571,56.1003588],[-2.8823459,56.0957629],[-2.8823459,56.1722898],[-2.4126804,56.1692316],[-2.4181736,56.2334017],[-2.5857151,56.2303484],[-2.5719822,56.3416356],[-2.7257908,56.3462022],[-2.7312839,56.4343808],[-2.6928318,56.4343808],[-2.6928318,56.4859769],[-2.5307834,56.4935587],[-2.5307834,56.570806],[-2.5302878,56.6047947],[-2.3732428,56.6044452],[-2.3684363,56.7398824],[-2.3292975,56.7398824],[-2.3292975,56.7888065],[-2.3145346,56.7891826],[-2.3148779,56.7967036],[-2.171369,56.7967036],[-2.1703979,56.9710595],[-2.0101725,56.9694716],[-2.0101725,57.0846832],[-2.0817687,57.085349],[-2.0488097,57.1259963],[-2.0409133,57.126369],[-2.0383434,57.2411129],[-1.878118,57.2421638],[-1.8771469,57.2978175],[-1.9868771,57.2983422],[-1.9082209,57.3560063],[-1.8752048,57.3560063],[-1.8761758,57.3769527],[-1.8120857,57.4120111],[-1.7120661,57.4120111],[-1.7034646,57.6441388],[-1.8666032,57.6451781],[-1.8646611,57.7033351],[-3.1204292,57.7064705],[-3.1218025,57.7504652],[-3.4445259,57.7526635],[-3.4472724,57.7138067],[-3.5145637,57.7094052],[-3.5118171,57.6939956],[-3.7645027,57.6917938],[-3.7672492,57.6344975],[-3.842378,57.6288312],[-3.8438346,57.5965825],[-3.9414265,57.5916386],[-3.9404554,57.6537782],[-3.8894746,57.6529989],[-3.8826772,57.7676408],[-3.7224517,57.766087],[-3.7195385,57.8819201],[-3.9146888,57.8853352],[-3.916062,57.9546243],[-3.745774,57.9538956],[-3.7471473,58.0688409],[-3.5837256,58.0695672],[-3.5837256,58.1116689],[-3.4560096,58.1138452],[-3.4544646,58.228503],[-3.4379851,58.2283222],[-3.4243233,58.2427725],[-3.412307,58.2438567],[-3.3735115,58.2695057],[-3.3063919,58.2862038],[-3.1229154,58.2859395],[-3.123602,58.3443661],[-2.9574338,58.3447264],[-2.951254,58.6422011],[-2.8812162,58.6429157],[-2.8851004,58.8112825],[-2.7180775,58.8142997],[-2.7161354,58.8715749],[-2.556881,58.8775984],[-2.5544533,58.9923453],[-2.5567617,59.0483775],[-2.391893,59.0485996],[-2.3918002,59.1106996],[-2.4733695,59.1106996],[-2.5591563,59.1783028],[-2.5630406,59.2210646],[-2.3921334,59.224046],[-2.3911409,59.2740075],[-2.3639512,59.2745036],[-2.3658933,59.285417],[-2.3911409,59.284921],[-2.3911409,59.3379505],[-2.2221759,59.3381981],[-2.2233897,59.395965],[-2.3758467,59.396583],[-2.3899271,59.4026383],[-2.4008516,59.3962122],[-2.5637882,59.3952604],[-2.5637882,59.3385811],[-2.7320164,59.3375306],[-2.7333896,59.3952604],[-3.0726511,59.3931174],[-3.0703404,59.3354759],[-3.0753186,59.3355634],[-3.0749753,59.3292593],[-3.0698254,59.3289091],[-3.069801,59.2196159],[-3.2363384,59.2166341],[-3.2336751,59.1606496],[-3.4032766,59.1588895],[-3.394086,58.9279316],[-3.5664497,58.9259268],[-3.5611089,58.8679885],[-3.392508,58.8699339],[-3.3894734,58.8698711],[-3.3891093,58.8684905],[-3.3912942,58.868616],[-3.3884161,58.7543084],[-3.2238208,58.7555677],[-3.2189655,58.691289],[-3.4634113,58.6905753],[-3.4551716,58.6341518],[-3.787508,58.6341518],[-3.7861347,58.5769211],[-3.9028645,58.5733411],[-3.9028645,58.6477304],[-4.0690327,58.6491594],[-4.0690327,58.5912376],[-4.7364521,58.5933845],[-4.7364521,58.6505884],[-5.0715351,58.6520173],[-5.0654779,58.5325854],[-5.2332047,58.5316087],[-5.2283494,58.4719947],[-5.2424298,58.4719947],[-5.2366034,58.4089731],[-5.2283494,58.4094818],[-5.2210664,58.3005859],[-5.5657939,58.2959933],[-5.5580254,58.2372573],[-5.4146722,58.2401326],[-5.4141866,58.2267768],[-5.3885749,58.2272242],[-5.382714,58.1198615],[-5.51043,58.1191362],[-5.5114011,58.006214],[-5.6745397,58.0041559],[-5.6716266,57.9449366],[-5.6716266,57.8887166],[-5.8347652,57.8856193],[-5.8277052,57.5988958],[-6.0384259,57.5986357],[-6.0389115,57.6459559],[-6.1981658,57.6456961],[-6.2076123,57.7600132],[-6.537067,57.7544033],[-6.5312406,57.6402392],[-6.7002056,57.6360809],[-6.6807844,57.5236293],[-6.8516915,57.5152857],[-6.8361545,57.3385811],[-6.6730158,57.3438213],[-6.674958,57.2850883],[-6.5098772,57.2850883],[-6.4982244,57.1757637],[-6.3506228,57.1820797],[-6.3312015,57.1251969],[-6.1797156,57.1230884],[-6.1719471,57.0682265],[-6.4593819,57.059779],[-6.4564687,57.1093806],[-6.6671895,57.1062165],[-6.6730158,57.002708],[-6.5021087,57.0048233],[-6.4836097,56.8917522],[-6.3266104,56.8894062],[-6.3156645,56.7799312],[-6.2146739,56.775675],[-6.2146739,56.7234965],[-6.6866107,56.7224309],[-6.6769001,56.6114413],[-6.8419809,56.607166],[-6.8400387,56.5483307],[-7.1546633,56.5461895],[-7.1488369,56.4872592],[-6.9915246,56.490476],[-6.9876404,56.4325329],[-6.6827265,56.4314591],[-6.6769001,56.5472601],[-6.5292985,56.5504717],[-6.5234721,56.4379018],[-6.3661598,56.4368281],[-6.3642177,56.3766524],[-6.5273563,56.3712749],[-6.5171745,56.2428427],[-6.4869621,56.247421],[-6.4869621,56.1893882],[-6.3001945,56.1985572],[-6.3029411,56.2581017],[-5.9019401,56.256576],[-5.8964469,56.0960466],[-6.0282829,56.0883855],[-6.0392692,56.1557502],[-6.3853385,56.1542205],[-6.3606193,55.96099],[-6.2123039,55.9640647],[-6.2047508,55.9202269],[-6.5185478,55.9129158],[-6.5061881,55.7501763],[-6.6764762,55.7409005],[-6.6599967,55.6263176],[-6.3551261,55.6232161],[-6.3578727,55.5689002],[-6.0392692,55.5720059],[-6.0310294,55.6247669],[-5.7398917,55.6309694],[-5.7371452,55.4569279],[-5.8964469,55.4600426],[-5.8964469,55.2789864],[-5.4350211,55.2821151],[-5.4405143,55.4506979],[-5.2867057,55.4569279],[-5.3086784,55.4070602],[-4.9735954,55.4008223],[-4.9845817,55.2038242],[-5.1493766,55.2038242],[-5.1411369,55.037337],[-5.2152946,55.0341891],[-5.2112173,54.8018593]],[[-2.1646559,60.1622059],[-1.9930299,60.1609801],[-1.9946862,60.1035151],[-2.1663122,60.104743],[-2.1646559,60.1622059]],[[-1.5360658,59.8570831],[-1.3653566,59.8559841],[-1.366847,59.7975565],[-1.190628,59.7964199],[-1.1862046,59.9695391],[-1.0078652,59.9683948],[-1.0041233,60.114145],[-0.8360832,60.1130715],[-0.834574,60.1716772],[-1.0074262,60.1727795],[-1.0052165,60.2583924],[-0.8299659,60.2572778],[-0.826979,60.3726551],[-0.6507514,60.3715381],[-0.6477198,60.4882292],[-0.9984896,60.4904445],[-0.9970279,60.546555],[-0.6425288,60.5443201],[-0.6394896,60.6606792],[-0.8148133,60.6617806],[-0.8132987,60.7196112],[-0.6383298,60.7185141],[-0.635467,60.8275393],[-0.797568,60.8285523],[-0.9941426,60.8297807],[-0.9954966,60.7782667],[-1.1670282,60.7793403],[-1.1700357,60.6646181],[-1.5222599,60.6668304],[-1.5237866,60.6084426],[-1.6975673,60.609536],[-1.7021271,60.4345249],[-1.5260578,60.4334111],[-1.5275203,60.3770719],[-1.8751127,60.3792746],[-1.8781372,60.2624647],[-1.7019645,60.2613443],[-1.7049134,60.1470532],[-1.528659,60.1459283],[-1.5360658,59.8570831]],[[-0.9847667,60.8943762],[-0.9860347,60.8361105],[-0.8078362,60.8351904],[-0.8065683,60.8934578],[-0.9847667,60.8943762]],[[-7.7696901,56.8788231],[-7.7614504,56.7608274],[-7.6009049,56.7641903],[-7.5972473,56.819332],[-7.4479894,56.8203948],[-7.4489319,56.8794098],[-7.2841369,56.8794098],[-7.2813904,57.0471152],[-7.1303283,57.0515969],[-7.1330749,57.511801],[-6.96828,57.5147514],[-6.9765198,57.6854668],[-6.8062317,57.6913392],[-6.8089782,57.8041985],[-6.6496765,57.8071252],[-6.6441833,57.8612267],[-6.3200866,57.8626878],[-6.3200866,58.1551617],[-6.1607849,58.1522633],[-6.1552917,58.20874],[-5.9850036,58.2101869],[-5.9904968,58.2680163],[-6.1497986,58.2665717],[-6.1415588,58.5557514],[-6.3173401,58.5557514],[-6.3091003,58.4983923],[-6.4876282,58.4955218],[-6.4876282,58.4423768],[-6.6606628,58.4395018],[-6.6469299,58.3819525],[-6.8117248,58.3805125],[-6.8117248,58.3286357],[-6.9792663,58.3286357],[-6.9710266,58.2694608],[-7.1413147,58.2680163],[-7.1403816,58.0358742],[-7.3020636,58.0351031],[-7.3030347,57.9774797],[-7.1379539,57.9777372],[-7.1413526,57.9202792],[-7.1398961,57.8640206],[-7.3020636,57.862471],[-7.298484,57.7442293],[-7.4509193,57.7456951],[-7.4550392,57.6899522],[-7.6186131,57.6906048],[-7.6198341,57.7456951],[-7.7901222,57.7442293],[-7.7873756,57.6855477],[-7.6222332,57.6853817],[-7.6173779,57.5712602],[-7.788285,57.5709998],[-7.7892561,57.512109],[-7.7038025,57.5115874],[-7.6999183,57.4546902],[-7.5367796,57.4552126],[-7.5348375,57.5126306],[-7.4581235,57.5131521],[-7.4552103,57.2824165],[-7.6115515,57.2845158],[-7.6144647,57.2272651],[-7.451326,57.2256881],[-7.451326,57.1103873],[-7.6164068,57.1088053],[-7.603783,56.8792358],[-7.7696901,56.8788231]],[[-1.7106618,59.5626284],[-1.5417509,59.562215],[-1.5423082,59.5037224],[-1.7112191,59.5041365],[-1.7106618,59.5626284]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLS-OS-6inch-Scotland-hist","name":"NLS - OS 6-inch Scotland 1842-82","type":"tms","template":"http://geo.nls.uk/maps/os/six_inch/{zoom}/{x}/{-y}.png","scaleExtent":[5,16],"polygon":[[[-5.2112173,54.8018593],[-5.0642752,54.8026508],[-5.0560354,54.6305176],[-4.3158316,54.6297227],[-4.3117117,54.7448258],[-3.8530325,54.7464112],[-3.8530325,54.8034424],[-3.5522818,54.8034424],[-3.5522818,54.8374644],[-3.468511,54.8406277],[-3.4657644,54.8983158],[-3.3847403,54.8991055],[-3.3888601,54.9559214],[-3.0920786,54.9539468],[-3.0392359,54.9923274],[-3.0212713,55.0493881],[-2.9591232,55.0463283],[-2.9202807,55.0666294],[-2.7857081,55.068652],[-2.7852225,55.0914426],[-2.7337562,55.0922761],[-2.737616,55.151204],[-2.7648395,55.1510672],[-2.7013114,55.1722505],[-2.6635459,55.2192808],[-2.6460364,55.2188891],[-2.629042,55.2233933],[-2.6317886,55.2287781],[-2.6235488,55.2446345],[-2.6197723,55.2454663],[-2.6099017,55.2454174],[-2.6099876,55.2486466],[-2.6408121,55.2590039],[-2.6247896,55.2615631],[-2.6045186,55.2823081],[-2.5693176,55.296132],[-2.5479542,55.3121617],[-2.5091116,55.3234891],[-2.4780376,55.3494471],[-2.4421083,55.3533118],[-2.4052079,55.3439256],[-2.3726772,55.3447539],[-2.3221819,55.3687665],[-2.3241241,55.3999337],[-2.2576062,55.425015],[-2.1985547,55.4273529],[-2.1484296,55.4717466],[-2.1944348,55.484199],[-2.2040479,55.529306],[-2.2960584,55.6379722],[-2.2177808,55.6379722],[-2.1059266,55.7452498],[-1.9716874,55.7462161],[-1.9697453,55.9190951],[-2.1201694,55.9207115],[-2.1242893,55.9776133],[-2.3440159,55.9783817],[-2.3440159,56.0390349],[-2.5046909,56.0413363],[-2.500571,56.1003588],[-2.8823459,56.0957629],[-2.8823459,56.1722898],[-2.4126804,56.1692316],[-2.4181736,56.2334017],[-2.5857151,56.2303484],[-2.5719822,56.3416356],[-2.7257908,56.3462022],[-2.7312839,56.4343808],[-2.6928318,56.4343808],[-2.6928318,56.4859769],[-2.5307834,56.4935587],[-2.5307834,56.570806],[-2.5302878,56.6047947],[-2.3732428,56.6044452],[-2.3684363,56.7398824],[-2.3292975,56.7398824],[-2.3292975,56.7888065],[-2.3145346,56.7891826],[-2.3148779,56.7967036],[-2.171369,56.7967036],[-2.1703979,56.9710595],[-2.0101725,56.9694716],[-2.0101725,57.0846832],[-2.0817687,57.085349],[-2.0488097,57.1259963],[-2.0409133,57.126369],[-2.0383434,57.2411129],[-1.878118,57.2421638],[-1.8771469,57.2978175],[-1.9868771,57.2983422],[-1.9082209,57.3560063],[-1.8752048,57.3560063],[-1.8761758,57.3769527],[-1.8120857,57.4120111],[-1.7120661,57.4120111],[-1.7034646,57.6441388],[-1.8666032,57.6451781],[-1.8646611,57.7033351],[-3.1204292,57.7064705],[-3.1218025,57.7504652],[-3.4445259,57.7526635],[-3.4472724,57.7138067],[-3.5145637,57.7094052],[-3.5118171,57.6939956],[-3.7645027,57.6917938],[-3.7672492,57.6344975],[-3.842378,57.6288312],[-3.8438346,57.5965825],[-3.9414265,57.5916386],[-3.9404554,57.6537782],[-3.8894746,57.6529989],[-3.8826772,57.7676408],[-3.7224517,57.766087],[-3.7195385,57.8819201],[-3.9146888,57.8853352],[-3.916062,57.9546243],[-3.745774,57.9538956],[-3.7471473,58.0688409],[-3.5837256,58.0695672],[-3.5837256,58.1116689],[-3.4560096,58.1138452],[-3.4544646,58.228503],[-3.4379851,58.2283222],[-3.4243233,58.2427725],[-3.412307,58.2438567],[-3.3735115,58.2695057],[-3.3063919,58.2862038],[-3.1229154,58.2859395],[-3.123602,58.3443661],[-2.9574338,58.3447264],[-2.951254,58.6422011],[-2.8812162,58.6429157],[-2.8851004,58.8112825],[-2.7180775,58.8142997],[-2.7161354,58.8715749],[-2.556881,58.8775984],[-2.5544533,58.9923453],[-2.5567617,59.0483775],[-2.391893,59.0485996],[-2.3918002,59.1106996],[-2.4733695,59.1106996],[-2.5591563,59.1783028],[-2.5630406,59.2210646],[-2.3921334,59.224046],[-2.3911409,59.2740075],[-2.3639512,59.2745036],[-2.3658933,59.285417],[-2.3911409,59.284921],[-2.3911409,59.3379505],[-2.2221759,59.3381981],[-2.2233897,59.395965],[-2.3758467,59.396583],[-2.3899271,59.4026383],[-2.4008516,59.3962122],[-2.5637882,59.3952604],[-2.5637882,59.3385811],[-2.7320164,59.3375306],[-2.7333896,59.3952604],[-3.0726511,59.3931174],[-3.0703404,59.3354759],[-3.0753186,59.3355634],[-3.0749753,59.3292593],[-3.0698254,59.3289091],[-3.069801,59.2196159],[-3.2363384,59.2166341],[-3.2336751,59.1606496],[-3.4032766,59.1588895],[-3.394086,58.9279316],[-3.5664497,58.9259268],[-3.5611089,58.8679885],[-3.392508,58.8699339],[-3.3894734,58.8698711],[-3.3891093,58.8684905],[-3.3912942,58.868616],[-3.3884161,58.7543084],[-3.2238208,58.7555677],[-3.2189655,58.691289],[-3.4634113,58.6905753],[-3.4551716,58.6341518],[-3.787508,58.6341518],[-3.7861347,58.5769211],[-3.9028645,58.5733411],[-3.9028645,58.6477304],[-4.0690327,58.6491594],[-4.0690327,58.5912376],[-4.7364521,58.5933845],[-4.7364521,58.6505884],[-5.0715351,58.6520173],[-5.0654779,58.5325854],[-5.2332047,58.5316087],[-5.2283494,58.4719947],[-5.2424298,58.4719947],[-5.2366034,58.4089731],[-5.2283494,58.4094818],[-5.2210664,58.3005859],[-5.5657939,58.2959933],[-5.5580254,58.2372573],[-5.4146722,58.2401326],[-5.4141866,58.2267768],[-5.3885749,58.2272242],[-5.382714,58.1198615],[-5.51043,58.1191362],[-5.5114011,58.006214],[-5.6745397,58.0041559],[-5.6716266,57.9449366],[-5.6716266,57.8887166],[-5.8347652,57.8856193],[-5.8277052,57.5988958],[-6.0384259,57.5986357],[-6.0389115,57.6459559],[-6.1981658,57.6456961],[-6.2076123,57.7600132],[-6.537067,57.7544033],[-6.5312406,57.6402392],[-6.7002056,57.6360809],[-6.6807844,57.5236293],[-6.8516915,57.5152857],[-6.8361545,57.3385811],[-6.6730158,57.3438213],[-6.674958,57.2850883],[-6.5098772,57.2850883],[-6.4982244,57.1757637],[-6.3506228,57.1820797],[-6.3312015,57.1251969],[-6.1797156,57.1230884],[-6.1719471,57.0682265],[-6.4593819,57.059779],[-6.4564687,57.1093806],[-6.6671895,57.1062165],[-6.6730158,57.002708],[-6.5021087,57.0048233],[-6.4836097,56.8917522],[-6.3266104,56.8894062],[-6.3156645,56.7799312],[-6.2146739,56.775675],[-6.2146739,56.7234965],[-6.6866107,56.7224309],[-6.6769001,56.6114413],[-6.8419809,56.607166],[-6.8400387,56.5483307],[-7.1546633,56.5461895],[-7.1488369,56.4872592],[-6.9915246,56.490476],[-6.9876404,56.4325329],[-6.6827265,56.4314591],[-6.6769001,56.5472601],[-6.5292985,56.5504717],[-6.5234721,56.4379018],[-6.3661598,56.4368281],[-6.3642177,56.3766524],[-6.5273563,56.3712749],[-6.5171745,56.2428427],[-6.4869621,56.247421],[-6.4869621,56.1893882],[-6.3001945,56.1985572],[-6.3029411,56.2581017],[-5.9019401,56.256576],[-5.8964469,56.0960466],[-6.0282829,56.0883855],[-6.0392692,56.1557502],[-6.3853385,56.1542205],[-6.3606193,55.96099],[-6.2123039,55.9640647],[-6.2047508,55.9202269],[-6.5185478,55.9129158],[-6.5061881,55.7501763],[-6.6764762,55.7409005],[-6.6599967,55.6263176],[-6.3551261,55.6232161],[-6.3578727,55.5689002],[-6.0392692,55.5720059],[-6.0310294,55.6247669],[-5.7398917,55.6309694],[-5.7371452,55.4569279],[-5.8964469,55.4600426],[-5.8964469,55.2789864],[-5.4350211,55.2821151],[-5.4405143,55.4506979],[-5.2867057,55.4569279],[-5.3086784,55.4070602],[-4.9735954,55.4008223],[-4.9845817,55.2038242],[-5.1493766,55.2038242],[-5.1411369,55.037337],[-5.2152946,55.0341891],[-5.2112173,54.8018593]],[[-2.1646559,60.1622059],[-1.9930299,60.1609801],[-1.9946862,60.1035151],[-2.1663122,60.104743],[-2.1646559,60.1622059]],[[-1.5360658,59.8570831],[-1.3653566,59.8559841],[-1.366847,59.7975565],[-1.190628,59.7964199],[-1.1862046,59.9695391],[-1.0078652,59.9683948],[-1.0041233,60.114145],[-0.8360832,60.1130715],[-0.834574,60.1716772],[-1.0074262,60.1727795],[-1.0052165,60.2583924],[-0.8299659,60.2572778],[-0.826979,60.3726551],[-0.6507514,60.3715381],[-0.6477198,60.4882292],[-0.9984896,60.4904445],[-0.9970279,60.546555],[-0.6425288,60.5443201],[-0.6394896,60.6606792],[-0.8148133,60.6617806],[-0.8132987,60.7196112],[-0.6383298,60.7185141],[-0.635467,60.8275393],[-0.797568,60.8285523],[-0.9941426,60.8297807],[-0.9954966,60.7782667],[-1.1670282,60.7793403],[-1.1700357,60.6646181],[-1.5222599,60.6668304],[-1.5237866,60.6084426],[-1.6975673,60.609536],[-1.7021271,60.4345249],[-1.5260578,60.4334111],[-1.5275203,60.3770719],[-1.8751127,60.3792746],[-1.8781372,60.2624647],[-1.7019645,60.2613443],[-1.7049134,60.1470532],[-1.528659,60.1459283],[-1.5360658,59.8570831]],[[-0.9847667,60.8943762],[-0.9860347,60.8361105],[-0.8078362,60.8351904],[-0.8065683,60.8934578],[-0.9847667,60.8943762]],[[-7.7696901,56.8788231],[-7.7614504,56.7608274],[-7.6009049,56.7641903],[-7.5972473,56.819332],[-7.4479894,56.8203948],[-7.4489319,56.8794098],[-7.2841369,56.8794098],[-7.2813904,57.0471152],[-7.1303283,57.0515969],[-7.1330749,57.511801],[-6.96828,57.5147514],[-6.9765198,57.6854668],[-6.8062317,57.6913392],[-6.8089782,57.8041985],[-6.6496765,57.8071252],[-6.6441833,57.8612267],[-6.3200866,57.8626878],[-6.3200866,58.1551617],[-6.1607849,58.1522633],[-6.1552917,58.20874],[-5.9850036,58.2101869],[-5.9904968,58.2680163],[-6.1497986,58.2665717],[-6.1415588,58.5557514],[-6.3173401,58.5557514],[-6.3091003,58.4983923],[-6.4876282,58.4955218],[-6.4876282,58.4423768],[-6.6606628,58.4395018],[-6.6469299,58.3819525],[-6.8117248,58.3805125],[-6.8117248,58.3286357],[-6.9792663,58.3286357],[-6.9710266,58.2694608],[-7.1413147,58.2680163],[-7.1403816,58.0358742],[-7.3020636,58.0351031],[-7.3030347,57.9774797],[-7.1379539,57.9777372],[-7.1413526,57.9202792],[-7.1398961,57.8640206],[-7.3020636,57.862471],[-7.298484,57.7442293],[-7.4509193,57.7456951],[-7.4550392,57.6899522],[-7.6186131,57.6906048],[-7.6198341,57.7456951],[-7.7901222,57.7442293],[-7.7873756,57.6855477],[-7.6222332,57.6853817],[-7.6173779,57.5712602],[-7.788285,57.5709998],[-7.7892561,57.512109],[-7.7038025,57.5115874],[-7.6999183,57.4546902],[-7.5367796,57.4552126],[-7.5348375,57.5126306],[-7.4581235,57.5131521],[-7.4552103,57.2824165],[-7.6115515,57.2845158],[-7.6144647,57.2272651],[-7.451326,57.2256881],[-7.451326,57.1103873],[-7.6164068,57.1088053],[-7.603783,56.8792358],[-7.7696901,56.8788231]],[[-1.7106618,59.5626284],[-1.5417509,59.562215],[-1.5423082,59.5037224],[-1.7112191,59.5041365],[-1.7106618,59.5626284]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLSC-EMAP5","name":"NLSC General Map with Contour line","type":"tms","template":"http://maps.nlsc.gov.tw/S_Maps/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=EMAP5_OPENDATA&STYLE=_null&TILEMATRIXSET=EPSG:3857&TILEMATRIX=EPSG:3857:{zoom}&TILEROW={y}&TILECOL={x}&FORMAT=image/png","description":"The emap from Taiwan National Land Surveying and Mapping Center","scaleExtent":[0,15],"polygon":[[[120.4570579,26.3970586],[120.44256,26.3708009],[120.44713,26.3531513],[120.4673009,26.3405831],[120.4978723,26.3340866],[120.5141036,26.3401594],[120.5341168,26.3641649],[120.5297045,26.3842128],[120.4956661,26.4015754],[120.4570579,26.3970586]],[[119.9007221,25.9858609],[119.8960071,25.9648902],[119.9131301,25.9470399],[119.9503542,25.9278478],[119.9905563,25.9260623],[120.0198392,25.9363284],[120.0277804,25.9557423],[120.0275322,25.9845224],[119.9989937,26.0010288],[119.9404278,26.0028131],[119.9007221,25.9858609]],[[122.089,24.5485],[121.709,23.4541],[121.717,22.698],[121.818,21.95],[121.803,21.8735],[121.759,21.8087],[121.694,21.7653],[120.861,21.5631],[120.815,21.5576],[120.739,21.5728],[120.661,21.6296],[120.202,22.1809],[119.27,23.0542],[119.153,23.2049],[119.128,23.2485],[119.103,23.4],[119.118,23.4765],[119.137,23.512],[119.361,23.8885],[119.406,23.9407],[120.968,25.2284],[121.408,25.4687],[121.989,25.8147],[122.065,25.8299],[122.141,25.8147],[122.216,25.7663],[122.26,25.7015],[122.297,25.48],[122.196,24.9696],[122.089,24.5485]],[[116.6855033,20.8547596],[116.6309071,20.8149565],[116.5941695,20.7600846],[116.5797214,20.6967501],[116.5893056,20.6325865],[116.621766,20.5753367],[116.6731874,20.5319171],[116.7373678,20.5075783],[116.8065659,20.5052653],[116.8724354,20.5252581],[116.9270316,20.5651373],[116.9637692,20.6200797],[116.9782173,20.6834462],[116.9686331,20.7475883],[116.9361727,20.8047732],[116.8847512,20.8481147],[116.8205709,20.872399],[116.7513728,20.8747063],[116.6855033,20.8547596]],[[118.2261504,24.4563345],[118.2936439,24.4538527],[118.2851467,24.4751026],[118.3097372,24.4916821],[118.3767709,24.4729348],[118.4100947,24.5332285],[118.4479031,24.5284069],[118.4746394,24.4599272],[118.512992,24.4315479],[118.5065839,24.4202318],[118.4811625,24.4332439],[118.4610567,24.4089192],[118.426145,24.3970385],[118.3970055,24.4284184],[118.3765564,24.4258395],[118.3397565,24.3814628],[118.3031926,24.3705764],[118.2574234,24.4139213],[118.1381276,24.3724838],[118.1617342,24.4022433],[118.2094226,24.4139604],[118.1895784,24.4352201],[118.2176338,24.430205],[118.2261504,24.4563345]],[[120.2234496,26.30045],[120.2550843,26.3100412],[120.269888,26.3368716],[120.2591889,26.3652192],[120.2292544,26.3784823],[120.1976197,26.3688968],[120.182816,26.3420738],[120.1935151,26.3137205],[120.2234496,26.30045]],[[119.4374461,25.0047541],[119.4342024,24.9886249],[119.4541901,24.9722553],[119.4827444,24.9718376],[119.4898402,24.9937882],[119.4715877,25.0069239],[119.4374461,25.0047541]],[[119.8869914,26.180381],[119.893227,26.1203128],[119.9285109,26.1080224],[119.9779388,26.1223611],[120.0366775,26.151728],[120.1098054,26.2134921],[120.119269,26.2713663],[120.0629175,26.3172592],[119.9923706,26.3164881],[119.9467732,26.2898799],[119.9020362,26.2439761],[119.8869914,26.180381]]],"terms_url":"http://maps.nlsc.gov.tw/","terms_text":"NLSC EMAP 2015"},{"id":"MAPNIK","name":"OpenStreetMap (Standard)","type":"tms","template":"https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png","description":"The default OpenStreetMap layer.","scaleExtent":[0,19],"terms_url":"https://openstreetmap.org/","terms_text":"© OpenStreetMap contributors, CC-BY-SA","default":true},{"id":"OpenStreetMap-turistautak","name":"OpenStreetMap (turistautak)","type":"tms","template":"http://{switch:h,i,j}.tile.openstreetmap.hu/turistautak/{zoom}/{x}/{y}.png","scaleExtent":[0,18],"polygon":[[[16.1139147,46.8691038],[16.1789749,46.90662],[16.2000429,46.9415079],[16.2217547,46.9355441],[16.2462784,46.9463851],[16.2553226,46.9642125],[16.2764694,46.9626082],[16.290583,47.0139849],[16.3016199,46.9992329],[16.3414618,46.9965225],[16.3505162,47.0106313],[16.3734016,46.9985929],[16.412765,47.00475],[16.4332705,46.9927417],[16.4478119,47.003893],[16.479997,46.9941169],[16.5121988,47.0011695],[16.4635584,47.0322699],[16.4478586,47.0227481],[16.439123,47.029663],[16.445673,47.038872],[16.520323,47.056103],[16.473213,47.0736169],[16.4637199,47.09392],[16.500798,47.110058],[16.500035,47.123295],[16.5295349,47.1287419],[16.5171609,47.1496938],[16.454951,47.1425878],[16.4648728,47.1683349],[16.4555643,47.1875584],[16.4305559,47.1847022],[16.4195013,47.1949147],[16.4189215,47.2107114],[16.4371293,47.2097043],[16.4426335,47.2337117],[16.4313127,47.2527554],[16.4671512,47.2531652],[16.4892319,47.2798885],[16.4646338,47.3338455],[16.4337002,47.3528101],[16.458513,47.3670496],[16.4454619,47.4070195],[16.4831657,47.4093628],[16.4963821,47.3892659],[16.5170941,47.4100218],[16.5749054,47.4054243],[16.5807291,47.4191699],[16.661847,47.455595],[16.6706419,47.47422],[16.6523395,47.500342],[16.6895619,47.510161],[16.7147797,47.540199],[16.663545,47.567733],[16.673199,47.6049544],[16.6595343,47.6061018],[16.652758,47.622852],[16.6314207,47.6283176],[16.5739108,47.619667],[16.5147382,47.6461964],[16.4967504,47.6393149],[16.425464,47.6621679],[16.4437449,47.674205],[16.4480507,47.6964725],[16.4746984,47.6811576],[16.4872245,47.6979767],[16.5521729,47.7225519],[16.5363779,47.736785],[16.5479799,47.751544],[16.6095193,47.7603722],[16.6344148,47.7590843],[16.65729,47.7414879],[16.7209405,47.7353565],[16.7534062,47.6828165],[16.8301587,47.681058],[16.8394284,47.7045139],[16.8668943,47.7211462],[16.876679,47.6876452],[17.0937421,47.7077706],[17.0706562,47.7285366],[17.0516019,47.7938499],[17.0749479,47.8084997],[17.047139,47.8285635],[17.0519452,47.8377691],[17.0105513,47.8581765],[17.0163878,47.8673325],[17.0857537,47.8746239],[17.113171,47.9271605],[17.0917133,47.9342916],[17.1183782,47.9601083],[17.094657,47.9708775],[17.2010289,48.019992],[17.241769,48.0224651],[17.257955,47.998655],[17.334651,47.993125],[17.4029929,47.947849],[17.4539199,47.8852579],[17.5267369,47.865509],[17.5675779,47.8151289],[17.608402,47.8218859],[17.7085789,47.756678],[17.7798739,47.739487],[17.8660959,47.74575],[17.9001292,47.7392633],[17.946867,47.744668],[17.9708709,47.7578392],[18.0044103,47.7463402],[18.0380583,47.7576812],[18.2958774,47.7314616],[18.4540681,47.7651226],[18.4931553,47.7527552],[18.5590761,47.7659963],[18.6460866,47.7590921],[18.7260691,47.7890411],[18.7411784,47.8138245],[18.7920013,47.8230869],[18.8485417,47.8167221],[18.855876,47.826077],[18.828014,47.834291],[18.8135749,47.85555],[18.76353,47.8716049],[18.756858,47.896838],[18.776746,47.955092],[18.7552499,47.9763469],[18.8157429,47.993442],[18.819998,48.039676],[18.833268,48.048239],[18.8749364,48.0470707],[18.886674,48.058682],[18.9089819,48.051139],[18.9439039,48.058865],[18.9816099,48.0536009],[19.0148639,48.078179],[19.0585249,48.0573529],[19.0843619,48.072781],[19.107402,48.065596],[19.1352889,48.074146],[19.2413679,48.0536529],[19.2557819,48.0715559],[19.3031119,48.088711],[19.3865969,48.091914],[19.400018,48.082304],[19.454053,48.101436],[19.467354,48.083933],[19.4944199,48.109906],[19.492377,48.1396639],[19.5128219,48.154663],[19.504518,48.173443],[19.528967,48.190358],[19.526044,48.20313],[19.577502,48.2160149],[19.6308263,48.2500725],[19.6445239,48.2391719],[19.669857,48.239212],[19.691219,48.203894],[19.721125,48.201473],[19.74618,48.2165119],[19.7871629,48.19253],[19.7987329,48.19482],[19.8052829,48.183733],[19.782415,48.165039],[19.794812,48.153529],[19.821331,48.169081],[19.8452819,48.162742],[19.8551729,48.178431],[19.8601309,48.169409],[19.898745,48.1663119],[19.9145359,48.146863],[19.898298,48.1249019],[19.937383,48.131118],[19.9743939,48.1660049],[19.988706,48.1621679],[20.029038,48.1776849],[20.049449,48.1671999],[20.0729859,48.179606],[20.0700369,48.1917019],[20.1340909,48.225182],[20.1331879,48.253982],[20.206162,48.250979],[20.2038299,48.261906],[20.228466,48.262779],[20.2349469,48.279933],[20.286858,48.26164],[20.3257109,48.272794],[20.3374649,48.301667],[20.3656579,48.316606],[20.384077,48.3511809],[20.4098349,48.365857],[20.402532,48.382565],[20.4205349,48.403858],[20.416228,48.418536],[20.507929,48.489363],[20.5065069,48.534415],[20.537471,48.527878],[20.5464939,48.544292],[20.586595,48.535759],[20.6538739,48.561413],[20.836359,48.58284],[20.8378,48.57421],[20.8504359,48.5816329],[20.8453301,48.5665046],[20.8681549,48.551818],[20.922323,48.559453],[20.9346349,48.538341],[20.955882,48.533963],[20.9561979,48.521666],[20.9815849,48.5177669],[21.0151139,48.532313],[21.0663209,48.525894],[21.1174479,48.4910549],[21.1608749,48.521499],[21.179634,48.518232],[21.221061,48.537497],[21.305488,48.5222489],[21.313377,48.550841],[21.326875,48.554129],[21.319384,48.561201],[21.4154499,48.558951],[21.4226649,48.578821],[21.4406099,48.585104],[21.514091,48.551065],[21.5420199,48.508395],[21.6139329,48.509416],[21.6201879,48.469826],[21.663549,48.417961],[21.6645609,48.392164],[21.7017409,48.380695],[21.711871,48.357617],[21.8174139,48.332787],[21.8352029,48.3346409],[21.837213,48.363253],[21.8842979,48.356047],[21.8848429,48.367539],[21.897883,48.36256],[21.8997959,48.3702229],[21.9281859,48.3615969],[21.9268059,48.370899],[21.949198,48.378728],[21.994463,48.377323],[22.0213259,48.392749],[22.0546049,48.377528],[22.0764859,48.387241],[22.086743,48.371564],[22.1359089,48.380519],[22.131056,48.3912329],[22.152768,48.3962409],[22.1561913,48.4093076],[22.2125722,48.4256468],[22.2371405,48.4100396],[22.2654858,48.4098675],[22.2398761,48.3870055],[22.2675722,48.3611612],[22.3178106,48.3545437],[22.3132861,48.3250712],[22.3372944,48.3079113],[22.3384267,48.2792074],[22.3847547,48.2339632],[22.4006407,48.249198],[22.4328384,48.2525166],[22.456386,48.2423109],[22.4899029,48.2534237],[22.4972201,48.2395546],[22.5161491,48.237965],[22.5311088,48.2094282],[22.5711442,48.1961428],[22.5616362,48.1816066],[22.5982449,48.144756],[22.5902763,48.1073414],[22.6754492,48.091997],[22.7347192,48.119848],[22.7576242,48.1200599],[22.7703914,48.1090162],[22.772319,48.1218742],[22.8027688,48.1221112],[22.8025285,48.1070813],[22.8254256,48.1175119],[22.8364365,48.080249],[22.8611284,48.0750312],[22.8677955,48.0524256],[22.8820424,48.0548053],[22.8659692,48.0113165],[22.835562,47.9905988],[22.8407599,47.9813636],[22.8725729,47.9752683],[22.8697274,47.9659593],[22.8915652,47.9672446],[22.897435,47.9540629],[22.8473299,47.9077579],[22.7928135,47.8908586],[22.7586924,47.8941446],[22.77775,47.8422508],[22.7136344,47.8360928],[22.6801938,47.7877527],[22.6111171,47.7717455],[22.5490018,47.7722246],[22.4812121,47.8108886],[22.4513078,47.803389],[22.4313319,47.7398119],[22.3566167,47.7486206],[22.3177714,47.7660887],[22.3176236,47.7433657],[22.2851369,47.7292757],[22.264325,47.7310675],[22.2589955,47.6979057],[22.2306796,47.693196],[22.1796501,47.5916115],[22.1289245,47.5978984],[22.0942787,47.5583628],[22.0782587,47.5621299],[22.0534529,47.5474795],[22.0712176,47.5380742],[22.0617872,47.5288029],[22.0451278,47.5398919],[22.0367222,47.5326653],[22.0071886,47.48362],[22.0327909,47.4508372],[22.0238835,47.3908631],[22.0119849,47.3758016],[21.9627373,47.381053],[21.9382461,47.3725317],[21.8777922,47.2857763],[21.8872845,47.2730473],[21.8534909,47.2397622],[21.8580662,47.1873597],[21.8124804,47.1667511],[21.7924092,47.1059751],[21.7268258,47.0983882],[21.6976037,47.057915],[21.6504151,47.0408303],[21.6888701,47.0019977],[21.6678744,46.9712337],[21.6814917,46.9652089],[21.6381964,46.9330487],[21.5984455,46.9274708],[21.6142857,46.8867275],[21.6016694,46.8668202],[21.520328,46.8373749],[21.5186086,46.8000703],[21.4831761,46.7650246],[21.5263389,46.7393249],[21.529369,46.7209721],[21.4923253,46.6859652],[21.4728438,46.6959075],[21.4299047,46.693937],[21.4309553,46.6781367],[21.4546661,46.660863],[21.4162375,46.6426231],[21.4097959,46.6218052],[21.3657038,46.6379501],[21.3300499,46.6318155],[21.3139733,46.617666],[21.3012351,46.5908672],[21.3207905,46.5828562],[21.2743045,46.5407362],[21.2600254,46.5021583],[21.2744188,46.4767333],[21.2964506,46.4762973],[21.3174343,46.4507288],[21.2895176,46.4154784],[21.2963256,46.4069601],[21.2250116,46.4136899],[21.2064214,46.4033825],[21.1992563,46.3479034],[21.1762269,46.3357664],[21.180497,46.3044494],[21.1155437,46.3018529],[21.1030549,46.2624637],[21.0708792,46.2539014],[21.0660827,46.2429394],[21.0366237,46.2480392],[21.0246723,46.2665329],[20.960817,46.2623039],[20.9465849,46.2793024],[20.9250701,46.2766191],[20.9218133,46.2618129],[20.8732713,46.2877555],[20.7756538,46.2759602],[20.7490474,46.2508489],[20.7618619,46.204563],[20.727401,46.2077485],[20.7341052,46.1939355],[20.7140487,46.1660531],[20.6843592,46.1447802],[20.6549178,46.1497739],[20.6394471,46.1267602],[20.5450486,46.1790935],[20.5014839,46.190334],[20.4949436,46.1709908],[20.4592293,46.1428837],[20.3975133,46.1574709],[20.3685325,46.1528554],[20.3557074,46.1696256],[20.2968136,46.1521542],[20.2549024,46.1158522],[20.2484757,46.1300956],[20.2330132,46.1241668],[20.1817362,46.1601137],[20.1364966,46.1449476],[20.1009667,46.1772756],[20.0636156,46.1437275],[20.0346142,46.1458888],[20.0158072,46.1768354],[19.9354075,46.1764243],[19.8533469,46.1500005],[19.8179747,46.1281652],[19.7585403,46.1479754],[19.6982054,46.1879317],[19.6827672,46.1800388],[19.661508,46.1904394],[19.6317396,46.1692993],[19.5676482,46.179106],[19.5604013,46.1665762],[19.5026585,46.1424492],[19.5271208,46.1210269],[19.4645033,46.0953827],[19.4665828,46.0820437],[19.4160037,46.0460453],[19.3803957,46.0358749],[19.3640923,46.0522965],[19.2819012,46.0148048],[19.2965348,45.9881173],[19.2856472,45.9968981],[19.1479857,45.9963445],[19.1338422,46.0370993],[19.104873,46.0401673],[19.0660427,46.0001999],[19.0796791,45.9636376],[19.0059803,45.9590674],[19.0092745,45.9236559],[18.9061334,45.9353801],[18.8794572,45.9166827],[18.8647137,45.9208493],[18.8685629,45.9113361],[18.8276792,45.9051714],[18.8220041,45.9145893],[18.8075092,45.9036055],[18.809247,45.8796189],[18.7956242,45.8784488],[18.7048857,45.9181883],[18.6700246,45.9108439],[18.6596602,45.9168934],[18.6651348,45.899279],[18.6412808,45.8890396],[18.6550179,45.8742393],[18.6277704,45.8733782],[18.6148449,45.8531438],[18.6236656,45.8398531],[18.5732391,45.8137578],[18.5749849,45.8004344],[18.559716,45.8037961],[18.5223504,45.7826858],[18.4906706,45.7947167],[18.4821905,45.7655032],[18.4562828,45.7695229],[18.4450763,45.7605195],[18.446853,45.737128],[18.40763,45.7397119],[18.3918949,45.7616983],[18.3642257,45.7729364],[18.3394214,45.7471605],[18.2968157,45.7612196],[18.2440473,45.7612305],[18.2307311,45.7790328],[18.1908702,45.7878759],[18.1681939,45.7762712],[18.1246514,45.7896277],[18.1068067,45.7708256],[18.0818922,45.7645205],[17.9958808,45.7957311],[17.9302095,45.7863301],[17.9066757,45.7925692],[17.8653145,45.7670064],[17.8262748,45.8099957],[17.8089784,45.8040989],[17.7809054,45.8174884],[17.7603399,45.811923],[17.7408624,45.8295975],[17.6632915,45.8381849],[17.6276211,45.8979446],[17.5700676,45.9358204],[17.4378254,45.9503823],[17.4258964,45.9272681],[17.4108059,45.9399665],[17.392149,45.9302149],[17.3828713,45.9475733],[17.3476208,45.9423413],[17.3438769,45.9605329],[17.3537711,45.9525011],[17.3905375,45.9581914],[17.387423,45.9661823],[17.3583539,45.9642737],[17.3754852,45.9686921],[17.3751895,45.9881054],[17.3635685,45.9915442],[17.3567202,45.9735836],[17.3339583,45.9960781],[17.3319847,45.9728948],[17.3129974,45.9665347],[17.323647,45.9887776],[17.2987653,45.9838652],[17.3041996,46.0021128],[17.2579726,46.0110256],[17.29632,46.0285169],[17.2541514,46.030005],[17.270955,46.0567055],[17.2324767,46.0592034],[17.2525145,46.0664725],[17.2313144,46.0790345],[17.2019916,46.0765488],[17.2331299,46.0989644],[17.2104017,46.1001693],[17.2129734,46.113855],[17.175927,46.1084583],[17.1743424,46.1287608],[17.1865197,46.1332308],[17.1810983,46.1505485],[17.1562307,46.1585819],[17.1592857,46.1696818],[17.1261012,46.1684495],[17.1227409,46.1789791],[17.0752482,46.1889531],[17.0661614,46.2022984],[16.9735401,46.2251982],[16.973954,46.2431113],[16.9504085,46.2415285],[16.8862356,46.2814598],[16.8713682,46.3252767],[16.8802109,46.3356966],[16.8615374,46.3452401],[16.8656232,46.3556489],[16.8521959,46.3517189],[16.8498589,46.3626245],[16.8352859,46.3638195],[16.8376499,46.3748032],[16.8261732,46.3670994],[16.7933444,46.387385],[16.7592072,46.3776563],[16.7298672,46.40149],[16.7182119,46.3898704],[16.6772872,46.4494536],[16.6631785,46.4486958],[16.6663732,46.4582995],[16.6187915,46.4619875],[16.604468,46.4760773],[16.5235997,46.5053761],[16.5325768,46.5314027],[16.5176728,46.5363516],[16.5084107,46.5652692],[16.4829969,46.5660383],[16.4834008,46.5786011],[16.4455713,46.610952],[16.4248583,46.6131645],[16.385941,46.6442485],[16.3915424,46.6637257],[16.4198454,46.6584771],[16.4286335,46.6939737],[16.3689211,46.7040082],[16.3798266,46.7153869],[16.3710856,46.7222945],[16.3570587,46.7142387],[16.3185954,46.7541449],[16.3305417,46.7752119],[16.3121626,46.7780033],[16.3127666,46.797314],[16.3406373,46.8051851],[16.3508404,46.8300552],[16.3403309,46.8468762],[16.3015007,46.8595142],[16.2913867,46.8728341],[16.2332296,46.8766702],[16.1560866,46.8537074],[16.126571,46.8569079],[16.1139147,46.8691038]]],"terms_url":"http://openstreetmap.hu/","terms_text":"OpenStreetMap.hu"},{"id":"osm-gps","name":"OpenStreetMap GPS traces","type":"tms","template":"http://{switch:a,b,c}.gps-tile.openstreetmap.org/lines/{zoom}/{x}/{y}.png","description":"Public GPS traces uploaded to OpenStreetMap.","scaleExtent":[0,20],"terms_url":"http://www.openstreetmap.org/copyright","terms_text":"© OpenStreetMap contributors","terms_html":"<span style='display: inline-block; padding: 0 8px; background-color: rgba(0,0,0,0.5);'><span style='color: #eee;'>GPS Direction:</span> <span style='font-size: 15px; padding-left: 2px; font-weight: bold;'> <span style='color: #0ee;'>&larr;</span> <span style='color: #96f;'>&darr;</span> <span style='color: #6e0;'>&uarr;</span> <span style='color: #f63;'>&rarr;</span> </span></span> © <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap contributors</a>.","overlay":true},{"id":"lu.geoportail.opendata.ortho2010","name":"Ortho 2010 geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/ortho_2010/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.jpeg","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/bd-l-ortho-webservices-wms-et-wmts","terms_text":"Administration du Cadastre et de la Topographie"},{"id":"lu.geoportail.opendata.ortho2013","name":"Ortho 2013 geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/ortho_2013/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.jpeg","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/bd-l-ortho-webservices-wms-et-wmts","terms_text":"Administration du Cadastre et de la Topographie"},{"id":"lu.geoportail.opendata.ortho2016","name":"Ortho 2016 geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/ortho_2016/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.jpeg","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/bd-l-ortho-webservices-wms-et-wmts","terms_text":"Administration du Cadastre et de la Topographie","best":true},{"id":"OS-historic-25k-OSM_Limited","name":"OS 1:25k historic (OSM)","type":"tms","template":"http://ooc.openstreetmap.org/os1/{zoom}/{x}/{y}.jpg","scaleExtent":[6,17],"polygon":[[[-6.4585407,49.9044128],[-6.3872009,49.9841116],[-6.2296827,49.9896159],[-6.2171269,49.8680087],[-6.4551164,49.8591793],[-6.4585407,49.9044128]],[[-1.4495137,60.8634056],[-0.7167114,60.8545122],[-0.7349744,60.4359756],[-0.6938826,60.4168218],[-0.7258429,60.3942735],[-0.7395401,60.0484714],[-0.9267357,60.0461918],[-0.9381501,59.8266157],[-1.4586452,59.831205],[-1.4455187,60.0535999],[-1.463211,60.0535999],[-1.4643524,60.0630002],[-1.5716475,60.0638546],[-1.5693646,60.1790005],[-1.643558,60.1807033],[-1.643558,60.1892162],[-1.8216221,60.1894999],[-1.8204807,60.3615507],[-1.8415973,60.3697345],[-1.8216221,60.3832755],[-1.8179852,60.5934321],[-1.453168,60.5934321],[-1.4495137,60.8634056]],[[-4.9089213,54.4242078],[-4.282598,54.4429861],[-4.2535417,54.029769],[-4.8766366,54.0221831],[-4.9089213,54.4242078]],[[-5.8667408,59.1444603],[-5.7759966,59.1470945],[-5.7720016,59.1014052],[-5.8621751,59.0990605],[-5.8667408,59.1444603]],[[-1.7065887,59.5703599],[-1.5579165,59.5693481],[-1.5564897,59.4965695],[-1.7054472,59.4975834],[-1.7065887,59.5703599]],[[-7.6865827,58.2940975],[-7.5330594,58.3006957],[-7.5256401,58.2646905],[-7.6797341,58.2577853],[-7.6865827,58.2940975]],[[-4.5338281,59.0359871],[-4.481322,59.0371616],[-4.4796099,59.0186583],[-4.5332574,59.0180707],[-4.5338281,59.0359871]],[[-8.6710698,57.8769896],[-8.4673234,57.8897332],[-8.4467775,57.7907],[-8.6510947,57.7779213],[-8.6710698,57.8769896]],[[-5.2395519,50.3530581],[-5.7920073,50.3384899],[-5.760047,49.9317027],[-4.6551363,49.9581461],[-4.677965,50.2860073],[-4.244219,50.2801723],[-4.2487848,50.2042525],[-3.3812929,50.2042525],[-3.4223846,50.5188201],[-3.1164796,50.5246258],[-3.1210453,50.6579592],[-2.6736357,50.6619495],[-2.5953453,50.6394325],[-2.5905026,50.5728419],[-2.4791203,50.5733545],[-2.4758919,50.5066704],[-2.3967943,50.5056438],[-2.401637,50.5723293],[-1.0400296,50.5718167],[-1.0335726,50.7059289],[-0.549302,50.7038843],[-0.5460736,50.7886618],[-0.0924734,50.7856002],[-0.0876307,50.7181949],[0.4789659,50.7120623],[0.487037,50.8182467],[0.9761503,50.8049868],[0.9922927,51.0126311],[1.4491213,51.0004424],[1.4781775,51.4090372],[1.0229632,51.4271576],[1.035877,51.7640881],[1.6105448,51.7500992],[1.646058,52.1560003],[1.7267698,52.1540195],[1.749369,52.4481811],[1.7870672,52.4811624],[1.759102,52.522505],[1.7933451,52.9602749],[0.3798147,52.9958468],[0.3895238,53.2511239],[0.3478614,53.2511239],[0.3238912,53.282186],[0.3461492,53.6538501],[0.128487,53.6575466],[0.116582,53.6674703],[0.1350586,54.0655731],[-0.0609831,54.065908],[-0.0414249,54.4709448],[-0.5662701,54.4771794],[-0.5592078,54.6565127],[-1.1665638,54.6623485],[-1.1637389,54.842611],[-1.3316194,54.843909],[-1.3257065,55.2470842],[-1.529453,55.2487108],[-1.524178,55.6540122],[-1.7638798,55.6540122],[-1.7733693,55.9719116],[-2.1607858,55.9682981],[-2.1543289,56.0621387],[-2.4578051,56.0585337],[-2.4190635,56.641717],[-2.0962164,56.641717],[-2.0833025,57.0021322],[-1.9283359,57.0126802],[-1.9180966,57.3590895],[-1.7502161,57.3625721],[-1.7695869,57.7608634],[-3.6937554,57.7574187],[-3.7066693,57.9806386],[-3.5969013,57.9772149],[-3.6033582,58.1207277],[-3.0222335,58.1309566],[-3.0286905,58.5410788],[-2.8478961,58.530968],[-2.86081,58.8430508],[-2.679624,58.8414991],[-2.6841897,58.885175],[-2.6339665,58.9052239],[-2.679624,58.9335083],[-2.6887555,59.0229231],[-2.3668703,59.0229231],[-2.3702946,59.2652861],[-2.3429001,59.2821989],[-2.3714361,59.2996861],[-2.3737189,59.3707083],[-2.3429001,59.385825],[-2.3725775,59.400354],[-2.3714361,59.4259098],[-3.0734196,59.4230067],[-3.0711368,59.3433649],[-3.103097,59.3311405],[-3.0745611,59.3136695],[-3.0722782,59.232603],[-3.3850319,59.1484167],[-3.3747589,58.9352753],[-3.5653789,58.9323303],[-3.554829,58.69759],[-5.2808579,58.6667732],[-5.2534159,58.3514125],[-5.5068508,58.3437887],[-5.4761804,58.0323557],[-5.8974958,58.0212436],[-5.8522972,57.6171758],[-6.1396311,57.6137174],[-6.1541592,57.7423183],[-6.2913692,57.7380102],[-6.3365678,58.1398784],[-6.1121891,58.1466944],[-6.1473778,58.5106285],[-6.2934817,58.5416182],[-6.8413713,58.2977321],[-7.0057382,58.2929331],[-7.1016189,58.2064403],[-7.2573132,58.1793148],[-7.2531092,58.1004928],[-7.4070698,58.0905566],[-7.391347,57.7911354],[-7.790991,57.7733151],[-7.7624215,57.5444165],[-7.698501,57.1453194],[-7.7943817,57.1304547],[-7.716764,56.7368628],[-7.0122067,56.7654359],[-6.979922,56.5453858],[-7.0638622,56.5453858],[-7.0444914,56.3562587],[-6.500676,56.3812917],[-6.4491433,55.9793649],[-6.563287,55.9691456],[-6.5393742,55.7030135],[-6.5595521,55.6907321],[-6.5345315,55.6761713],[-6.5216176,55.5704434],[-5.8912587,55.5923416],[-5.8560127,55.2320733],[-5.2293639,55.2515958],[-5.1837064,54.6254139],[-3.6655956,54.6518373],[-3.6496155,54.4320023],[-3.5400375,54.4306744],[-3.530906,54.0290181],[-3.0697656,54.030359],[-3.0675737,53.8221388],[-3.0804876,53.7739911],[-3.0619239,53.7477488],[-3.0611168,53.6737049],[-3.2144691,53.6708361],[-3.2057699,53.4226163],[-3.2799632,53.355224],[-3.2896655,53.3608441],[-3.3327547,53.364931],[-3.3761293,53.3540318],[-4.0888976,53.3433102],[-4.0945474,53.4612036],[-4.697412,53.4448624],[-4.6882805,53.3318598],[-4.7202407,53.2895771],[-4.6837148,53.2486184],[-4.6768661,53.1542644],[-4.8480816,53.1446807],[-4.8178336,52.7440299],[-4.2545751,52.7558939],[-4.228876,52.254876],[-4.2607571,52.2536408],[-4.2724603,52.2432637],[-4.8136263,52.230095],[-4.8079191,52.1138892],[-5.3889104,52.0991668],[-5.3717888,51.9129667],[-5.4208706,51.9101502],[-5.414022,51.8453218],[-5.3683645,51.8474373],[-5.3466772,51.5595332],[-4.773676,51.5758518],[-4.7656859,51.4885146],[-4.1915432,51.4970427],[-4.1869775,51.4344663],[-3.6151177,51.4444274],[-3.6105519,51.3746543],[-3.1494115,51.3789292],[-3.1494115,51.2919281],[-4.3038735,51.2745907],[-4.2861169,51.0508721],[-4.8543277,51.0366633],[-4.8372201,50.7212787],[-5.2618345,50.7082694],[-5.2395519,50.3530581]],[[-2.1502671,60.171318],[-2.0030218,60.1696146],[-2.0013096,60.0997023],[-2.148555,60.1011247],[-2.1502671,60.171318]],[[-6.2086011,59.1163488],[-6.1229934,59.1166418],[-6.121852,59.0714985],[-6.2097426,59.0714985],[-6.2086011,59.1163488]],[[-4.4159559,59.0889036],[-4.4212022,59.0770848],[-4.3971904,59.0779143],[-4.3913388,59.0897328],[-4.4159559,59.0889036]]]},{"id":"OS-New_Popular_Edition-historic","name":"OS New Popular Edition historic","type":"tms","template":"http://ooc.openstreetmap.org/npe/{zoom}/{x}/{y}.png","polygon":[[[-5.8,49.8],[-5.8,55.8],[1.9,55.8],[1.9,49.8],[-5.8,49.8]]]},{"id":"OS-OpenData_Locator","name":"OS OpenData Locator","type":"tms","template":"http://tiles.itoworld.com/os_locator/{zoom}/{x}/{y}.png","polygon":[[[-9,49.8],[-9,61.1],[1.9,61.1],[1.9,49.8],[-9,49.8]]],"overlay":true},{"id":"OS-OpenData_StreetView","name":"OS OpenData StreetView","type":"tms","template":"http://os.openstreetmap.org/sv/{zoom}/{x}/{y}.png","scaleExtent":[1,18],"polygon":[[[-5.8292886,50.0229734],[-5.8292886,50.254819],[-5.373356,50.254819],[-5.373356,50.3530588],[-5.1756021,50.3530588],[-5.1756021,50.5925406],[-4.9970743,50.5925406],[-4.9970743,50.6935617],[-4.7965738,50.6935617],[-4.7965738,50.7822112],[-4.6949503,50.7822112],[-4.6949503,50.9607371],[-4.6043131,50.9607371],[-4.6043131,51.0692066],[-4.3792215,51.0692066],[-4.3792215,51.2521782],[-3.9039346,51.2521782],[-3.9039346,51.2916998],[-3.7171671,51.2916998],[-3.7171671,51.2453014],[-3.1486246,51.2453014],[-3.1486246,51.362067],[-3.7446329,51.362067],[-3.7446329,51.4340386],[-3.8297769,51.4340386],[-3.8297769,51.5298246],[-4.0852091,51.5298246],[-4.0852091,51.4939284],[-4.3792215,51.4939284],[-4.3792215,51.5427168],[-5.1444195,51.5427168],[-5.1444195,51.6296003],[-5.7387103,51.6296003],[-5.7387103,51.774037],[-5.5095393,51.774037],[-5.5095393,51.9802596],[-5.198799,51.9802596],[-5.198799,52.0973358],[-4.8880588,52.0973358],[-4.8880588,52.1831557],[-4.4957492,52.1831557],[-4.4957492,52.2925739],[-4.3015365,52.2925739],[-4.3015365,52.3685318],[-4.1811246,52.3685318],[-4.1811246,52.7933685],[-4.4413696,52.7933685],[-4.4413696,52.7369614],[-4.8569847,52.7369614],[-4.8569847,52.9317255],[-4.7288044,52.9317255],[-4.7288044,53.5038599],[-4.1578191,53.5038599],[-4.1578191,53.4113498],[-3.3110518,53.4113498],[-3.3110518,53.5038599],[-3.2333667,53.5038599],[-3.2333667,54.0159169],[-3.3926211,54.0159169],[-3.3926211,54.1980953],[-3.559644,54.1980953],[-3.559644,54.433732],[-3.7188984,54.433732],[-3.7188984,54.721897],[-4.3015365,54.721897],[-4.3015365,54.6140739],[-5.0473132,54.6140739],[-5.0473132,54.7532915],[-5.2298731,54.7532915],[-5.2298731,55.2190799],[-5.6532567,55.2190799],[-5.6532567,55.250088],[-5.8979647,55.250088],[-5.8979647,55.4822462],[-6.5933212,55.4822462],[-6.5933212,56.3013441],[-7.1727691,56.3013441],[-7.1727691,56.5601822],[-6.8171722,56.5601822],[-6.8171722,56.6991713],[-6.5315276,56.6991713],[-6.5315276,56.9066964],[-6.811679,56.9066964],[-6.811679,57.3716613],[-6.8721038,57.3716613],[-6.8721038,57.5518893],[-7.0973235,57.5518893],[-7.0973235,57.2411085],[-7.1742278,57.2411085],[-7.1742278,56.9066964],[-7.3719817,56.9066964],[-7.3719817,56.8075885],[-7.5202972,56.8075885],[-7.5202972,56.7142479],[-7.8306806,56.7142479],[-7.8306806,56.8994605],[-7.6494061,56.8994605],[-7.6494061,57.4739617],[-7.8306806,57.4739617],[-7.8306806,57.7915584],[-7.4736249,57.7915584],[-7.4736249,58.086063],[-7.1879804,58.086063],[-7.1879804,58.367197],[-6.8034589,58.367197],[-6.8034589,58.4155786],[-6.638664,58.4155786],[-6.638664,58.4673277],[-6.5178143,58.4673277],[-6.5178143,58.5625632],[-6.0536224,58.5625632],[-6.0536224,58.1568843],[-6.1470062,58.1568843],[-6.1470062,58.1105865],[-6.2799798,58.1105865],[-6.2799798,57.7122664],[-6.1591302,57.7122664],[-6.1591302,57.6667563],[-5.9339104,57.6667563],[-5.9339104,57.8892524],[-5.80643,57.8892524],[-5.80643,57.9621767],[-5.6141692,57.9621767],[-5.6141692,58.0911236],[-5.490819,58.0911236],[-5.490819,58.3733281],[-5.3199118,58.3733281],[-5.3199118,58.75015],[-3.5719977,58.75015],[-3.5719977,59.2091788],[-3.1944501,59.2091788],[-3.1944501,59.4759216],[-2.243583,59.4759216],[-2.243583,59.1388749],[-2.4611012,59.1388749],[-2.4611012,58.8185938],[-2.7407675,58.8185938],[-2.7407675,58.5804743],[-2.9116746,58.5804743],[-2.9116746,58.1157523],[-3.4865441,58.1157523],[-3.4865441,57.740386],[-1.7153245,57.740386],[-1.7153245,57.2225558],[-1.9794538,57.2225558],[-1.9794538,56.8760742],[-2.1658979,56.8760742],[-2.1658979,56.6333186],[-2.3601106,56.6333186],[-2.3601106,56.0477521],[-1.9794538,56.0477521],[-1.9794538,55.8650949],[-1.4745008,55.8650949],[-1.4745008,55.2499926],[-1.3221997,55.2499926],[-1.3221997,54.8221737],[-1.0550014,54.8221737],[-1.0550014,54.6746628],[-0.6618765,54.6746628],[-0.6618765,54.5527463],[-0.3247617,54.5527463],[-0.3247617,54.2865195],[0.0092841,54.2865195],[0.0092841,53.7938518],[0.2081962,53.7938518],[0.2081962,53.5217726],[0.4163548,53.5217726],[0.4163548,53.0298851],[1.4273388,53.0298851],[1.4273388,52.92021],[1.8333912,52.92021],[1.8333912,52.042488],[1.5235504,52.042488],[1.5235504,51.8261335],[1.2697049,51.8261335],[1.2697049,51.6967453],[1.116651,51.6967453],[1.116651,51.440346],[1.5235504,51.440346],[1.5235504,51.3331831],[1.4507565,51.3331831],[1.4507565,51.0207553],[1.0699883,51.0207553],[1.0699883,50.9008416],[0.7788126,50.9008416],[0.7788126,50.729843],[-0.7255952,50.729843],[-0.7255952,50.7038437],[-1.0074383,50.7038437],[-1.0074383,50.5736307],[-2.3625252,50.5736307],[-2.3625252,50.4846421],[-2.4987805,50.4846421],[-2.4987805,50.5736307],[-3.4096378,50.5736307],[-3.4096378,50.2057837],[-3.6922446,50.2057837],[-3.6922446,50.1347737],[-5.005468,50.1347737],[-5.005468,49.9474456],[-5.2839506,49.9474456],[-5.2839506,50.0229734],[-5.8292886,50.0229734]],[[-6.4580707,49.8673563],[-6.4580707,49.9499935],[-6.3978807,49.9499935],[-6.3978807,50.0053797],[-6.1799606,50.0053797],[-6.1799606,49.9168614],[-6.2540201,49.9168614],[-6.2540201,49.8673563],[-6.4580707,49.8673563]],[[-5.8343165,49.932156],[-5.8343165,49.9754641],[-5.7683254,49.9754641],[-5.7683254,49.932156],[-5.8343165,49.932156]],[[-1.9483797,60.6885737],[-1.9483797,60.3058841],[-1.7543149,60.3058841],[-1.7543149,60.1284428],[-1.5754914,60.1284428],[-1.5754914,59.797917],[-1.0316959,59.797917],[-1.0316959,60.0354518],[-0.6626918,60.0354518],[-0.6626918,60.9103862],[-1.1034395,60.9103862],[-1.1034395,60.8040022],[-1.3506319,60.8040022],[-1.3506319,60.6885737],[-1.9483797,60.6885737]],[[-2.203381,60.1968568],[-2.203381,60.0929443],[-1.9864011,60.0929443],[-1.9864011,60.1968568],[-2.203381,60.1968568]],[[-1.7543149,59.5698289],[-1.7543149,59.4639383],[-1.5373349,59.4639383],[-1.5373349,59.5698289],[-1.7543149,59.5698289]],[[-4.5585981,59.1370518],[-4.5585981,58.9569099],[-4.2867004,58.9569099],[-4.2867004,59.1370518],[-4.5585981,59.1370518]],[[-6.2787732,59.2025744],[-6.2787732,59.0227769],[-5.6650612,59.0227769],[-5.6650612,59.2025744],[-6.2787732,59.2025744]],[[-8.7163482,57.9440556],[-8.7163482,57.7305936],[-8.3592926,57.7305936],[-8.3592926,57.9440556],[-8.7163482,57.9440556]],[[-7.6077005,50.4021026],[-7.6077005,50.2688657],[-7.3907205,50.2688657],[-7.3907205,50.4021026],[-7.6077005,50.4021026]],[[-7.7304303,58.3579902],[-7.7304303,58.248313],[-7.5134503,58.248313],[-7.5134503,58.3579902],[-7.7304303,58.3579902]]]},{"id":"OS-Scottish_Popular-historic","name":"OS Scottish Popular historic","type":"tms","template":"http://ooc.openstreetmap.org/npescotland/tiles/{zoom}/{x}/{y}.jpg","scaleExtent":[6,15],"polygon":[[[-7.8,54.5],[-7.8,61.1],[-1.1,61.1],[-1.1,54.5],[-7.8,54.5]]]},{"id":"Pangasinan_Bulacan_HiRes","name":"Pangasinán/Bulacan (Philippines HiRes)","type":"tms","template":"http://gravitystorm.dev.openstreetmap.org/imagery/philippines/{zoom}/{x}/{y}.png","scaleExtent":[12,19],"polygon":[[[120.336593,15.985768],[120.445995,15.984],[120.446134,15.974459],[120.476464,15.974592],[120.594247,15.946832],[120.598064,16.090795],[120.596537,16.197999],[120.368537,16.218527],[120.347576,16.042308],[120.336593,15.985768]],[[120.8268,15.3658],[121.2684,15.2602],[121.2699,14.7025],[120.695,14.8423],[120.8268,15.3658]]]},{"id":"PNOA-Spain-TMS","name":"PNOA Spain","type":"tms","template":"http://www.ign.es/wmts/pnoa-ma?request=GetTile&service=WMTS&VERSION=1.0.0&Layer=OI.OrthoimageCoverage&Style=default&Format=image/png&TileMatrixSet=GoogleMapsCompatible&TileMatrix={zoom}&TileRow={y}&TileCol={x}","polygon":[[[-17.8846298,28.4460601],[-17.8939535,28.5225529],[-18.0212548,28.7481927],[-18.0224091,28.8038375],[-17.9424017,28.8726124],[-17.8911792,28.8737099],[-17.8903302,28.8515102],[-17.7675902,28.8537764],[-17.7669837,28.8312183],[-17.7412714,28.8319975],[-17.7394926,28.7642235],[-17.7139824,28.7649677],[-17.7129312,28.7303731],[-17.7574427,28.6931782],[-17.7570788,28.6741254],[-17.7457913,28.6743524],[-17.7457266,28.6165627],[-17.7519687,28.5833675],[-17.7622536,28.5591958],[-17.7833086,28.541667],[-17.7831575,28.4936643],[-17.808611,28.4925024],[-17.8060072,28.4468974],[-17.8846298,28.4460601]],[[-18.1661033,27.7851643],[-18.163494,27.6949247],[-18.0889827,27.6963366],[-18.0873398,27.6738724],[-18.0364092,27.6753701],[-18.0350079,27.6302571],[-17.9589987,27.6323976],[-17.8603269,27.7926025],[-17.8630328,27.8368793],[-17.8884015,27.8364947],[-17.8891263,27.8590536],[-17.9906491,27.8567467],[-18.0386803,27.7655831],[-18.1146412,27.7637873],[-18.1154627,27.7863613],[-18.1661033,27.7851643]],[[-17.36038,28.0639801],[-17.3629657,28.1757247],[-17.3375583,28.1763688],[-17.3384577,28.2213012],[-17.1857883,28.2238767],[-17.0820788,28.1351849],[-17.0808422,28.0679977],[-17.1315446,28.0668073],[-17.1563337,28.0214628],[-17.2321063,28.0203711],[-17.2319938,27.9980388],[-17.2576823,27.9978403],[-17.257851,28.0199741],[-17.3086658,28.0192298],[-17.36038,28.0639801]],[[-16.9278171,28.3275779],[-16.9286591,28.3721879],[-16.8776666,28.3729288],[-16.8780707,28.3954191],[-16.5214259,28.4226146],[-16.4457117,28.491135],[-16.4462506,28.535972],[-16.4205859,28.5362679],[-16.4209227,28.5588419],[-16.3443329,28.5597589],[-16.3446023,28.5822095],[-16.1912541,28.5837179],[-16.1916246,28.6068435],[-16.1279344,28.6078193],[-16.1277997,28.5921762],[-16.0995079,28.5925015],[-16.0993395,28.5163822],[-16.1648148,28.5161158],[-16.1647474,28.4938583],[-16.2385755,28.4484704],[-16.2653516,28.4476116],[-16.2658569,28.4030038],[-16.3167484,28.4017594],[-16.3163105,28.380189],[-16.3420763,28.3795075],[-16.3408301,28.2892963],[-16.415837,28.1976134],[-16.415096,28.1311312],[-16.5153297,28.0164796],[-16.6168433,28.01532],[-16.6168096,27.9930469],[-16.7184243,27.9919168],[-16.7190979,28.0371426],[-16.7446952,28.0367859],[-16.7453351,28.0818146],[-16.7706967,28.0816065],[-16.8223966,28.1259036],[-16.8231712,28.1708652],[-16.8487012,28.1707464],[-16.8502842,28.260791],[-16.8756457,28.2605537],[-16.8760836,28.2832162],[-16.9015125,28.2827713],[-16.9023882,28.3279337],[-16.9278171,28.3275779]],[[-15.8537427,27.9008901],[-15.8542032,27.9901812],[-15.828953,27.9906555],[-15.8291065,28.035578],[-15.7782992,28.0363232],[-15.7532793,28.0814298],[-15.7278756,28.0815652],[-15.7282593,28.1718567],[-15.4989741,28.1728039],[-15.4987438,28.1504075],[-15.4497785,28.1507459],[-15.4501622,28.1961425],[-15.3972827,28.1961425],[-15.3964385,28.0383554],[-15.3710348,28.0380167],[-15.3706511,28.0153212],[-15.3457847,28.0153212],[-15.3454777,27.9254406],[-15.3708046,27.9252372],[-15.3705743,27.8352137],[-15.395978,27.8347387],[-15.4209979,27.7879673],[-15.4718052,27.7893932],[-15.471882,27.7666454],[-15.522766,27.7667813],[-15.5477092,27.7216112],[-15.6236132,27.7213395],[-15.6241504,27.741991],[-15.7007451,27.7433495],[-15.801669,27.8110501],[-15.8537427,27.9008901]],[[-14.5215621,28.0467778],[-14.5224358,28.1184131],[-14.4157526,28.1156076],[-14.2168794,28.2278805],[-14.2153651,28.33903],[-14.1641672,28.4528287],[-14.1115132,28.4747955],[-14.0335806,28.7226671],[-13.9565217,28.7449351],[-13.9561722,28.7665857],[-13.8290221,28.7664325],[-13.8289639,28.7879765],[-13.8000741,28.7879255],[-13.8012972,28.7189894],[-13.827566,28.719347],[-13.8278572,28.6517968],[-13.8025786,28.651899],[-13.8033941,28.5384172],[-13.8288474,28.5384684],[-13.8315061,28.3970177],[-13.9158189,28.2241438],[-13.9856445,28.2235696],[-14.0369588,28.1795787],[-14.1387139,28.1799894],[-14.1386556,28.1579103],[-14.2153651,28.1578076],[-14.2147244,28.1118888],[-14.2913173,28.0452356],[-14.3319673,28.0368713],[-14.4457846,28.0469834],[-14.4466583,28.0657961],[-14.4962835,28.0682631],[-14.495934,28.0458525],[-14.5215621,28.0467778]],[[-13.800662,28.8456579],[-13.8009273,28.8231121],[-13.775688,28.8230539],[-13.69729,28.8898184],[-13.69729,28.9127744],[-13.6072498,28.9117991],[-13.4388551,29.0002417],[-13.4374559,29.1351289],[-13.4117005,29.1349931],[-13.4105556,29.2229789],[-13.4592801,29.255586],[-13.4597392,29.2942023],[-13.5091254,29.2945638],[-13.5100581,29.3163453],[-13.5635382,29.3172941],[-13.5640564,29.2713764],[-13.5389228,29.2711956],[-13.5389747,29.2500375],[-13.5661293,29.2501279],[-13.5665956,29.2030039],[-13.5156549,29.2022349],[-13.5156549,29.1820579],[-13.5398038,29.1827819],[-13.5408921,29.137528],[-13.65782,29.1368528],[-13.713222,29.0935079],[-13.7663353,29.0934533],[-13.8502463,29.0165937],[-13.8518224,28.983425],[-13.8524443,28.914861],[-13.9013122,28.89245],[-13.9024005,28.8469779],[-13.800662,28.8456579]],[[1.6479916,38.9990693],[1.7321668,38.9993635],[1.7314703,39.0441733],[1.6489512,39.0431944],[1.6481552,39.1276358],[1.3948608,39.1265691],[1.3954412,39.0864199],[1.2281145,39.0852615],[1.2291095,39.0028958],[1.1448657,39.0018003],[1.1452803,38.8319988],[1.3113632,38.8331615],[1.3121924,38.7906483],[1.3946949,38.7916178],[1.3951924,38.7529597],[1.3112803,38.7519251],[1.3125919,38.6238804],[1.6489036,38.6251112],[1.6480745,38.7111504],[1.58456,38.7101152],[1.5811604,38.7005387],[1.5491544,38.7002798],[1.5197188,38.7092094],[1.50355,38.7253185],[1.4813282,38.9155064],[1.5518906,38.9254411],[1.5667328,38.9566554],[1.6487378,38.9583318],[1.6479916,38.9990693]],[[2.5450749,39.4166673],[2.43933,39.4161122],[2.438714,39.4846853],[2.439022,39.4993424],[2.3122308,39.4993424],[2.3119228,39.5417911],[2.2290722,39.5409994],[2.2283536,39.6260571],[2.3460076,39.6270851],[2.9270445,39.9601558],[3.1456647,39.9600498],[3.1460753,40.0019797],[3.2313899,40.0019797],[3.2312872,39.8329231],[3.1482313,39.8331596],[3.1484366,39.7935717],[3.4814817,39.7931773],[3.4803472,39.5959027],[3.3150618,39.4784606],[3.3146179,39.3785504],[3.0830178,39.2499355],[2.9798608,39.2501482],[2.9790395,39.3334971],[2.7287424,39.3334177],[2.7288451,39.4581361],[2.6456865,39.4577397],[2.6453785,39.4996593],[2.5452802,39.4994216],[2.5450749,39.4166673]],[[3.8120402,40.0434431],[3.729082,40.0437979],[3.7286185,39.9584155],[3.8126633,39.9576011],[3.8122771,39.9164393],[3.9608975,39.9159813],[4.1938142,39.791308],[4.3150279,39.7905799],[4.3159934,39.8329294],[4.3987393,39.8320396],[4.3973664,39.9185834],[4.3158003,39.9193274],[4.3161865,40.0433985],[4.2318959,40.0443594],[4.2324752,40.0847793],[4.1491501,40.086109],[4.1490623,40.1255157],[4.0627981,40.1272166],[4.0624217,40.0849941],[3.8128687,40.085294],[3.8120402,40.0434431]],[[-8.8910646,41.8228891],[-9.1092038,42.5751065],[-9.0365469,42.730656],[-9.0883419,42.7269569],[-9.1466113,42.7750272],[-9.2185488,42.9016271],[-9.2760988,42.8605106],[-9.3099094,42.9311297],[-9.2789763,42.9821991],[-9.3099094,43.0600377],[-9.2523594,43.1041725],[-9.2314975,43.1703151],[-9.1473307,43.210176],[-9.06748,43.1991644],[-9.0336694,43.2426748],[-8.99842,43.2447709],[-8.9998588,43.2955793],[-8.9372732,43.3055265],[-8.92936,43.326986],[-8.8638969,43.3290792],[-8.8761263,43.3740655],[-8.8221732,43.3735426],[-8.785485,43.3191358],[-8.7063538,43.305003],[-8.6099575,43.3296025],[-8.5509688,43.3233227],[-8.5243519,43.3364048],[-8.5250713,43.3646525],[-8.45745,43.3918416],[-8.3610538,43.4111803],[-8.3603344,43.4634161],[-8.3344369,43.5797394],[-8.2776063,43.5708796],[-8.0646713,43.7239184],[-7.9992081,43.7233986],[-7.9171994,43.7826357],[-7.8560525,43.7914643],[-7.83591,43.7374337],[-7.6628443,43.809819],[-7.3188932,43.6782695],[-7.1997467,43.5830817],[-6.2488228,43.6075032],[-6.1229322,43.5790105],[-5.8520425,43.6798953],[-5.6036334,43.5708672],[-5.2855347,43.5619084],[-5.1787525,43.4991591],[-4.9089869,43.4836655],[-4.6156167,43.4192021],[-4.1839917,43.4249168],[-3.8029478,43.5195394],[-3.7400025,43.4869277],[-3.5612827,43.5423572],[-3.1083013,43.3816347],[-2.9385737,43.4624573],[-2.7452417,43.4755094],[-2.3046245,43.3170625],[-1.9854018,43.3563045],[-1.8552841,43.3972545],[-1.769802,43.3964383],[-1.7700492,43.3760501],[-1.7100474,43.3756908],[-1.7113451,43.3312527],[-1.7225915,43.3131806],[-1.6890375,43.3129108],[-1.6881106,43.3341294],[-1.6446695,43.3337248],[-1.6449785,43.3133155],[-1.6029903,43.3129528],[-1.6034352,43.2926624],[-1.5635905,43.2921227],[-1.5630468,43.3133844],[-1.4779905,43.3128355],[-1.3667723,43.2761368],[-1.3568809,43.2381533],[-1.3703692,43.1712972],[-1.4423067,43.0833554],[-1.4198262,43.0603647],[-1.3730668,43.051166],[-1.3640746,43.1115893],[-1.3020285,43.135217],[-1.2354864,43.1332484],[-1.2795481,43.0774443],[-1.1923239,43.0649635],[-1.0061856,43.0077821],[-0.942341,42.9748951],[-0.7562028,42.9821318],[-0.7148387,42.9610774],[-0.6968543,42.9031405],[-0.5511809,42.8220693],[-0.5044215,42.8484456],[-0.4288871,42.8200906],[-0.3164848,42.8655842],[-0.1456332,42.810856],[-0.0314324,42.7124874],[0.1861785,42.7540985],[0.3021777,42.7177729],[0.3642238,42.7428729],[0.4487504,42.7144695],[0.6276949,42.7223973],[0.6411832,42.8576747],[0.7149192,42.882718],[0.9675996,42.8181119],[1.108777,42.7989808],[1.1753192,42.7342872],[1.3632559,42.7415521],[1.4113736,42.7093914],[1.4806054,42.7103407],[1.4813006,42.5010664],[1.6443591,42.5020345],[1.6432777,42.5424539],[1.730407,42.5434214],[1.7316429,42.5011803],[2.0638621,42.5016359],[2.0645572,42.4590247],[2.3969309,42.4599364],[2.3976786,42.4178363],[2.4804823,42.4179732],[2.4809767,42.3759441],[2.6447922,42.3762636],[2.6444832,42.4592447],[2.8113266,42.4596094],[2.8112648,42.5010358],[3.063878,42.5008535],[3.063878,42.4591535],[3.2307832,42.4593359],[3.2304935,42.3764363],[3.3141469,42.3760369],[3.3141243,42.3339864],[3.397855,42.3340435],[3.3973912,42.290094],[3.3138923,42.2908368],[3.3139695,42.2070151],[3.1475896,42.2073012],[3.1475896,42.1260612],[3.2305478,42.1260039],[3.2466753,41.9529359],[3.1945206,41.8558943],[3.060537,41.7647419],[2.7835777,41.6371796],[2.26293,41.4271601],[2.1649151,41.2989297],[1.86008,41.2232228],[1.3763003,41.116273],[1.1793714,41.0464585],[1.0858526,41.048493],[0.758537,40.8195599],[0.9114042,40.733761],[0.8781331,40.6751363],[0.6650182,40.5358666],[0.5580112,40.5502166],[0.433919,40.3757589],[0.2675635,40.1919192],[0.1641534,40.0647234],[0.0751307,40.0144671],[0.010387,39.8952188],[-0.0939224,39.8116904],[-0.1847435,39.6311716],[-0.2908513,39.5036254],[-0.2863552,39.333431],[-0.1856427,39.1774612],[-0.2135185,39.1558487],[-0.1110076,38.9722246],[0.0094878,38.8826835],[0.1218901,38.872183],[0.2342925,38.798636],[0.2558737,38.7264162],[0.0958128,38.6133825],[-0.0022021,38.6070586],[-0.0570544,38.5269073],[-0.2719677,38.4762395],[-0.379874,38.3931234],[-0.3834708,38.3381297],[-0.4509122,38.3310763],[-0.5048654,38.2830943],[-0.4823849,38.1948095],[-0.429331,38.1658287],[-0.4545091,38.148859],[-0.5839966,38.1721913],[-0.6136708,38.1198599],[-0.6370505,37.9612228],[-0.6811123,37.9456238],[-0.7323677,37.8810656],[-0.7215771,37.7830562],[-0.688306,37.7340026],[-0.6641461,37.6231485],[-0.7193941,37.5878413],[-0.9196258,37.5375806],[-1.1107098,37.5164093],[-1.3383246,37.5286671],[-1.4408917,37.3903714],[-1.6766966,37.2765189],[-1.8540816,36.9122889],[-2.0683486,36.6929117],[-2.2158766,36.6619233],[-2.3721861,36.7801753],[-2.6812926,36.6591056],[-2.9201476,36.6675585],[-3.09402,36.712625],[-3.4610839,36.6548788],[-3.7280395,36.6929117],[-4.3743529,36.6633322],[-4.6571151,36.4404171],[-4.9188018,36.4531321],[-5.1699508,36.3513541],[-5.2841094,36.1970201],[-5.2680911,36.1241812],[-5.3524784,36.1224654],[-5.3516094,36.0401413],[-5.4365759,36.0388921],[-5.4353207,36.0034384],[-5.6888562,36.0036518],[-5.6899635,36.0405317],[-5.85506,36.0385595],[-5.8566821,36.1242077],[-5.9384817,36.1221487],[-5.9400265,36.1655625],[-5.9983445,36.1645024],[-6.0357297,36.1780957],[-6.0775178,36.2224132],[-6.1506113,36.2864561],[-6.231541,36.3770075],[-6.3358504,36.5310643],[-6.3214629,36.5816265],[-6.404191,36.6234958],[-6.4743301,36.7489673],[-6.4158808,36.7993866],[-6.490516,36.9173818],[-6.6298949,37.0194012],[-6.8744824,37.1083766],[-7.0426363,37.1850699],[-7.2647434,37.1843535],[-7.3753473,37.1535419],[-7.408316,37.1682196],[-7.4202886,37.2118318],[-7.4249231,37.2350505],[-7.4380543,37.2451969],[-7.4459717,37.3326142],[-7.4480958,37.3909382],[-7.4696271,37.4075829],[-7.4647029,37.4530494],[-7.5019723,37.516411],[-7.5191587,37.5229203],[-7.5219588,37.5723727],[-7.4501271,37.6695835],[-7.4249019,37.7599222],[-7.316662,37.839974],[-7.268329,37.988952],[-7.1536786,38.0155235],[-7.1177098,38.0553626],[-7.0142997,38.0243785],[-6.9963153,38.1075633],[-6.9614706,38.201254],[-7.080617,38.1570753],[-7.3402665,38.4402363],[-7.2638329,38.7380741],[-7.0435243,38.8729667],[-7.0615086,38.907962],[-6.9693387,39.0198308],[-7.0008114,39.0887867],[-7.1536786,39.0957658],[-7.1525545,39.1602899],[-7.2447245,39.1968854],[-7.2559647,39.2813308],[-7.3368944,39.3535074],[-7.3279022,39.4559917],[-7.5144901,39.5886496],[-7.5527069,39.6795427],[-7.0502684,39.6752171],[-6.9951913,39.8195433],[-6.9221297,39.8790868],[-6.886161,40.0229854],[-7.0412762,40.1347927],[-7.0176717,40.266146],[-6.8086034,40.3450071],[-6.8681766,40.4451649],[-6.8535643,40.6066433],[-6.837828,40.8757589],[-6.9536024,41.0370445],[-6.8018592,41.0395879],[-6.7681385,41.138706],[-6.6411239,41.2655616],[-6.5624422,41.2630269],[-6.217367,41.5791017],[-6.3162811,41.644652],[-6.5152332,41.6412921],[-6.5871707,41.6883151],[-6.5478299,41.8559743],[-6.6298836,41.9112057],[-7.1334461,41.9404756],[-7.1682909,41.8718791],[-7.4256922,41.7847727],[-7.9539833,41.8459271],[-8.130455,41.7805819],[-8.2518495,41.9078597],[-8.1293309,42.0348842],[-8.2484774,42.1008034],[-8.3676239,42.0557521],[-8.6070409,42.0340493],[-8.8910646,41.8228891]]],"terms_text":"PNOA","best":true},{"id":"Slovakia-Historic-Maps","name":"Slovakia Historic Maps","type":"tms","template":"http://tms.freemap.sk/historicke/{zoom}/{x}/{y}.png","scaleExtent":[0,12],"polygon":[[[16.8196949,47.4927236],[16.8196949,49.5030322],[22.8388318,49.5030322],[22.8388318,47.4927236],[16.8196949,47.4927236]]]},{"id":"Soskut_Pusztazamor_Tarnok_Diosd_orto_2017","name":"Sóskút, Pusztazámor, Tárnok, Diósd ortophoto 2017","type":"tms","template":"http://adam.openstreetmap.hu/mapproxy/tiles/1.0.0/Soskut-Tarnok-Pusztazamor-Diosd/mercator/{zoom}/{x}/{y}.png","polygon":[[[18.79273330201,47.37078533804],[18.791936169,47.37048036201],[18.79139114593,47.37063268281],[18.7901097,47.3717614],[18.7891647,47.3734529],[18.78721506824,47.37566027041],[18.7860339,47.37764910001],[18.7849824,47.3790513],[18.783695,47.3803226],[18.782665,47.3819499],[18.781399,47.3836789],[18.7793426,47.3871257],[18.776657,47.3893959],[18.764716,47.396699],[18.7616966,47.3996569],[18.7563102,47.4032821],[18.7583737,47.4065272],[18.75879657883,47.40776342073],[18.76199554897,47.41217224817],[18.7630394973,47.41315137445],[18.7659298,47.4147108],[18.7704058,47.4176575],[18.77247285488,47.41808545272],[18.7724806,47.4202978],[18.8086021,47.4404108],[18.8174212,47.435389],[18.8209188,47.4357228],[18.8280427,47.4375516],[18.8302099,47.4352584],[18.8358533,47.4375371],[18.8404882,47.4334586],[18.847655,47.4357228],[18.8510024,47.4328054],[18.8689996,47.4396086],[18.87361350924,47.43597176329],[18.87499181607,47.43342149293],[18.87386045593,47.43248349864],[18.8760377,47.4279677],[18.8605023,47.4230028],[18.8662101,47.4179794],[18.8724328,47.4108645],[18.8662959,47.4077278],[18.8696433,47.4047072],[18.86776892261,47.40207457802],[18.86509430105,47.40052438512],[18.87081279074,47.3983820654],[18.86772375423,47.39699336542],[18.86992005424,47.39655168559],[18.87648610191,47.39477958954],[18.87748924808,47.39494663392],[18.87866942005,47.39462343887],[18.88358322696,47.3899604942],[18.88290731029,47.3896699544],[18.88538567142,47.38530440107],[18.87747851924,47.38339390377],[18.88181296901,47.37604910406],[18.87914148883,47.37392756692],[18.88638345317,47.36922645965],[18.88205973224,47.36772957402],[18.87973157482,47.36640704749],[18.8746997507,47.36252284243],[18.87282220439,47.36136733615],[18.87027947025,47.36062605465],[18.86687842922,47.3585329683],[18.86234013156,47.35637438604],[18.85566679554,47.35199153827],[18.84873596744,47.34728120653],[18.83192388134,47.3384118486],[18.82497159557,47.34257772442],[18.81619540767,47.34925116493],[18.8107880743,47.35356882392],[18.80823461132,47.35599644336],[18.80645362453,47.35854023611],[18.80707589702,47.359019909],[18.80634633617,47.36021180457],[18.80465118007,47.36175250772],[18.80381433086,47.36335130305],[18.80054616504,47.36544732015],[18.79988097721,47.36617355102],[18.79416204336,47.36974865444],[18.79273330201,47.37078533804]],[[18.91871480064,47.4093812629],[18.91826418952,47.40997664498],[18.9206674488,47.41155945729],[18.92509845809,47.41372304121],[18.93473295288,47.41916790937],[18.94063381271,47.42241278301],[18.94981769638,47.41937843296],[18.95154503898,47.41749820965],[18.95689872818,47.41922598493],[18.95770339088,47.41877589767],[18.95755318717,47.41435467478],[18.9621129425,47.40506817222],[18.96266011314,47.40117592194],[18.96316436843,47.39903360927],[18.95446328239,47.3967314338],[18.95275739746,47.39526437993],[18.95201710777,47.39362297422],[18.95119098739,47.39356487042],[18.94692091064,47.39798783856],[18.94410995559,47.3984526281],[18.94161013679,47.39868502134],[18.93735078887,47.39633199249],[18.93617061691,47.39682584676],[18.93122462348,47.39999947627],[18.93120316581,47.40023186269],[18.92923978881,47.40204734624],[18.92561344223,47.40604845111],[18.92465857582,47.40635342305],[18.92293123321,47.40925782918],[18.91871480064,47.4093812629]]],"terms_url":"http://fototerkep.hu/","terms_text":"Fototerkep.hu","best":true},{"id":"South_Africa-CD_NGI-Aerial","name":"South Africa CD:NGI Aerial","type":"tms","template":"http://{switch:a,b,c}.aerial.openstreetmap.org.za/ngi-aerial/{zoom}/{x}/{y}.jpg","scaleExtent":[1,22],"polygon":[[[17.8396817,-32.7983384],[17.8893509,-32.6972835],[18.00364,-32.6982187],[18.0991679,-32.7485251],[18.2898747,-32.5526645],[18.2930182,-32.0487089],[18.105455,-31.6454966],[17.8529257,-31.3443951],[17.5480046,-30.902171],[17.4044506,-30.6374731],[17.2493704,-30.3991663],[16.9936977,-29.6543552],[16.7987996,-29.19437],[16.5494139,-28.8415949],[16.4498691,-28.691876],[16.4491046,-28.5515766],[16.6002551,-28.4825663],[16.7514057,-28.4486958],[16.7462192,-28.2458973],[16.8855148,-28.04729],[16.9929502,-28.0244005],[17.0529659,-28.0257086],[17.1007562,-28.0338839],[17.2011527,-28.0930546],[17.2026346,-28.2328424],[17.2474611,-28.2338215],[17.2507953,-28.198892],[17.3511919,-28.1975861],[17.3515624,-28.2442655],[17.4015754,-28.2452446],[17.4149122,-28.3489751],[17.4008345,-28.547997],[17.4526999,-28.5489733],[17.4512071,-28.6495106],[17.4983599,-28.6872054],[17.6028204,-28.6830048],[17.6499732,-28.6967928],[17.6525928,-28.7381457],[17.801386,-28.7381457],[17.9994276,-28.7560602],[18.0002748,-28.7956172],[18.1574507,-28.8718055],[18.5063811,-28.8718055],[18.6153564,-28.8295875],[18.9087513,-28.8277516],[19.1046973,-28.9488548],[19.1969071,-28.9378513],[19.243012,-28.8516164],[19.2314858,-28.802963],[19.2587296,-28.7009928],[19.4431493,-28.6973163],[19.5500289,-28.4958332],[19.6967264,-28.4939914],[19.698822,-28.4479358],[19.8507587,-28.4433291],[19.8497109,-28.4027818],[19.9953605,-28.399095],[19.9893671,-24.7497859],[20.2916682,-24.9192346],[20.4724562,-25.1501701],[20.6532441,-25.4529449],[20.733265,-25.6801957],[20.8281046,-25.8963498],[20.8429232,-26.215851],[20.6502804,-26.4840868],[20.6532441,-26.8204869],[21.0889134,-26.846933],[21.6727695,-26.8389998],[21.7765003,-26.6696268],[21.9721069,-26.6431395],[22.2803355,-26.3274702],[22.5707817,-26.1333967],[22.7752795,-25.6775246],[23.0005235,-25.2761948],[23.4658301,-25.2735148],[23.883717,-25.597366],[24.2364017,-25.613402],[24.603905,-25.7896563],[25.110704,-25.7389432],[25.5078447,-25.6855376],[25.6441766,-25.4823781],[25.8419267,-24.7805437],[25.846641,-24.7538456],[26.3928487,-24.6332894],[26.4739066,-24.5653312],[26.5089966,-24.4842437],[26.5861946,-24.4075775],[26.7300635,-24.3014458],[26.8567384,-24.2499463],[26.8574402,-24.1026901],[26.9215471,-23.8990957],[26.931831,-23.8461891],[26.9714827,-23.6994344],[27.0006074,-23.6367644],[27.0578041,-23.6052574],[27.1360547,-23.5203437],[27.3339623,-23.3973792],[27.5144057,-23.3593929],[27.5958145,-23.2085465],[27.8098634,-23.0994957],[27.8828506,-23.0620496],[27.9382928,-22.9496487],[28.0407556,-22.8255118],[28.2056786,-22.6552861],[28.3397223,-22.5639374],[28.4906093,-22.560697],[28.6108769,-22.5400248],[28.828175,-22.4550173],[28.9285324,-22.4232328],[28.9594116,-22.3090081],[29.0162574,-22.208335],[29.2324117,-22.1693453],[29.3531213,-22.1842926],[29.6548952,-22.1186426],[29.7777102,-22.1361956],[29.9292989,-22.1849425],[30.1166795,-22.2830348],[30.2563377,-22.2914767],[30.3033582,-22.3395204],[30.5061784,-22.3057617],[30.8374279,-22.284983],[31.0058599,-22.3077095],[31.1834152,-22.3232913],[31.2930586,-22.3674647],[31.5680579,-23.1903385],[31.5568311,-23.4430809],[31.6931122,-23.6175209],[31.7119696,-23.741136],[31.7774743,-23.8800628],[31.8886337,-23.9481098],[31.9144386,-24.1746736],[31.9948307,-24.3040878],[32.0166656,-24.4405988],[32.0077331,-24.6536578],[32.019643,-24.9140701],[32.035523,-25.0849767],[32.019643,-25.3821442],[31.9928457,-25.4493771],[31.9997931,-25.5165725],[32.0057481,-25.6078978],[32.0057481,-25.6624806],[31.9362735,-25.8403721],[31.9809357,-25.9546537],[31.8687838,-26.0037251],[31.4162062,-25.7277683],[31.3229117,-25.7438611],[31.2504595,-25.8296526],[31.1393001,-25.9162746],[31.1164727,-25.9912361],[30.9656135,-26.2665756],[30.8921689,-26.3279703],[30.8534616,-26.4035568],[30.8226943,-26.4488849],[30.8022583,-26.5240694],[30.8038369,-26.8082089],[30.9020939,-26.7807451],[30.9100338,-26.8489495],[30.9824859,-26.9082627],[30.976531,-27.0029222],[31.0034434,-27.0441587],[31.1543322,-27.1980416],[31.5015607,-27.311117],[31.9700183,-27.311117],[31.9700183,-27.120472],[31.9769658,-27.050664],[32.0002464,-26.7983892],[32.1069826,-26.7984645],[32.3114546,-26.8479493],[32.899986,-26.8516059],[32.886091,-26.9816971],[32.709427,-27.4785436],[32.6240724,-27.7775144],[32.5813951,-28.07479],[32.5387178,-28.2288046],[32.4275584,-28.5021568],[32.3640388,-28.5945699],[32.0702603,-28.8469827],[31.9878832,-28.9069497],[31.7764818,-28.969487],[31.4638459,-29.2859343],[31.359634,-29.3854348],[31.1680825,-29.6307408],[31.064863,-29.7893535],[31.0534493,-29.8470469],[31.0669933,-29.8640319],[31.0455459,-29.9502017],[30.9518556,-30.0033946],[30.8651833,-30.1024093],[30.7244725,-30.392502],[30.3556256,-30.9308873],[30.0972364,-31.2458274],[29.8673136,-31.4304296],[29.7409393,-31.5014699],[29.481312,-31.6978686],[28.8943171,-32.2898903],[28.5497137,-32.5894641],[28.1436499,-32.8320732],[28.0748735,-32.941689],[27.8450942,-33.082869],[27.3757956,-33.3860685],[26.8805407,-33.6458951],[26.5916871,-33.7480756],[26.4527308,-33.7935795],[26.206754,-33.7548943],[26.0077897,-33.7223961],[25.8055494,-33.7524272],[25.7511073,-33.8006512],[25.6529079,-33.8543597],[25.6529079,-33.9469768],[25.7195789,-34.0040115],[25.7202807,-34.0511235],[25.5508915,-34.063151],[25.3504571,-34.0502627],[25.2810609,-34.0020322],[25.0476316,-33.9994588],[24.954724,-34.0043594],[24.9496586,-34.1010363],[24.8770358,-34.1506456],[24.8762914,-34.2005281],[24.8532574,-34.2189562],[24.7645287,-34.2017946],[24.5001356,-34.2003254],[24.3486733,-34.1163824],[24.1988819,-34.1019039],[23.9963377,-34.0514443],[23.8017509,-34.0524332],[23.7493589,-34.0111855],[23.4973536,-34.009014],[23.4155191,-34.0434586],[23.4154284,-34.1140433],[22.9000853,-34.0993009],[22.8412418,-34.0547911],[22.6470321,-34.0502627],[22.6459843,-34.0072768],[22.570016,-34.0064081],[22.5050499,-34.0645866],[22.2519968,-34.0645866],[22.2221334,-34.1014701],[22.1621197,-34.1057019],[22.1712431,-34.1521766],[22.1576913,-34.2180897],[22.0015632,-34.2172232],[21.9496952,-34.3220009],[21.8611528,-34.4007145],[21.5614708,-34.4020114],[21.5468011,-34.3661242],[21.501744,-34.3669892],[21.5006961,-34.4020114],[21.4194886,-34.4465247],[21.1978706,-34.4478208],[21.0988193,-34.3991325],[21.0033746,-34.3753872],[20.893192,-34.3997115],[20.8976647,-34.4854003],[20.7446802,-34.4828092],[20.5042011,-34.486264],[20.2527197,-34.701477],[20.0803502,-34.8361855],[19.9923317,-34.8379056],[19.899074,-34.8275845],[19.8938348,-34.7936018],[19.5972963,-34.7961833],[19.3929677,-34.642015],[19.2877095,-34.6404784],[19.2861377,-34.5986563],[19.3474363,-34.5244458],[19.3285256,-34.4534372],[19.098001,-34.449981],[19.0725583,-34.3802371],[19.0023531,-34.3525593],[18.9520568,-34.3949373],[18.7975006,-34.3936403],[18.7984174,-34.1016376],[18.501748,-34.1015292],[18.4999545,-34.3616945],[18.4477325,-34.3620007],[18.4479944,-34.3522691],[18.3974362,-34.3514041],[18.3971742,-34.3022959],[18.3565705,-34.3005647],[18.3479258,-34.2020436],[18.2972095,-34.1950274],[18.2951139,-33.9937138],[18.3374474,-33.9914079],[18.3476638,-33.8492427],[18.3479258,-33.781555],[18.4124718,-33.7448849],[18.3615477,-33.6501624],[18.2992013,-33.585591],[18.2166839,-33.448872],[18.1389858,-33.3974083],[17.9473472,-33.1602647],[17.8855247,-33.0575732],[17.8485884,-32.9668505],[17.8396817,-32.8507302],[17.8396817,-32.7983384]]],"best":true},{"id":"South-Tyrol-Orthofoto2011","name":"South Tyrol Orthofoto 2011","type":"tms","template":"http://geoservices.buergernetz.bz.it/geoserver/gwc/service/wmts/?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=P_BZ_OF_2011_EPSG3857&STYLE=default&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX=GoogleMapsCompatible%3A{zoom}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg","scaleExtent":[0,18],"polygon":[[[10.38615,46.68821],[10.39201,46.69016],[10.40215,46.70624],[10.41274,46.70821],[10.41622,46.71479],[10.4168,46.71847],[10.39934,46.73435],[10.43464,46.75356],[10.44107,46.75413],[10.44011,46.77149],[10.42123,46.78861],[10.42845,46.79755],[10.43851,46.79869],[10.44925,46.80462],[10.45602,46.81635],[10.45438,46.82221],[10.4583,46.82478],[10.45513,46.83059],[10.45906,46.83548],[10.46483,46.83624],[10.46229,46.8413],[10.46987,46.84933],[10.46819,46.8553],[10.47838,46.86013],[10.48372,46.85543],[10.49628,46.85305],[10.49931,46.84857],[10.52124,46.84653],[10.5527,46.8511],[10.55795,46.84695],[10.55264,46.8408],[10.55536,46.84087],[10.58883,46.85125],[10.59502,46.85829],[10.60936,46.8597],[10.62441,46.86558],[10.64858,46.86655],[10.66787,46.87651],[10.67297,46.87138],[10.69112,46.86861],[10.69786,46.86339],[10.69508,46.85308],[10.70594,46.84786],[10.71763,46.84795],[10.72333,46.83892],[10.75621,46.83383],[10.76481,46.82409],[10.76387,46.81971],[10.75239,46.81387],[10.74506,46.80223],[10.7276,46.79709],[10.73122,46.78925],[10.75722,46.78624],[10.77744,46.79149],[10.78678,46.79735],[10.81439,46.77662],[10.82479,46.77472],[10.83129,46.78138],[10.84112,46.78282],[10.85354,46.77506],[10.86845,46.77313],[10.86993,46.7669],[10.88294,46.76393],[10.88962,46.76529],[10.8951,46.77092],[10.90527,46.76911],[10.92299,46.7764],[10.92821,46.77408],[10.94388,46.77648],[10.97522,46.77361],[10.97932,46.77014],[10.99475,46.76804],[11.01397,46.77317],[11.02328,46.76715],[11.0346,46.79428],[11.04234,46.801],[11.03792,46.80562],[11.05633,46.80928],[11.07279,46.82092],[11.08171,46.82252],[11.0762,46.83384],[11.06887,46.83793],[11.07303,46.84345],[11.06988,46.85348],[11.08742,46.87927],[11.09961,46.88922],[11.09538,46.89178],[11.09795,46.89844],[11.0946,46.91247],[11.10792,46.91706],[11.10804,46.92632],[11.11418,46.93234],[11.13851,46.92865],[11.16322,46.94091],[11.16642,46.94479],[11.16114,46.94979],[11.1637,46.96677],[11.17598,46.96367],[11.18658,46.97062],[11.19527,46.97152],[11.20418,46.96877],[11.20688,46.96403],[11.22047,46.97025],[11.24139,46.9708],[11.24865,46.97517],[11.25582,46.97535],[11.26272,46.98169],[11.27662,46.98168],[11.28762,46.98699],[11.30709,46.98525],[11.3205,46.99345],[11.33765,46.98606],[11.34516,46.99169],[11.35932,46.99154],[11.37697,46.98025],[11.38324,46.97168],[11.40465,46.96609],[11.43929,46.97601],[11.45134,46.99294],[11.46803,46.99582],[11.46859,47.003],[11.47831,47.01201],[11.50238,47.01073],[11.50313,47.00808],[11.51366,47.00595],[11.51679,47.00091],[11.53381,46.99233],[11.53846,46.98519],[11.55297,46.99149],[11.57663,46.99657],[11.58,47.00277],[11.58879,47.00641],[11.59901,47.00657],[11.60944,47.01207],[11.62697,47.01437],[11.63629,47.00383],[11.66542,46.99304],[11.6885,46.99658],[11.71226,46.99416],[11.72897,46.97322],[11.74698,46.97013],[11.76411,46.97412],[11.78106,46.99342],[11.81526,46.991],[11.83564,46.99417],[11.84396,47.0025],[11.85192,47.0014],[11.86722,47.01252],[11.87393,47.01136],[11.8794,47.01714],[11.89137,47.01728],[11.91627,47.03422],[11.9329,47.03864],[11.94688,47.03464],[11.95457,47.04374],[11.96773,47.04158],[11.97912,47.0511],[11.98587,47.04815],[11.99534,47.05064],[12.02037,47.04821],[12.02968,47.05127],[12.03353,47.0583],[12.04276,47.06228],[12.07543,47.0605],[12.08035,47.06951],[12.09308,47.07791],[12.10329,47.07931],[12.11867,47.07445],[12.13561,47.08171],[12.15125,47.08049],[12.15997,47.08267],[12.18589,47.09322],[12.2278,47.08302],[12.24228,47.06892],[12.23786,47.0644],[12.21821,47.05795],[12.2182,47.04483],[12.20552,47.02595],[12.18048,47.02414],[12.16423,47.01782],[12.14786,47.02357],[12.12723,47.01218],[12.12285,47.00662],[12.1322,46.99339],[12.12974,46.98593],[12.13977,46.982],[12.13808,46.96514],[12.13328,46.96292],[12.13882,46.95764],[12.15927,46.95133],[12.1702,46.93758],[12.15414,46.91654],[12.14675,46.91413],[12.16205,46.908],[12.16959,46.91121],[12.19154,46.90682],[12.20106,46.8965],[12.2022,46.88806],[12.21663,46.87517],[12.22147,46.88084],[12.23125,46.88146],[12.2345,46.88919],[12.24162,46.89192],[12.27486,46.88512],[12.27979,46.87921],[12.27736,46.87319],[12.29326,46.86566],[12.2912,46.85704],[12.29733,46.84455],[12.30833,46.84137],[12.30726,46.83271],[12.285,46.81503],[12.29383,46.8027],[12.28905,46.79948],[12.28889,46.79427],[12.28232,46.79153],[12.28539,46.7839],[12.30943,46.78603],[12.35837,46.77583],[12.37036,46.74163],[12.38475,46.71745],[12.40283,46.70811],[12.41103,46.70701],[12.41522,46.70163],[12.42862,46.6997],[12.42943,46.69567],[12.44268,46.68979],[12.47501,46.68756],[12.4795,46.67969],[12.43473,46.66714],[12.40648,46.64167],[12.38115,46.64183],[12.37944,46.63733],[12.3915,46.62765],[12.38577,46.62154],[12.35939,46.61829],[12.34465,46.62376],[12.34034,46.63022],[12.33578,46.62732],[12.3172,46.62876],[12.31785,46.62355],[12.30802,46.61811],[12.28413,46.61623],[12.26982,46.62003],[12.25931,46.62809],[12.24502,46.62326],[12.24198,46.61586],[12.21241,46.60918],[12.20444,46.59836],[12.19228,46.59321],[12.19261,46.62059],[12.1818,46.6192],[12.17117,46.63275],[12.16062,46.63574],[12.1511,46.63215],[12.1436,46.6327],[12.13739,46.64122],[12.12342,46.64475],[12.10949,46.65204],[12.10609,46.65783],[12.09345,46.66123],[12.08826,46.66638],[12.07985,46.66686],[12.07038,46.67386],[12.07173,46.66064],[12.06686,46.65364],[12.07479,46.64329],[12.06837,46.63997],[12.06495,46.62121],[12.05448,46.61778],[12.05318,46.60989],[12.04613,46.60716],[12.05043,46.60016],[12.04763,46.58357],[12.03665,46.57668],[12.0266,46.55871],[12.02189,46.55791],[11.99941,46.53208],[11.99411,46.53345],[11.98704,46.54417],[11.96633,46.54363],[11.95094,46.53869],[11.94719,46.52879],[11.94147,46.52689],[11.93294,46.52631],[11.9121,46.532],[11.8904,46.52175],[11.85192,46.51682],[11.82849,46.50783],[11.82334,46.51315],[11.82391,46.52141],[11.81086,46.53146],[11.79385,46.52023],[11.79189,46.51322],[11.76157,46.50503],[11.74317,46.50391],[11.73202,46.50877],[11.71935,46.50916],[11.71524,46.51245],[11.69889,46.50218],[11.6672,46.49647],[11.64515,46.49743],[11.63849,46.50051],[11.63495,46.49486],[11.64297,46.49346],[11.65174,46.48271],[11.64536,46.47189],[11.64179,46.47439],[11.62679,46.4708],[11.62987,46.46377],[11.61882,46.44325],[11.62143,46.42539],[11.60161,46.39731],[11.60307,46.38924],[11.5932,46.38265],[11.56489,46.38018],[11.55878,46.35076],[11.55249,46.34418],[11.54423,46.34483],[11.53837,46.35015],[11.52445,46.35502],[11.47969,46.36277],[11.48052,46.3551],[11.46322,46.34922],[11.45556,46.33396],[11.42105,46.32441],[11.40517,46.32387],[11.39865,46.31426],[11.39994,46.30709],[11.39569,46.3083],[11.38188,46.30052],[11.36088,46.29906],[11.36078,46.29682],[11.38256,46.29177],[11.3871,46.28143],[11.39609,46.27423],[11.39862,46.264],[11.38756,46.26029],[11.37347,46.2629],[11.36836,46.26135],[11.35783,46.26481],[11.35495,46.27564],[11.33912,46.28306],[11.33379,46.29049],[11.33471,46.2962],[11.3129,46.28256],[11.31737,46.27303],[11.30645,46.25786],[11.29124,46.2604],[11.24743,46.22933],[11.20622,46.2187],[11.18267,46.22496],[11.17077,46.23806],[11.17994,46.24434],[11.18351,46.25269],[11.18935,46.25354],[11.19448,46.2461],[11.20029,46.25566],[11.16604,46.26129],[11.14885,46.27904],[11.13725,46.28336],[11.14293,46.28934],[11.15847,46.29059],[11.16439,46.2986],[11.1761,46.30346],[11.1847,46.32104],[11.18894,46.32151],[11.18696,46.32673],[11.1942,46.33016],[11.20204,46.34212],[11.19001,46.35984],[11.19263,46.36578],[11.20393,46.36765],[11.19792,46.37232],[11.21275,46.39804],[11.21345,46.40675],[11.20565,46.4166],[11.21026,46.4206],[11.20347,46.42682],[11.21416,46.43556],[11.21634,46.44255],[11.20903,46.45293],[11.21419,46.45807],[11.21736,46.45731],[11.21886,46.46199],[11.21626,46.47277],[11.20939,46.481],[11.20876,46.49346],[11.19608,46.50241],[11.1924,46.501],[11.18686,46.50734],[11.18002,46.49823],[11.17014,46.49635],[11.16095,46.4878],[11.12934,46.48058],[11.1103,46.49643],[11.10449,46.4948],[11.08812,46.50128],[11.08173,46.53021],[11.05915,46.51508],[11.03795,46.51357],[11.05006,46.50784],[11.05773,46.49235],[11.06278,46.4894],[11.06894,46.46619],[11.07625,46.45487],[11.0778,46.44569],[11.07301,46.44042],[11.05394,46.44849],[11.0414,46.44569],[11.02817,46.46116],[11.00952,46.46917],[11.00462,46.47607],[10.98695,46.48289],[10.96543,46.48103],[10.95791,46.46983],[10.93819,46.46578],[10.9325,46.45831],[10.93332,46.4528],[10.91305,46.44284],[10.89161,46.44366],[10.88324,46.44995],[10.88093,46.44579],[10.87162,46.4438],[10.86174,46.43509],[10.85113,46.43817],[10.80034,46.44185],[10.78906,46.45164],[10.77835,46.47112],[10.76934,46.47609],[10.76463,46.4848],[10.75906,46.48547],[10.74422,46.48333],[10.71753,46.46022],[10.69667,46.4573],[10.68293,46.44846],[10.66821,46.45122],[10.63303,46.44309],[10.61439,46.45098],[10.60128,46.46139],[10.59995,46.46766],[10.57672,46.47237],[10.55875,46.48187],[10.54986,46.49123],[10.53685,46.49062],[10.52657,46.49425],[10.49366,46.49719],[10.48141,46.49337],[10.45714,46.5096],[10.45124,46.53083],[10.45814,46.54215],[10.47056,46.54377],[10.46954,46.54856],[10.47617,46.55749],[10.47321,46.56701],[10.48305,46.5777],[10.48575,46.58921],[10.48221,46.59199],[10.48576,46.59805],[10.48291,46.60512],[10.49055,46.61394],[10.44632,46.63989],[10.40935,46.63389],[10.40011,46.63648],[10.39873,46.6455],[10.38946,46.65862],[10.39057,46.67089],[10.3803,46.68399],[10.38615,46.68821]]],"terms_url":"http://geoservices.buergernetz.bz.it/geokatalog/","terms_text":"© Autonomen Provinz Bozen/Provincia Autonoma di Bolzano CC-BY 3.0"},{"id":"South-Tyrol-Orthofoto2014","name":"South Tyrol Orthofoto 2014","type":"tms","template":"http://geoservices.buergernetz.bz.it/geoserver/gwc/service/wmts/?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=P_BZ_OF_2014_EPSG3857&STYLE=default&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX=GoogleMapsCompatible%3A{zoom}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg","scaleExtent":[0,18],"polygon":[[[12.23442,46.84254],[12.24913,46.82785],[12.24913,46.81945],[12.25753,46.81735],[12.26173,46.80686],[12.26594,46.80686],[12.26804,46.79637],[12.26173,46.79427],[12.27014,46.78587],[12.27224,46.76908],[12.28485,46.76698],[12.29745,46.7439],[12.30166,46.7439],[12.30166,46.7376],[12.28695,46.7376],[12.23652,46.72081],[12.18819,46.71451],[12.16298,46.70192],[12.10835,46.69353],[12.08944,46.68303],[12.05792,46.68093],[12.04531,46.67464],[12.03481,46.67464],[12.03061,46.68303],[12.0096,46.68303],[11.98438,46.66834],[11.94866,46.66414],[11.93816,46.65575],[11.90874,46.64525],[11.89193,46.64525],[11.8457,46.62846],[11.82049,46.62636],[11.80998,46.60748],[11.79528,46.60328],[11.78897,46.59069],[11.78057,46.58859],[11.76586,46.55501],[11.75325,46.54871],[11.73855,46.52982],[11.73224,46.52982],[11.72384,46.51513],[11.71543,46.51513],[11.71333,46.50254],[11.70913,46.50254],[11.70913,46.49624],[11.69652,46.48575],[11.69442,46.47735],[11.66711,46.47525],[11.66711,46.44587],[11.6608,46.44587],[11.64399,46.45846],[11.63769,46.45846],[11.63349,46.44587],[11.62508,46.44797],[11.62508,46.43957],[11.61878,46.43957],[11.61458,46.42278],[11.61037,46.42278],[11.61037,46.41649],[11.62508,46.41229],[11.62508,46.3934],[11.61458,46.38291],[11.60617,46.38291],[11.60407,46.37241],[11.58306,46.37241],[11.58306,46.34932],[11.55995,46.32414],[11.53894,46.32834],[11.53894,46.34513],[11.52423,46.34723],[11.50111,46.34723],[11.49901,46.32834],[11.48851,46.33044],[11.49271,46.32204],[11.41917,46.32414],[11.41707,46.25278],[11.35613,46.24858],[11.34773,46.25698],[11.34563,46.26747],[11.34143,46.26747],[11.33722,46.25068],[11.31201,46.24858],[11.30991,46.25278],[11.3015,46.25278],[11.2889,46.24019],[11.2889,46.2234],[11.25108,46.2234],[11.24898,46.2129],[11.16283,46.215],[11.16283,46.24858],[11.12711,46.24858],[11.13131,46.25278],[11.12291,46.25488],[11.12501,46.29895],[11.16283,46.29895],[11.16283,46.36821],[11.16703,46.36821],[11.16703,46.38081],[11.17543,46.3871],[11.17754,46.3997],[11.20485,46.3997],[11.20695,46.42068],[11.19014,46.42068],[11.19014,46.42698],[11.19435,46.42698],[11.19855,46.44167],[11.20485,46.44587],[11.20695,46.47315],[11.19014,46.47525],[11.18804,46.48365],[11.15232,46.47525],[11.08298,46.47525],[11.08088,46.43537],[11.04096,46.42068],[11.01154,46.42068],[10.99894,46.44587],[10.98843,46.44587],[10.98423,46.45217],[10.96952,46.45217],[10.96112,46.48365],[10.95691,46.48365],[10.95481,46.49414],[10.94851,46.49624],[10.94431,46.50673],[10.91069,46.49624],[10.90018,46.49624],[10.89808,46.51093],[10.85606,46.50254],[10.84135,46.54241],[10.86446,46.54661],[10.86236,46.55081],[10.76571,46.54031],[10.72158,46.55081],[10.59762,46.55291],[10.5619,46.54871],[10.53668,46.55291],[10.50096,46.54871],[10.48415,46.55501],[10.46314,46.55501],[10.47155,46.5676],[10.47365,46.59069],[10.47785,46.59069],[10.47785,46.61797],[10.46944,46.62636],[10.44843,46.63476],[10.42532,46.62846],[10.3938,46.63056],[10.3896,46.64525],[10.3812,46.64735],[10.3833,46.66414],[10.3791,46.66834],[10.3791,46.69353],[10.3854,46.72081],[10.3896,46.72081],[10.3938,46.7376],[10.41692,46.75229],[10.41692,46.78587],[10.42112,46.79847],[10.42532,46.79847],[10.42532,46.80686],[10.43373,46.81106],[10.43793,46.79007],[10.44423,46.78377],[10.44843,46.7439],[10.45264,46.7439],[10.45684,46.72711],[10.46104,46.72711],[10.46524,46.71032],[10.46944,46.71032],[10.47365,46.67254],[10.47995,46.67044],[10.48415,46.65575],[10.48836,46.65575],[10.48415,46.62846],[10.48836,46.62846],[10.48836,46.62217],[10.49886,46.62007],[10.52828,46.62427],[10.49886,46.63056],[10.49886,46.64525],[10.50516,46.64316],[10.49886,46.66204],[10.51777,46.65785],[10.58921,46.66204],[10.63123,46.65365],[10.79302,46.65575],[10.79723,46.65155],[10.88127,46.65155],[10.89178,46.65785],[10.9275,46.66414],[10.94431,46.67464],[10.98003,46.67464],[11.00104,46.68303],[11.02415,46.68303],[11.05147,46.69772],[11.12711,46.70822],[11.13971,46.71242],[11.14392,46.71871],[11.17543,46.72081],[11.19855,46.7334],[11.24898,46.7355],[11.25318,46.72291],[11.2952,46.72921],[11.30571,46.70822],[11.31831,46.70822],[11.33722,46.71871],[11.38555,46.72081],[11.43178,46.7376],[11.50952,46.7439],[11.54734,46.75649],[11.56835,46.75649],[11.58306,46.76698],[11.60617,46.76908],[11.61037,46.77538],[11.69862,46.79427],[11.71753,46.79427],[11.72174,46.79007],[11.73855,46.75859],[11.74905,46.75019],[11.76166,46.70192],[11.76586,46.70192],[11.78687,46.71661],[11.8331,46.72291],[11.86041,46.7376],[11.90874,46.7439],[11.92135,46.75229],[11.95286,46.75859],[11.95917,46.76488],[11.99489,46.77538],[12.00749,46.77538],[12.0096,46.77958],[12.03061,46.78168],[12.05792,46.79427],[12.09995,46.79847],[12.13566,46.81316],[12.15878,46.81316],[12.18609,46.82785],[12.21551,46.83205],[12.23442,46.84254]],[[11.97388,46.96637],[11.99489,46.96007],[11.99489,46.95587],[12.0096,46.95797],[12.0117,46.94748],[12.0159,46.94748],[12.0117,46.94118],[12.018,46.93908],[12.02851,46.92229],[12.00749,46.9118],[11.97388,46.9055],[11.95707,46.89501],[11.91714,46.88871],[11.85831,46.86982],[11.8394,46.86982],[11.80158,46.85303],[11.76166,46.84464],[11.74905,46.83415],[11.68181,46.81945],[11.67971,46.81526],[11.6545,46.81106],[11.64399,46.80476],[11.63769,46.80686],[11.63139,46.82155],[11.62508,46.82155],[11.62298,46.83205],[11.61037,46.84464],[11.61668,46.84884],[11.61458,46.85723],[11.61037,46.85723],[11.61668,46.86563],[11.64609,46.86563],[11.68602,46.88242],[11.69022,46.88871],[11.74905,46.89711],[11.75325,46.90341],[11.78057,46.9076],[11.80158,46.9202],[11.8457,46.92649],[11.87722,46.94118],[11.89613,46.94328],[11.92135,46.95797],[11.96757,46.96217],[11.97388,46.96637]]],"terms_url":"http://geoservices.buergernetz.bz.it/geokatalog/","terms_text":"© Autonomen Provinz Bozen/Provincia Autonoma di Bolzano CC-BY 3.0","best":true},{"id":"South-Tyrol-Topomap","name":"South Tyrol Topomap","type":"tms","template":"http://geoservices.buergernetz.bz.it/geoserver/gwc/service/wmts/?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=P_BZ_BASEMAP_TOPO&STYLE=default&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX=GoogleMapsCompatible%3A{zoom}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg","description":"Topographical basemap of South Tyrol","scaleExtent":[0,20],"polygon":[[[10.38615,46.68821],[10.39201,46.69016],[10.40215,46.70624],[10.41274,46.70821],[10.41622,46.71479],[10.4168,46.71847],[10.39934,46.73435],[10.43464,46.75356],[10.44107,46.75413],[10.44011,46.77149],[10.42123,46.78861],[10.42845,46.79755],[10.43851,46.79869],[10.44925,46.80462],[10.45602,46.81635],[10.45438,46.82221],[10.4583,46.82478],[10.45513,46.83059],[10.45906,46.83548],[10.46483,46.83624],[10.46229,46.8413],[10.46987,46.84933],[10.46819,46.8553],[10.47838,46.86013],[10.48372,46.85543],[10.49628,46.85305],[10.49931,46.84857],[10.52124,46.84653],[10.5527,46.8511],[10.55795,46.84695],[10.55264,46.8408],[10.55536,46.84087],[10.58883,46.85125],[10.59502,46.85829],[10.60936,46.8597],[10.62441,46.86558],[10.64858,46.86655],[10.66787,46.87651],[10.67297,46.87138],[10.69112,46.86861],[10.69786,46.86339],[10.69508,46.85308],[10.70594,46.84786],[10.71763,46.84795],[10.72333,46.83892],[10.75621,46.83383],[10.76481,46.82409],[10.76387,46.81971],[10.75239,46.81387],[10.74506,46.80223],[10.7276,46.79709],[10.73122,46.78925],[10.75722,46.78624],[10.77744,46.79149],[10.78678,46.79735],[10.81439,46.77662],[10.82479,46.77472],[10.83129,46.78138],[10.84112,46.78282],[10.85354,46.77506],[10.86845,46.77313],[10.86993,46.7669],[10.88294,46.76393],[10.88962,46.76529],[10.8951,46.77092],[10.90527,46.76911],[10.92299,46.7764],[10.92821,46.77408],[10.94388,46.77648],[10.97522,46.77361],[10.97932,46.77014],[10.99475,46.76804],[11.01397,46.77317],[11.02328,46.76715],[11.0346,46.79428],[11.04234,46.801],[11.03792,46.80562],[11.05633,46.80928],[11.07279,46.82092],[11.08171,46.82252],[11.0762,46.83384],[11.06887,46.83793],[11.07303,46.84345],[11.06988,46.85348],[11.08742,46.87927],[11.09961,46.88922],[11.09538,46.89178],[11.09795,46.89844],[11.0946,46.91247],[11.10792,46.91706],[11.10804,46.92632],[11.11418,46.93234],[11.13851,46.92865],[11.16322,46.94091],[11.16642,46.94479],[11.16114,46.94979],[11.1637,46.96677],[11.17598,46.96367],[11.18658,46.97062],[11.19527,46.97152],[11.20418,46.96877],[11.20688,46.96403],[11.22047,46.97025],[11.24139,46.9708],[11.24865,46.97517],[11.25582,46.97535],[11.26272,46.98169],[11.27662,46.98168],[11.28762,46.98699],[11.30709,46.98525],[11.3205,46.99345],[11.33765,46.98606],[11.34516,46.99169],[11.35932,46.99154],[11.37697,46.98025],[11.38324,46.97168],[11.40465,46.96609],[11.43929,46.97601],[11.45134,46.99294],[11.46803,46.99582],[11.46859,47.003],[11.47831,47.01201],[11.50238,47.01073],[11.50313,47.00808],[11.51366,47.00595],[11.51679,47.00091],[11.53381,46.99233],[11.53846,46.98519],[11.55297,46.99149],[11.57663,46.99657],[11.58,47.00277],[11.58879,47.00641],[11.59901,47.00657],[11.60944,47.01207],[11.62697,47.01437],[11.63629,47.00383],[11.66542,46.99304],[11.6885,46.99658],[11.71226,46.99416],[11.72897,46.97322],[11.74698,46.97013],[11.76411,46.97412],[11.78106,46.99342],[11.81526,46.991],[11.83564,46.99417],[11.84396,47.0025],[11.85192,47.0014],[11.86722,47.01252],[11.87393,47.01136],[11.8794,47.01714],[11.89137,47.01728],[11.91627,47.03422],[11.9329,47.03864],[11.94688,47.03464],[11.95457,47.04374],[11.96773,47.04158],[11.97912,47.0511],[11.98587,47.04815],[11.99534,47.05064],[12.02037,47.04821],[12.02968,47.05127],[12.03353,47.0583],[12.04276,47.06228],[12.07543,47.0605],[12.08035,47.06951],[12.09308,47.07791],[12.10329,47.07931],[12.11867,47.07445],[12.13561,47.08171],[12.15125,47.08049],[12.15997,47.08267],[12.18589,47.09322],[12.2278,47.08302],[12.24228,47.06892],[12.23786,47.0644],[12.21821,47.05795],[12.2182,47.04483],[12.20552,47.02595],[12.18048,47.02414],[12.16423,47.01782],[12.14786,47.02357],[12.12723,47.01218],[12.12285,47.00662],[12.1322,46.99339],[12.12974,46.98593],[12.13977,46.982],[12.13808,46.96514],[12.13328,46.96292],[12.13882,46.95764],[12.15927,46.95133],[12.1702,46.93758],[12.15414,46.91654],[12.14675,46.91413],[12.16205,46.908],[12.16959,46.91121],[12.19154,46.90682],[12.20106,46.8965],[12.2022,46.88806],[12.21663,46.87517],[12.22147,46.88084],[12.23125,46.88146],[12.2345,46.88919],[12.24162,46.89192],[12.27486,46.88512],[12.27979,46.87921],[12.27736,46.87319],[12.29326,46.86566],[12.2912,46.85704],[12.29733,46.84455],[12.30833,46.84137],[12.30726,46.83271],[12.285,46.81503],[12.29383,46.8027],[12.28905,46.79948],[12.28889,46.79427],[12.28232,46.79153],[12.28539,46.7839],[12.30943,46.78603],[12.35837,46.77583],[12.37036,46.74163],[12.38475,46.71745],[12.40283,46.70811],[12.41103,46.70701],[12.41522,46.70163],[12.42862,46.6997],[12.42943,46.69567],[12.44268,46.68979],[12.47501,46.68756],[12.4795,46.67969],[12.43473,46.66714],[12.40648,46.64167],[12.38115,46.64183],[12.37944,46.63733],[12.3915,46.62765],[12.38577,46.62154],[12.35939,46.61829],[12.34465,46.62376],[12.34034,46.63022],[12.33578,46.62732],[12.3172,46.62876],[12.31785,46.62355],[12.30802,46.61811],[12.28413,46.61623],[12.26982,46.62003],[12.25931,46.62809],[12.24502,46.62326],[12.24198,46.61586],[12.21241,46.60918],[12.20444,46.59836],[12.19228,46.59321],[12.19261,46.62059],[12.1818,46.6192],[12.17117,46.63275],[12.16062,46.63574],[12.1511,46.63215],[12.1436,46.6327],[12.13739,46.64122],[12.12342,46.64475],[12.10949,46.65204],[12.10609,46.65783],[12.09345,46.66123],[12.08826,46.66638],[12.07985,46.66686],[12.07038,46.67386],[12.07173,46.66064],[12.06686,46.65364],[12.07479,46.64329],[12.06837,46.63997],[12.06495,46.62121],[12.05448,46.61778],[12.05318,46.60989],[12.04613,46.60716],[12.05043,46.60016],[12.04763,46.58357],[12.03665,46.57668],[12.0266,46.55871],[12.02189,46.55791],[11.99941,46.53208],[11.99411,46.53345],[11.98704,46.54417],[11.96633,46.54363],[11.95094,46.53869],[11.94719,46.52879],[11.94147,46.52689],[11.93294,46.52631],[11.9121,46.532],[11.8904,46.52175],[11.85192,46.51682],[11.82849,46.50783],[11.82334,46.51315],[11.82391,46.52141],[11.81086,46.53146],[11.79385,46.52023],[11.79189,46.51322],[11.76157,46.50503],[11.74317,46.50391],[11.73202,46.50877],[11.71935,46.50916],[11.71524,46.51245],[11.69889,46.50218],[11.6672,46.49647],[11.64515,46.49743],[11.63849,46.50051],[11.63495,46.49486],[11.64297,46.49346],[11.65174,46.48271],[11.64536,46.47189],[11.64179,46.47439],[11.62679,46.4708],[11.62987,46.46377],[11.61882,46.44325],[11.62143,46.42539],[11.60161,46.39731],[11.60307,46.38924],[11.5932,46.38265],[11.56489,46.38018],[11.55878,46.35076],[11.55249,46.34418],[11.54423,46.34483],[11.53837,46.35015],[11.52445,46.35502],[11.47969,46.36277],[11.48052,46.3551],[11.46322,46.34922],[11.45556,46.33396],[11.42105,46.32441],[11.40517,46.32387],[11.39865,46.31426],[11.39994,46.30709],[11.39569,46.3083],[11.38188,46.30052],[11.36088,46.29906],[11.36078,46.29682],[11.38256,46.29177],[11.3871,46.28143],[11.39609,46.27423],[11.39862,46.264],[11.38756,46.26029],[11.37347,46.2629],[11.36836,46.26135],[11.35783,46.26481],[11.35495,46.27564],[11.33912,46.28306],[11.33379,46.29049],[11.33471,46.2962],[11.3129,46.28256],[11.31737,46.27303],[11.30645,46.25786],[11.29124,46.2604],[11.24743,46.22933],[11.20622,46.2187],[11.18267,46.22496],[11.17077,46.23806],[11.17994,46.24434],[11.18351,46.25269],[11.18935,46.25354],[11.19448,46.2461],[11.20029,46.25566],[11.16604,46.26129],[11.14885,46.27904],[11.13725,46.28336],[11.14293,46.28934],[11.15847,46.29059],[11.16439,46.2986],[11.1761,46.30346],[11.1847,46.32104],[11.18894,46.32151],[11.18696,46.32673],[11.1942,46.33016],[11.20204,46.34212],[11.19001,46.35984],[11.19263,46.36578],[11.20393,46.36765],[11.19792,46.37232],[11.21275,46.39804],[11.21345,46.40675],[11.20565,46.4166],[11.21026,46.4206],[11.20347,46.42682],[11.21416,46.43556],[11.21634,46.44255],[11.20903,46.45293],[11.21419,46.45807],[11.21736,46.45731],[11.21886,46.46199],[11.21626,46.47277],[11.20939,46.481],[11.20876,46.49346],[11.19608,46.50241],[11.1924,46.501],[11.18686,46.50734],[11.18002,46.49823],[11.17014,46.49635],[11.16095,46.4878],[11.12934,46.48058],[11.1103,46.49643],[11.10449,46.4948],[11.08812,46.50128],[11.08173,46.53021],[11.05915,46.51508],[11.03795,46.51357],[11.05006,46.50784],[11.05773,46.49235],[11.06278,46.4894],[11.06894,46.46619],[11.07625,46.45487],[11.0778,46.44569],[11.07301,46.44042],[11.05394,46.44849],[11.0414,46.44569],[11.02817,46.46116],[11.00952,46.46917],[11.00462,46.47607],[10.98695,46.48289],[10.96543,46.48103],[10.95791,46.46983],[10.93819,46.46578],[10.9325,46.45831],[10.93332,46.4528],[10.91305,46.44284],[10.89161,46.44366],[10.88324,46.44995],[10.88093,46.44579],[10.87162,46.4438],[10.86174,46.43509],[10.85113,46.43817],[10.80034,46.44185],[10.78906,46.45164],[10.77835,46.47112],[10.76934,46.47609],[10.76463,46.4848],[10.75906,46.48547],[10.74422,46.48333],[10.71753,46.46022],[10.69667,46.4573],[10.68293,46.44846],[10.66821,46.45122],[10.63303,46.44309],[10.61439,46.45098],[10.60128,46.46139],[10.59995,46.46766],[10.57672,46.47237],[10.55875,46.48187],[10.54986,46.49123],[10.53685,46.49062],[10.52657,46.49425],[10.49366,46.49719],[10.48141,46.49337],[10.45714,46.5096],[10.45124,46.53083],[10.45814,46.54215],[10.47056,46.54377],[10.46954,46.54856],[10.47617,46.55749],[10.47321,46.56701],[10.48305,46.5777],[10.48575,46.58921],[10.48221,46.59199],[10.48576,46.59805],[10.48291,46.60512],[10.49055,46.61394],[10.44632,46.63989],[10.40935,46.63389],[10.40011,46.63648],[10.39873,46.6455],[10.38946,46.65862],[10.39057,46.67089],[10.3803,46.68399],[10.38615,46.68821]]],"terms_url":"http://geoservices.buergernetz.bz.it/geokatalog/","terms_text":"© Autonomen Provinz Bozen/Provincia Autonoma di Bolzano"},{"id":"Bern-bern2016-tms","name":"Stadt Bern 10cm (2016)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/bern2016/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,21],"polygon":[[[7.2943145,46.9237564],[7.2982665,46.9274715],[7.3061586,46.9309487],[7.3043338,46.9362344],[7.3068603,46.9403709],[7.3246431,46.9432765],[7.3284525,46.946409],[7.3414051,46.9460797],[7.3438454,46.9473713],[7.3434554,46.9487937],[7.3513567,46.9485481],[7.3505628,46.950213],[7.3530901,46.9519266],[7.3582028,46.9511773],[7.3685031,46.9566244],[7.3715097,46.9607339],[7.37503,46.959835],[7.3785111,46.9614686],[7.3806232,46.9654741],[7.3832097,46.9663014],[7.3937998,46.9669268],[7.4000528,46.9691779],[7.4082922,46.9686857],[7.4281713,46.9738041],[7.4327053,46.972689],[7.4353602,46.9684345],[7.4378522,46.9684302],[7.4412474,46.9767865],[7.4456893,46.9747939],[7.4483835,46.9756393],[7.4477006,46.9790125],[7.4440468,46.9780682],[7.4412738,46.9798224],[7.4506732,46.9901527],[7.4522112,46.9896803],[7.454649,46.9778182],[7.4680382,46.9758258],[7.4707923,46.969998],[7.4701907,46.9674116],[7.4781618,46.9711823],[7.4845237,46.9701571],[7.4861275,46.9679018],[7.4857945,46.9646828],[7.4784708,46.9629043],[7.4802865,46.9606768],[7.4789304,46.9587841],[7.4797786,46.9566019],[7.4770135,46.9544586],[7.4840504,46.9499938],[7.4833925,46.9451977],[7.4955563,46.9396169],[7.4935119,46.9376594],[7.4908036,46.9387617],[7.4894997,46.9368667],[7.4766667,46.9369496],[7.4781093,46.9362489],[7.4746986,46.9339187],[7.4753537,46.9329898],[7.4691047,46.9292427],[7.4707683,46.9255044],[7.4585674,46.934836],[7.4476373,46.9304297],[7.435418,46.9349668],[7.4338022,46.9331237],[7.4376403,46.9307415],[7.4146941,46.9368183],[7.413844,46.9315682],[7.4070798,46.9303824],[7.408065,46.9256296],[7.4021268,46.9241992],[7.4014835,46.9211927],[7.3875736,46.9304506],[7.3823129,46.927282],[7.3800187,46.9298929],[7.3808694,46.9324085],[7.3748669,46.9314306],[7.3748901,46.9327104],[7.368066,46.9323929],[7.3683058,46.930426],[7.3604074,46.9285884],[7.3605592,46.9272018],[7.338783,46.9245357],[7.3393683,46.9196675],[7.3274574,46.9190326],[7.3269178,46.9235974],[7.324374,46.9251891],[7.3082264,46.9222857],[7.2943145,46.9237564]]],"terms_text":"Orthophoto 2016, Vermessungsamt Stadt Bern ","best":true},{"id":"Uster-2008","name":"Stadt Uster Orthophoto 2008 10cm","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/uster/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","polygon":[[[8.6,47.31],[8.6,47.39],[8.77,47.39],[8.77,47.31],[8.6,47.31]]],"terms_text":"Stadt Uster Vermessung Orthophoto 2008"},{"id":"Zuerich-zh_luftbild2011-tms","name":"Stadt Zürich Luftbild 2011","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/zh_luftbild2011/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","polygon":[[[8.4441,47.3141],[8.4441,47.4411],[8.6284,47.4411],[8.6284,47.3141],[8.4441,47.3141]]],"terms_text":"Stadt Zürich Luftbild 2011"},{"id":"Zuerich-city_map","name":"Stadtplan Zürich","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/zh_stadtplan/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","polygon":[[[8.4482,47.321],[8.4482,47.4339],[8.6248,47.4339],[8.6248,47.321],[8.4482,47.321]]],"terms_text":"Stadt Zürich Open Government Data"},{"id":"stamen-terrain-background","name":"Stamen Terrain","type":"tms","template":"http://{switch:a,b,c,d}.tile.stamen.com/terrain-background/{zoom}/{x}/{y}.jpg","scaleExtent":[4,18],"terms_url":"http://maps.stamen.com/#terrain","terms_text":"Map tiles by Stamen Design, under CC BY 3.0"},{"id":"Stevns_Denmark","name":"Stevns (Denmark)","type":"tms","template":"http://{switch:a,b,c}.tile.openstreetmap.dk/stevns/2009/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[12.0913942,55.3491574],[12.0943104,55.3842256],[12.1573875,55.3833103],[12.1587287,55.4013326],[12.1903468,55.400558],[12.1931411,55.4364665],[12.2564251,55.4347995],[12.2547073,55.4168882],[12.3822489,55.4134349],[12.3795942,55.3954143],[12.4109213,55.3946958],[12.409403,55.3766417],[12.4407807,55.375779],[12.4394142,55.3578314],[12.4707413,55.3569971],[12.4629475,55.2672214],[12.4315633,55.2681491],[12.430045,55.2502103],[12.3672011,55.2519673],[12.3656858,55.2340267],[12.2714604,55.2366031],[12.2744467,55.272476],[12.2115654,55.2741475],[12.2130078,55.2920322],[12.1815665,55.2928638],[12.183141,55.3107091],[12.2144897,55.3100981],[12.2159927,55.3279764],[12.1214458,55.3303379],[12.1229489,55.3483291],[12.0913942,55.3491574]]],"terms_text":"Stevns Kommune"},{"id":"Surrey-Air_Survey","name":"Surrey Air Survey","type":"tms","template":"http://gravitystorm.dev.openstreetmap.org/surrey/{zoom}/{x}/{y}.png","scaleExtent":[8,19],"polygon":[[[-0.752478,51.0821941],[-0.7595183,51.0856254],[-0.8014342,51.1457917],[-0.8398864,51.1440686],[-0.8357665,51.1802397],[-0.8529549,51.2011266],[-0.8522683,51.2096231],[-0.8495217,51.217903],[-0.8266907,51.2403696],[-0.8120995,51.2469248],[-0.7736474,51.2459577],[-0.7544213,51.2381127],[-0.754078,51.233921],[-0.7446366,51.2333836],[-0.7430693,51.2847178],[-0.751503,51.3069524],[-0.7664376,51.3121032],[-0.7820588,51.3270157],[-0.7815438,51.3388135],[-0.7374268,51.3720456],[-0.7192307,51.3769748],[-0.6795769,51.3847961],[-0.6807786,51.3901523],[-0.6531411,51.3917591],[-0.6301385,51.3905808],[-0.6291085,51.3970074],[-0.6234437,51.3977572],[-0.613144,51.4295552],[-0.6002471,51.4459121],[-0.5867081,51.4445365],[-0.5762368,51.453202],[-0.5626755,51.4523462],[-0.547741,51.4469972],[-0.5372697,51.4448575],[-0.537098,51.4526671],[-0.5439644,51.4545926],[-0.5405312,51.4698865],[-0.5309182,51.4760881],[-0.5091172,51.4744843],[-0.5086022,51.4695657],[-0.4900628,51.4682825],[-0.4526406,51.4606894],[-0.4486924,51.4429316],[-0.4414826,51.4418616],[-0.4418259,51.4369394],[-0.4112702,51.4380095],[-0.4014855,51.4279498],[-0.3807145,51.4262372],[-0.3805428,51.4161749],[-0.3491288,51.4138195],[-0.3274994,51.4037544],[-0.3039818,51.3990424],[-0.3019219,51.3754747],[-0.309475,51.369688],[-0.3111916,51.3529669],[-0.2955704,51.3541462],[-0.2923089,51.3673303],[-0.2850991,51.3680805],[-0.2787476,51.3771891],[-0.2655297,51.3837247],[-0.2411538,51.3847961],[-0.2123147,51.3628288],[-0.2107697,51.3498578],[-0.190857,51.3502867],[-0.1542931,51.3338802],[-0.1496583,51.3057719],[-0.1074296,51.2966491],[-0.0887185,51.3099571],[-0.0878602,51.3220811],[-0.0652009,51.3215448],[-0.0641709,51.3264793],[-0.0519829,51.3263721],[-0.0528412,51.334631],[-0.0330779,51.3430876],[0.0019187,51.3376339],[0.0118751,51.3281956],[0.013935,51.2994398],[0.0202865,51.2994398],[0.0240631,51.3072743],[0.0331611,51.3086694],[0.0455207,51.30545],[0.0523872,51.2877392],[0.0616569,51.2577764],[0.0640602,51.2415518],[0.0462074,51.2126342],[0.0407142,51.2109136],[0.0448341,51.1989753],[0.0494689,51.1997283],[0.0558204,51.1944573],[0.0611419,51.1790713],[0.0623435,51.1542061],[0.0577087,51.1417146],[0.0204582,51.1365447],[-0.0446015,51.1336364],[-0.1566964,51.1352522],[-0.1572114,51.1290043],[-0.2287942,51.1183379],[-0.2473336,51.1183379],[-0.2500802,51.1211394],[-0.299347,51.1137042],[-0.3221779,51.1119799],[-0.3223496,51.1058367],[-0.3596001,51.1019563],[-0.3589135,51.1113333],[-0.3863793,51.1117644],[-0.3869014,51.1062516],[-0.4281001,51.0947174],[-0.4856784,51.0951554],[-0.487135,51.0872266],[-0.5297404,51.0865404],[-0.5302259,51.0789914],[-0.61046,51.076551],[-0.6099745,51.080669],[-0.6577994,51.0792202],[-0.6582849,51.0743394],[-0.6836539,51.0707547],[-0.6997979,51.070831],[-0.7296581,51.0744919],[-0.752478,51.0821941]]]},{"id":"Szeged_2011","name":"Szeged orthophoto 2011","type":"tms","template":"http://e.tile.openstreetmap.hu/szeged-2011-10cm/{zoom}/{x}/{y}.png","scaleExtent":[10,22],"polygon":[[[20.1459914,46.2281144],[20.1332261,46.2290431],[20.1258373,46.2298686],[20.122329,46.2309893],[20.1208484,46.2317537],[20.1189709,46.2335126],[20.1131237,46.2413638],[20.1120293,46.2433005],[20.1115733,46.2449996],[20.1111871,46.247092],[20.1112944,46.2487725],[20.1115948,46.2509686],[20.1122171,46.2528047],[20.1129949,46.2542681],[20.1135421,46.2553549],[20.1147705,46.2567977],[20.1352251,46.2768529],[20.1366386,46.2775055],[20.1378939,46.2780301],[20.1393932,46.2783508],[20.1408818,46.2784583],[20.1611494,46.278159],[20.1621093,46.2781579],[20.1635894,46.277702],[20.1661777,46.2761484],[20.1687795,46.2738569],[20.1696108,46.2714413],[20.1695895,46.2704465],[20.1700871,46.2704418],[20.1739897,46.2643295],[20.1766182,46.2582878],[20.1947983,46.25492],[20.1858719,46.2448077],[20.1846595,46.2453122],[20.1780371,46.2383112],[20.1781766,46.2377101],[20.1795258,46.2370961],[20.1725666,46.2300241],[20.1698349,46.2350404],[20.1687701,46.2362946],[20.1670262,46.2378475],[20.1659431,46.2387342],[20.1654408,46.2389988],[20.1654837,46.2389988],[20.1635177,46.2401383],[20.1602051,46.2412003],[20.1592684,46.241531],[20.1592684,46.2415751],[20.1583504,46.2418505],[20.1549473,46.2422869],[20.1510796,46.2351538],[20.1493804,46.232459],[20.1459914,46.2281144]]],"terms_url":"http://www.geo.u-szeged.hu/","terms_text":"SZTE TFGT - University of Szeged","best":true},{"id":"tnris.org","name":"Texas Orthophoto","type":"tms","template":"https://txgi.tnris.org/login/path/ecology-fiona-poem-romeo/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=texas&STYLE=&FORMAT=image/png&tileMatrixSet=0to20&tileMatrix=0to20:{zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,20],"polygon":[[[-99.9985439,34.5601834],[-95.55654502453,33.99257450647],[-93.89679027134,33.61039304449],[-93.98468089634,32.04103124103],[-93.41613841587,31.02505269211],[-93.74531484297,29.57268254375],[-96.50492070332,28.23158511753],[-97.36942054453,26.95467452634],[-97.04866958924,25.80530249434],[-99.0734177889,26.32559221139],[-100.76599193149,29.02531904433],[-102.3315436893,29.8433892263],[-103.13354564242,28.88112103669],[-104.2887874222,29.28831477845],[-104.7269783935,29.94815782859],[-104.72696778796,30.23535241761],[-106.53450082091,31.78456647831],[-106.75767043939,31.78457253947],[-106.75766067978,32.04385536686],[-106.61848436611,32.04385159755],[-103.11949492759,32.04375683439],[-103.09544343487,36.50045758762],[-103.05798056071,36.54268645422],[-100.00042146824,36.54222227302],[-99.9985439,34.5601834]]],"terms_url":"https://tnris.org/maps-and-data/online-mapping-services/"},{"id":"tf-landscape","name":"Thunderforest Landscape","type":"tms","template":"https://{switch:a,b,c}.tile.thunderforest.com/landscape/{zoom}/{x}/{y}.png","scaleExtent":[0,22],"terms_url":"http://www.thunderforest.com/terms/","terms_text":"Maps © Thunderforest, Data © OpenStreetMap contributors"},{"id":"lu.geoportail.opendata.topo","name":"Topographical Map geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/topo/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/cartes-topographiques-services-wms-et-wmts/","terms_text":"Administration du Cadastre et de la Topographie"},{"id":"Toulouse-Orthophotoplan-2007","name":"Toulouse - Orthophotoplan 2007","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/toulouse_ortho2007/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[1.1919978,43.6328791],[1.2015377,43.6329729],[1.2011107,43.6554932],[1.2227985,43.6557029],[1.2226231,43.6653353],[1.2275341,43.6653849],[1.2275417,43.6656387],[1.2337568,43.6656883],[1.2337644,43.6650153],[1.2351218,43.6650319],[1.2350913,43.6670729],[1.2443566,43.6671556],[1.2441584,43.6743925],[1.2493973,43.6744256],[1.2493973,43.6746628],[1.2555666,43.6747234],[1.2555742,43.6744532],[1.2569545,43.6744697],[1.2568782,43.678529],[1.2874873,43.6788257],[1.2870803,43.7013229],[1.3088219,43.7014632],[1.3086493,43.7127673],[1.3303262,43.7129544],[1.3300242,43.7305221],[1.3367106,43.7305845],[1.3367322,43.7312235],[1.3734338,43.7310456],[1.3735848,43.7245772],[1.4604504,43.7252947],[1.4607783,43.7028034],[1.4824875,43.7029516],[1.4829828,43.6692071],[1.5046832,43.6693616],[1.5048383,43.6581174],[1.5265475,43.6582656],[1.5266945,43.6470298],[1.548368,43.6471633],[1.5485357,43.6359385],[1.5702172,43.636082],[1.5705123,43.6135777],[1.5488166,43.6134276],[1.549097,43.5909479],[1.5707695,43.5910694],[1.5709373,43.5798341],[1.5793714,43.5798894],[1.5794782,43.5737682],[1.5809119,43.5737792],[1.5810859,43.5573794],[1.5712334,43.5573131],[1.5716504,43.5235497],[1.3984804,43.5222618],[1.3986509,43.5110113],[1.3120959,43.5102543],[1.3118968,43.5215192],[1.2902569,43.5213126],[1.2898637,43.5438168],[1.311517,43.5440133],[1.3113271,43.5552596],[1.3036924,43.5551924],[1.3036117,43.5595099],[1.2955449,43.5594317],[1.2955449,43.5595489],[1.2895595,43.5594473],[1.2892899,43.5775366],[1.2675698,43.5773647],[1.2673973,43.5886141],[1.25355,43.5885047],[1.2533774,43.5956282],[1.2518029,43.5956282],[1.2518029,43.5949409],[1.2350437,43.5947847],[1.2350437,43.5945972],[1.2239572,43.5945972],[1.2239357,43.5994708],[1.2139708,43.599299],[1.2138845,43.6046408],[1.2020647,43.6044846],[1.2019464,43.61048],[1.1924294,43.6103695],[1.1919978,43.6328791]]],"terms_url":"https://wiki.openstreetmap.org/wiki/Toulouse/ToulouseMetropoleData","terms_text":"ToulouseMetropole"},{"id":"Toulouse-Orthophotoplan-2011","name":"Toulouse - Orthophotoplan 2011","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/toulouse_ortho2011/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[1.1135067,43.6867566],[1.1351836,43.6870842],[1.1348907,43.6983471],[1.1782867,43.6990338],[1.1779903,43.7102786],[1.1996591,43.7106144],[1.1993387,43.7218722],[1.2427356,43.7225269],[1.2424336,43.7337491],[1.2641536,43.734092],[1.2638301,43.7453588],[1.2855285,43.7456548],[1.2852481,43.756935],[1.306925,43.757231],[1.3066446,43.7684779],[1.3283431,43.7687894],[1.3280842,43.780034],[1.4367275,43.7815757],[1.4373098,43.7591004],[1.4590083,43.7593653],[1.4593318,43.7481479],[1.4810303,43.7483972],[1.4813322,43.7371777],[1.5030307,43.7374115],[1.5035915,43.7149664],[1.5253115,43.7151846],[1.5256135,43.7040057],[1.5472688,43.7042552],[1.5475708,43.6930431],[1.5692045,43.6932926],[1.5695712,43.6820316],[1.5912049,43.6822656],[1.5917441,43.6597998],[1.613421,43.6600339],[1.613723,43.6488291],[1.6353783,43.6490788],[1.6384146,43.5140731],[1.2921649,43.5094658],[1.2918629,43.5206966],[1.2702076,43.5203994],[1.2698841,43.5316437],[1.2482288,43.531331],[1.2476048,43.5537788],[1.2259628,43.5534914],[1.2256819,43.564716],[1.2039835,43.564419],[1.2033148,43.5869049],[1.1816164,43.5865611],[1.1810237,43.6090368],[1.1592821,43.6086932],[1.1589585,43.6199523],[1.1372601,43.6196244],[1.1365933,43.642094],[1.1149055,43.6417629],[1.1135067,43.6867566]]],"terms_url":"https://wiki.openstreetmap.org/wiki/Toulouse/ToulouseMetropoleData","terms_text":"ToulouseMetropole"},{"id":"Toulouse-Orthophotoplan-2013","name":"Toulouse - Orthophotoplan 2013","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/toulouse_2013/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[1.1135067,43.6867566],[1.1351836,43.6870842],[1.1348907,43.6983471],[1.1782867,43.6990338],[1.1779903,43.7102786],[1.1996591,43.7106144],[1.1993387,43.7218722],[1.2427356,43.7225269],[1.2424336,43.7337491],[1.2641536,43.734092],[1.2638301,43.7453588],[1.2855285,43.7456548],[1.2852481,43.756935],[1.306925,43.757231],[1.3066446,43.7684779],[1.3283431,43.7687894],[1.3280842,43.780034],[1.4367275,43.7815757],[1.4373098,43.7591004],[1.4590083,43.7593653],[1.4593318,43.7481479],[1.4810303,43.7483972],[1.4813322,43.7371777],[1.5030307,43.7374115],[1.5035915,43.7149664],[1.5253115,43.7151846],[1.5256135,43.7040057],[1.5472688,43.7042552],[1.5475708,43.6930431],[1.5692045,43.6932926],[1.5695712,43.6820316],[1.5912049,43.6822656],[1.5917441,43.6597998],[1.613421,43.6600339],[1.613723,43.6488291],[1.6353783,43.6490788],[1.6384146,43.5140731],[1.2921649,43.5094658],[1.2918629,43.5206966],[1.2702076,43.5203994],[1.2698841,43.5316437],[1.2482288,43.531331],[1.2476048,43.5537788],[1.2259628,43.5534914],[1.2256819,43.564716],[1.2039835,43.564419],[1.2033148,43.5869049],[1.1816164,43.5865611],[1.1810237,43.6090368],[1.1592821,43.6086932],[1.1589585,43.6199523],[1.1372601,43.6196244],[1.1365933,43.642094],[1.1149055,43.6417629],[1.1135067,43.6867566]]],"terms_url":"https://wiki.openstreetmap.org/wiki/Toulouse/ToulouseMetropoleData","terms_text":"ToulouseMetropole"},{"id":"Toulouse-Orthophotoplan-2015","name":"Toulouse - Orthophotoplan 2015","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/toulouse_2015/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[1.1135067,43.6867566],[1.1351836,43.6870842],[1.1348907,43.6983471],[1.1782867,43.6990338],[1.1779903,43.7102786],[1.1996591,43.7106144],[1.1993387,43.7218722],[1.2427356,43.7225269],[1.2424336,43.7337491],[1.2641536,43.734092],[1.2638301,43.7453588],[1.2855285,43.7456548],[1.2852481,43.756935],[1.306925,43.757231],[1.3066446,43.7684779],[1.3283431,43.7687894],[1.3280842,43.780034],[1.4367275,43.7815757],[1.4373098,43.7591004],[1.4590083,43.7593653],[1.4593318,43.7481479],[1.4810303,43.7483972],[1.4813322,43.7371777],[1.5030307,43.7374115],[1.5035915,43.7149664],[1.5253115,43.7151846],[1.5256135,43.7040057],[1.5472688,43.7042552],[1.5475708,43.6930431],[1.5692045,43.6932926],[1.5695712,43.6820316],[1.5912049,43.6822656],[1.5917441,43.6597998],[1.613421,43.6600339],[1.613723,43.6488291],[1.6353783,43.6490788],[1.6384146,43.5140731],[1.2921649,43.5094658],[1.2918629,43.5206966],[1.2702076,43.5203994],[1.2698841,43.5316437],[1.2482288,43.531331],[1.2476048,43.5537788],[1.2259628,43.5534914],[1.2256819,43.564716],[1.2039835,43.564419],[1.2033148,43.5869049],[1.1816164,43.5865611],[1.1810237,43.6090368],[1.1592821,43.6086932],[1.1589585,43.6199523],[1.1372601,43.6196244],[1.1365933,43.642094],[1.1149055,43.6417629],[1.1135067,43.6867566]]],"terms_url":"https://wiki.openstreetmap.org/wiki/Toulouse/ToulouseMetropoleData","terms_text":"ToulouseMetropole"},{"id":"Tours-Orthophoto-2008_2010","name":"Tours - Orthophotos 2008-2010","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/tours/{zoom}/{x}/{y}","scaleExtent":[0,20],"polygon":[[[0.5457462,47.465264],[0.54585,47.4608163],[0.5392188,47.4606983],[0.5393484,47.456243],[0.5327959,47.4561003],[0.5329011,47.451565],[0.52619,47.4514013],[0.5265854,47.4424884],[0.5000941,47.4420739],[0.5002357,47.4375835],[0.4936014,47.4374324],[0.4937,47.4329285],[0.4606141,47.4324593],[0.4607248,47.4279827],[0.4541016,47.4278125],[0.454932,47.4053921],[0.4615431,47.4054476],[0.4619097,47.3964924],[0.4684346,47.3966005],[0.4691319,47.3786415],[0.4757125,47.3787609],[0.4762116,47.3652018],[0.4828297,47.3653499],[0.4829611,47.3608321],[0.4763543,47.360743],[0.476654,47.3517263],[0.4700497,47.3516186],[0.4701971,47.3471313],[0.4637503,47.3470104],[0.4571425,47.3424146],[0.4572922,47.3379061],[0.4506741,47.3378081],[0.4508379,47.3333051],[0.4442212,47.3332032],[0.4443809,47.328711],[0.4311392,47.3284977],[0.4316262,47.3150004],[0.4382432,47.3151136],[0.4383815,47.3106174],[0.4714487,47.3111374],[0.4713096,47.3156565],[0.477888,47.3157542],[0.4780733,47.3112802],[0.4846826,47.3113639],[0.4848576,47.3068686],[0.4914359,47.3069803],[0.491745,47.2979733],[0.4851578,47.2978722],[0.4854269,47.2888744],[0.4788485,47.2887697],[0.4791574,47.2797818],[0.4857769,47.2799005],[0.4859107,47.2753885],[0.492539,47.2755029],[0.4926669,47.2710127],[0.4992986,47.2711066],[0.4994296,47.2666116],[0.5192658,47.2669245],[0.5194225,47.2624231],[0.5260186,47.2625205],[0.5258735,47.2670183],[0.5456972,47.2673383],[0.5455537,47.2718283],[0.5587737,47.2720366],[0.5586259,47.2765185],[0.5652252,47.2766278],[0.5650848,47.2811206],[0.5716753,47.2812285],[0.5715223,47.2857217],[0.5781436,47.2858299],[0.5779914,47.2903294],[0.5846023,47.2904263],[0.5843076,47.2994231],[0.597499,47.2996094],[0.5976637,47.2951375],[0.6571596,47.2960036],[0.6572988,47.2915091],[0.6705019,47.2917186],[0.6703475,47.2962082],[0.6836175,47.2963688],[0.6834322,47.3008929],[0.690062,47.3009558],[0.6899241,47.3054703],[0.7362019,47.3061157],[0.7360848,47.3106063],[0.7559022,47.3108935],[0.7557718,47.315392],[0.7623755,47.3154716],[0.7622314,47.3199941],[0.7754911,47.3201546],[0.77497,47.3388218],[0.7745786,47.351628],[0.7680363,47.3515901],[0.767589,47.3605298],[0.7742443,47.3606238],[0.7733465,47.3921266],[0.7667434,47.3920195],[0.7664411,47.4010837],[0.7730647,47.4011115],[0.7728868,47.4101297],[0.7661849,47.4100226],[0.7660267,47.4145044],[0.7527613,47.4143038],[0.7529788,47.4098086],[0.7462373,47.4097016],[0.7459424,47.4232208],[0.7392324,47.4231451],[0.738869,47.4366116],[0.7323267,47.4365171],[0.7321869,47.4410556],[0.7255048,47.44098],[0.7254209,47.4453479],[0.7318793,47.4454803],[0.7318514,47.4501126],[0.7384496,47.450226],[0.7383098,47.454631],[0.7449359,47.4547444],[0.7443209,47.4771985],[0.7310685,47.4769717],[0.7309008,47.4815445],[0.7176205,47.4812611],[0.7177883,47.4768394],[0.69777,47.4764993],[0.6980496,47.4719827],[0.6914514,47.4718882],[0.6917309,47.4630241],[0.6851048,47.4629295],[0.684937,47.4673524],[0.678255,47.4673335],[0.6779754,47.4762158],[0.6714051,47.4761592],[0.6710417,47.4881952],[0.6577334,47.4879685],[0.6578173,47.48504],[0.6511911,47.4848322],[0.6514707,47.4758568],[0.6448166,47.4757245],[0.6449284,47.4712646],[0.6117976,47.4707543],[0.6118815,47.4663129],[0.6052833,47.4661239],[0.6054231,47.4616631],[0.5988808,47.4615497],[0.5990206,47.4570886],[0.572488,47.4566916],[0.5721805,47.4656513],[0.5457462,47.465264]]],"terms_url":"http://wiki.openstreetmap.org/wiki/Tours/Orthophoto","terms_text":"Orthophoto Tour(s) Plus 2008"},{"id":"Tours-Orthophoto-2013","name":"Tours - Orthophotos 2013","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/tours_2013/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[0.427093505859375,47.26199018174824],[0.427093505859375,47.50096732311069],[0.814361572265625,47.50096732311069],[0.814361572265625,47.26199018174824],[0.427093505859375,47.26199018174824]]],"terms_url":"http://wiki.openstreetmap.org/wiki/Tours/Orthophoto","terms_text":"Orthophoto Tour(s)plus 2013"},{"id":"US_Forest_Service_roads","name":"U.S. Forest Service roads","type":"tms","template":"http://osm.cycle.travel/forest/{zoom}/{x}/{y}.png","scaleExtent":[0,19],"polygon":[[[-124.7617886,48.4130148],[-124.6059492,45.90245],[-124.9934269,40.0557614],[-122.5369737,36.8566086],[-119.9775867,33.0064099],[-117.675935,32.4630223],[-114.8612307,32.4799891],[-111.0089311,31.336015],[-108.1992687,31.3260016],[-108.1871123,31.7755116],[-106.5307225,31.7820947],[-106.4842052,31.7464455],[-106.429317,31.7520583],[-106.2868855,31.5613291],[-106.205248,31.446704],[-105.0205259,30.5360988],[-104.5881916,29.6997856],[-103.2518856,28.8908685],[-102.7173632,29.3920567],[-102.1513983,29.7475702],[-101.2552871,29.4810523],[-100.0062436,28.0082173],[-99.2351068,26.4475962],[-98.0109067,25.9928035],[-97.435024,25.8266009],[-96.9555259,25.9821589],[-96.8061741,27.7978168],[-95.5563349,28.5876066],[-93.7405308,29.4742093],[-90.9028456,28.8564513],[-88.0156706,28.9944338],[-88.0162494,30.0038862],[-86.0277506,30.0047454],[-84.0187909,28.9961781],[-81.9971976,25.9826768],[-81.9966618,25.0134917],[-84.0165592,25.0125783],[-84.0160068,24.0052745],[-80.0199985,24.007096],[-79.8901116,26.8550713],[-80.0245309,32.0161282],[-75.4147385,35.0531894],[-74.0211163,39.5727927],[-72.002019,40.9912464],[-69.8797398,40.9920457],[-69.8489304,43.2619916],[-66.9452845,44.7104937],[-67.7596632,47.0990024],[-69.2505131,47.5122328],[-70.4614886,46.2176574],[-71.412273,45.254878],[-72.0222508,45.0059846],[-75.0798841,44.9802854],[-76.9023061,43.8024568],[-78.7623935,43.6249578],[-79.15798,43.4462589],[-79.0060087,42.8005317],[-82.662475,41.6889458],[-82.1761642,43.588535],[-83.2813977,46.138853],[-87.5064535,48.0142702],[-88.3492194,48.2963271],[-89.4353148,47.9837822],[-93.9981078,49.0067142],[-95.1105379,49.412004],[-96.0131199,49.0060547],[-123.3228926,49.0042878],[-123.2275233,48.1849927],[-124.7617886,48.4130148]],[[-160.5787616,22.5062947],[-160.5782192,21.4984647],[-158.7470604,21.2439843],[-157.5083185,20.995803],[-155.9961942,18.7790194],[-154.6217803,18.7586966],[-154.6890176,19.8805722],[-156.2927622,21.2225888],[-157.5047384,21.9984962],[-159.0093692,22.5070181],[-160.5787616,22.5062947]],[[-167.1571546,68.721974],[-164.8553982,67.0255078],[-168.002195,66.0017503],[-169.0087448,66.001546],[-169.0075381,64.9987675],[-172.5143281,63.8767267],[-173.8197023,59.74014],[-162.5018149,58.0005815],[-160.0159024,58.0012389],[-160.0149725,57.000035],[-160.5054788,56.9999017],[-165.8092575,54.824847],[-178.000097,52.2446469],[-177.9992996,51.2554252],[-171.4689067,51.8215329],[-162.40251,53.956664],[-159.0075717,55.002502],[-158.0190709,55.0027849],[-151.9963213,55.9991902],[-151.500341,57.9987853],[-151.5012894,58.9919816],[-138.5159989,58.9953194],[-138.5150471,57.9986434],[-133.9948193,54.0031685],[-130.0044418,54.0043387],[-130.0070826,57.0000507],[-131.975877,56.9995156],[-135.1229873,59.756601],[-138.0071813,59.991805],[-139.1715881,60.4127229],[-140.9874011,61.0118551],[-140.9683975,69.9535069],[-156.176891,71.5633329],[-160.413634,70.7397728],[-163.0218273,69.9707435],[-164.9717003,68.994689],[-167.1571546,68.721974]]]},{"id":"Zuerich-zh_uebersichtsplan-tms","name":"Übersichtsplan Zürich","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/zh_uebersichtsplan/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[0,21],"polygon":[[[8.4482,47.321],[8.4482,47.4339],[8.6248,47.4339],[8.6248,47.321],[8.4482,47.321]]],"terms_text":"Stadt Zürich Open Government Data"},{"id":"USGS-Large_Scale","name":"USGS Large Scale Imagery","type":"tms","template":"http://{switch:a,b,c}.tile.openstreetmap.us/usgs_large_scale/{zoom}/{x}/{y}.jpg","scaleExtent":[12,20],"polygon":[[[-123.2549305,48.7529029],[-123.2549305,48.5592263],[-123.192224,48.5592263],[-123.192224,48.4348366],[-122.9419646,48.4348366],[-122.9419646,48.3720812],[-122.8806229,48.3720812],[-122.8806229,48.3094763],[-122.8167566,48.3094763],[-122.8167566,48.1904587],[-123.0041133,48.1904587],[-123.0041133,48.1275918],[-123.058416,48.1275918],[-123.058416,48.190514],[-123.254113,48.190514],[-123.254113,48.1274982],[-123.3706593,48.1274982],[-123.3706593,48.1908403],[-124.0582632,48.1908403],[-124.0582632,48.253442],[-124.1815163,48.253442],[-124.1815163,48.3164666],[-124.4319117,48.3164666],[-124.4319117,48.3782613],[-124.5564618,48.3782613],[-124.5564618,48.4408305],[-124.7555107,48.4408305],[-124.7555107,48.1914986],[-124.8185282,48.1914986],[-124.8185282,48.1228381],[-124.7552951,48.1228381],[-124.7552951,47.5535253],[-124.3812108,47.5535253],[-124.3812108,47.1218696],[-124.1928897,47.1218696],[-124.1928897,43.7569431],[-124.4443382,43.7569431],[-124.4443382,43.1425556],[-124.6398855,43.1425556],[-124.6398855,42.6194503],[-124.4438525,42.6194503],[-124.4438525,39.8080662],[-123.8815685,39.8080662],[-123.8815685,39.1102825],[-123.75805,39.1102825],[-123.75805,38.4968799],[-123.2702803,38.4968799],[-123.2702803,37.9331905],[-122.8148084,37.9331905],[-122.8148084,37.8019606],[-122.5664316,37.8019606],[-122.5664316,36.9319611],[-121.8784026,36.9319611],[-121.8784026,36.6897596],[-122.0034748,36.6897596],[-122.0034748,36.4341056],[-121.9414159,36.4341056],[-121.9414159,35.9297636],[-121.5040977,35.9297636],[-121.5040977,35.8100273],[-121.3790276,35.8100273],[-121.3790276,35.4239164],[-120.9426515,35.4239164],[-120.9426515,35.1849683],[-120.8171978,35.1849683],[-120.8171978,35.1219894],[-120.6918447,35.1219894],[-120.6918447,34.4966794],[-120.5045898,34.4966794],[-120.5045898,34.4339651],[-120.0078775,34.4339651],[-120.0078775,34.3682626],[-119.5283517,34.3682626],[-119.5283517,34.0576434],[-119.0060985,34.0576434],[-119.0060985,33.9975267],[-118.5046259,33.9975267],[-118.5046259,33.8694631],[-118.4413209,33.8694631],[-118.4413209,33.6865253],[-118.066912,33.6865253],[-118.066912,33.3063832],[-117.5030045,33.3063832],[-117.5030045,33.0500337],[-117.3188195,33.0500337],[-117.3188195,32.6205888],[-117.1917023,32.6205888],[-117.1917023,32.4974566],[-116.746496,32.4974566],[-116.746496,32.5609161],[-115.9970138,32.5609161],[-115.9970138,32.6264942],[-114.8808125,32.6264942],[-114.8808125,32.4340796],[-114.6294474,32.4340796],[-114.6294474,32.3731636],[-114.4447437,32.3731636],[-114.4447437,32.3075418],[-114.2557628,32.3075418],[-114.2557628,32.2444561],[-114.0680274,32.2444561],[-114.0680274,32.1829113],[-113.8166499,32.1829113],[-113.8166499,32.1207622],[-113.6307421,32.1207622],[-113.6307421,32.0565099],[-113.4417495,32.0565099],[-113.4417495,31.9984372],[-113.2546027,31.9984372],[-113.2546027,31.9325434],[-113.068072,31.9325434],[-113.068072,31.8718062],[-112.8161105,31.8718062],[-112.8161105,31.8104171],[-112.6308756,31.8104171],[-112.6308756,31.7464723],[-112.4418918,31.7464723],[-112.4418918,31.6856001],[-112.257192,31.6856001],[-112.257192,31.6210352],[-112.0033787,31.6210352],[-112.0033787,31.559584],[-111.815619,31.559584],[-111.815619,31.4970238],[-111.6278586,31.4970238],[-111.6278586,31.4339867],[-111.4418978,31.4339867],[-111.4418978,31.3733859],[-111.2559708,31.3733859],[-111.2559708,31.3113225],[-108.1845822,31.3113225],[-108.1845822,31.7459502],[-106.5065055,31.7459502],[-106.5065055,31.6842308],[-106.3797265,31.6842308],[-106.3797265,31.621752],[-106.317434,31.621752],[-106.317434,31.4968167],[-106.2551769,31.4968167],[-106.2551769,31.4344889],[-106.1924698,31.4344889],[-106.1924698,31.3721296],[-106.0039212,31.3721296],[-106.0039212,31.309328],[-105.9416582,31.309328],[-105.9416582,31.2457547],[-105.8798174,31.2457547],[-105.8798174,31.1836194],[-105.8162349,31.1836194],[-105.8162349,31.1207155],[-105.6921198,31.1207155],[-105.6921198,31.0584835],[-105.6302881,31.0584835],[-105.6302881,30.9328271],[-105.5044418,30.9328271],[-105.5044418,30.8715864],[-105.4412973,30.8715864],[-105.4412973,30.808463],[-105.3781497,30.808463],[-105.3781497,30.7471828],[-105.1904658,30.7471828],[-105.1904658,30.6843231],[-105.1286244,30.6843231],[-105.1286244,30.6199737],[-105.0036504,30.6199737],[-105.0036504,30.5589058],[-104.9417962,30.5589058],[-104.9417962,30.4963236],[-104.8782018,30.4963236],[-104.8782018,30.3098261],[-104.8155257,30.3098261],[-104.8155257,30.2478305],[-104.7536079,30.2478305],[-104.7536079,29.9353916],[-104.690949,29.9353916],[-104.690949,29.8090156],[-104.6291301,29.8090156],[-104.6291301,29.6843577],[-104.5659869,29.6843577],[-104.5659869,29.6223459],[-104.5037188,29.6223459],[-104.5037188,29.5595436],[-104.4410072,29.5595436],[-104.4410072,29.4974832],[-104.2537551,29.4974832],[-104.2537551,29.3716718],[-104.1291984,29.3716718],[-104.1291984,29.3091621],[-104.0688737,29.3091621],[-104.0688737,29.2467276],[-103.8187309,29.2467276],[-103.8187309,29.1843076],[-103.755736,29.1843076],[-103.755736,29.1223174],[-103.5667542,29.1223174],[-103.5667542,29.0598119],[-103.5049819,29.0598119],[-103.5049819,28.9967506],[-103.3165753,28.9967506],[-103.3165753,28.9346923],[-103.0597572,28.9346923],[-103.0597572,29.0592965],[-102.9979694,29.0592965],[-102.9979694,29.1212855],[-102.9331397,29.1212855],[-102.9331397,29.1848575],[-102.8095989,29.1848575],[-102.8095989,29.2526154],[-102.8701345,29.2526154],[-102.8701345,29.308096],[-102.8096681,29.308096],[-102.8096681,29.3715484],[-102.7475655,29.3715484],[-102.7475655,29.5581899],[-102.684554,29.5581899],[-102.684554,29.6847655],[-102.4967764,29.6847655],[-102.4967764,29.7457694],[-102.3086647,29.7457694],[-102.3086647,29.8086627],[-102.1909323,29.8086627],[-102.1909323,29.7460097],[-101.5049914,29.7460097],[-101.5049914,29.6846777],[-101.3805796,29.6846777],[-101.3805796,29.5594459],[-101.3175057,29.5594459],[-101.3175057,29.4958934],[-101.1910075,29.4958934],[-101.1910075,29.4326115],[-101.067501,29.4326115],[-101.067501,29.308808],[-100.9418897,29.308808],[-100.9418897,29.2456231],[-100.8167271,29.2456231],[-100.8167271,29.1190449],[-100.7522672,29.1190449],[-100.7522672,29.0578214],[-100.6925358,29.0578214],[-100.6925358,28.8720431],[-100.6290158,28.8720431],[-100.6290158,28.8095363],[-100.5679901,28.8095363],[-100.5679901,28.622554],[-100.5040411,28.622554],[-100.5040411,28.5583804],[-100.4421832,28.5583804],[-100.4421832,28.4968266],[-100.379434,28.4968266],[-100.379434,28.3092865],[-100.3171942,28.3092865],[-100.3171942,28.1835681],[-100.254483,28.1835681],[-100.254483,28.1213885],[-100.1282282,28.1213885],[-100.1282282,28.059215],[-100.0659537,28.059215],[-100.0659537,27.9966087],[-100.0023855,27.9966087],[-100.0023855,27.9332152],[-99.9426497,27.9332152],[-99.9426497,27.7454658],[-99.816851,27.7454658],[-99.816851,27.6834301],[-99.7541346,27.6834301],[-99.7541346,27.6221543],[-99.6291629,27.6221543],[-99.6291629,27.5588977],[-99.5672838,27.5588977],[-99.5672838,27.4353752],[-99.5041798,27.4353752],[-99.5041798,27.3774021],[-99.5671796,27.3774021],[-99.5671796,27.2463726],[-99.504975,27.2463726],[-99.504975,26.9965649],[-99.4427427,26.9965649],[-99.4427427,26.872803],[-99.3800633,26.872803],[-99.3800633,26.8068179],[-99.3190684,26.8068179],[-99.3190684,26.7473614],[-99.2537541,26.7473614],[-99.2537541,26.6210068],[-99.1910617,26.6210068],[-99.1910617,26.4956737],[-99.1300639,26.4956737],[-99.1300639,26.3713808],[-99.0029473,26.3713808],[-99.0029473,26.3093836],[-98.816572,26.3093836],[-98.816572,26.2457762],[-98.6920082,26.2457762],[-98.6920082,26.1837096],[-98.4440896,26.1837096],[-98.4440896,26.1217217],[-98.3823181,26.1217217],[-98.3823181,26.0596488],[-98.2532707,26.0596488],[-98.2532707,25.9986871],[-98.0109084,25.9986871],[-98.0109084,25.9932255],[-97.6932319,25.9932255],[-97.6932319,25.9334103],[-97.6313904,25.9334103],[-97.6313904,25.8695893],[-97.5046779,25.8695893],[-97.5046779,25.8073488],[-97.3083401,25.8073488],[-97.3083401,25.8731159],[-97.2456326,25.8731159],[-97.2456326,25.9353731],[-97.1138939,25.9353731],[-97.1138939,27.6809179],[-97.0571035,27.6809179],[-97.0571035,27.8108242],[-95.5810766,27.8108242],[-95.5810766,28.7468827],[-94.271041,28.7468827],[-94.271041,29.5594076],[-92.5029947,29.5594076],[-92.5029947,29.4974754],[-91.8776216,29.4974754],[-91.8776216,29.3727013],[-91.378418,29.3727013],[-91.378418,29.2468326],[-91.3153953,29.2468326],[-91.3153953,29.1844301],[-91.1294702,29.1844301],[-91.1294702,29.1232559],[-91.0052632,29.1232559],[-91.0052632,28.9968437],[-89.4500159,28.9968437],[-89.4500159,28.8677422],[-88.8104309,28.8677422],[-88.8104309,30.1841864],[-85.8791527,30.1841864],[-85.8791527,29.5455038],[-84.8368083,29.5455038],[-84.8368083,29.6225158],[-84.7482786,29.6225158],[-84.7482786,29.683624],[-84.685894,29.683624],[-84.685894,29.7468386],[-83.6296975,29.7468386],[-83.6296975,29.4324361],[-83.3174937,29.4324361],[-83.3174937,29.0579442],[-82.879659,29.0579442],[-82.879659,27.7453529],[-82.8182822,27.7453529],[-82.8182822,26.9290868],[-82.3796782,26.9290868],[-82.3796782,26.3694183],[-81.8777106,26.3694183],[-81.8777106,25.805971],[-81.5036862,25.805971],[-81.5036862,25.7474753],[-81.4405462,25.7474753],[-81.4405462,25.6851489],[-81.3155883,25.6851489],[-81.3155883,25.5600985],[-81.2538534,25.5600985],[-81.2538534,25.4342361],[-81.1902012,25.4342361],[-81.1902012,25.1234341],[-81.1288133,25.1234341],[-81.1288133,25.0619389],[-81.0649231,25.0619389],[-81.0649231,24.8157807],[-81.6289469,24.8157807],[-81.6289469,24.7538367],[-81.6907173,24.7538367],[-81.6907173,24.6899374],[-81.8173189,24.6899374],[-81.8173189,24.6279161],[-82.1910041,24.6279161],[-82.1910041,24.496294],[-81.6216596,24.496294],[-81.6216596,24.559484],[-81.372006,24.559484],[-81.372006,24.6220687],[-81.0593278,24.6220687],[-81.0593278,24.684826],[-80.9347147,24.684826],[-80.9347147,24.7474828],[-80.7471081,24.7474828],[-80.7471081,24.8100618],[-80.3629898,24.8100618],[-80.3629898,25.1175858],[-80.122344,25.1175858],[-80.122344,25.7472357],[-80.0588458,25.7472357],[-80.0588458,26.3708251],[-79.995837,26.3708251],[-79.995837,26.9398003],[-80.0587265,26.9398003],[-80.0587265,27.1277466],[-80.1226251,27.1277466],[-80.1226251,27.2534279],[-80.1846956,27.2534279],[-80.1846956,27.3781229],[-80.246175,27.3781229],[-80.246175,27.5658729],[-80.3094768,27.5658729],[-80.3094768,27.7530311],[-80.3721485,27.7530311],[-80.3721485,27.8774451],[-80.4351457,27.8774451],[-80.4351457,28.0033366],[-80.4966078,28.0033366],[-80.4966078,28.1277326],[-80.5587159,28.1277326],[-80.5587159,28.3723509],[-80.4966335,28.3723509],[-80.4966335,29.5160326],[-81.1213644,29.5160326],[-81.1213644,31.6846966],[-80.6018723,31.6846966],[-80.6018723,32.2475309],[-79.4921024,32.2475309],[-79.4921024,32.9970261],[-79.1116488,32.9970261],[-79.1116488,33.3729457],[-78.6153621,33.3729457],[-78.6153621,33.8097638],[-77.9316963,33.8097638],[-77.9316963,33.8718243],[-77.8692252,33.8718243],[-77.8692252,34.0552454],[-77.6826392,34.0552454],[-77.6826392,34.2974598],[-77.2453509,34.2974598],[-77.2453509,34.5598585],[-76.4973277,34.5598585],[-76.4973277,34.622796],[-76.4337602,34.622796],[-76.4337602,34.6849285],[-76.373212,34.6849285],[-76.373212,34.7467674],[-76.3059364,34.7467674],[-76.3059364,34.808551],[-76.2468017,34.808551],[-76.2468017,34.8728418],[-76.1825922,34.8728418],[-76.1825922,34.9335332],[-76.120814,34.9335332],[-76.120814,34.9952359],[-75.9979015,34.9952359],[-75.9979015,35.0578182],[-75.870338,35.0578182],[-75.870338,35.1219097],[-75.7462194,35.1219097],[-75.7462194,35.1818911],[-75.4929694,35.1818911],[-75.4929694,35.3082988],[-75.4325662,35.3082988],[-75.4325662,35.7542495],[-75.4969907,35.7542495],[-75.4969907,37.8105602],[-75.3082972,37.8105602],[-75.3082972,37.8720088],[-75.245601,37.8720088],[-75.245601,37.9954849],[-75.1828751,37.9954849],[-75.1828751,38.0585079],[-75.1184793,38.0585079],[-75.1184793,38.2469091],[-75.0592098,38.2469091],[-75.0592098,38.3704316],[-74.9948111,38.3704316],[-74.9948111,38.8718417],[-74.4878252,38.8718417],[-74.4878252,39.3089428],[-74.1766317,39.3089428],[-74.1766317,39.6224653],[-74.0567045,39.6224653],[-74.0567045,39.933178],[-73.9959035,39.933178],[-73.9959035,40.1854852],[-73.9341593,40.1854852],[-73.9341593,40.4959486],[-73.8723024,40.4959486],[-73.8723024,40.5527135],[-71.8074506,40.5527135],[-71.8074506,41.3088005],[-70.882512,41.3088005],[-70.882512,41.184978],[-70.7461947,41.184978],[-70.7461947,41.3091865],[-70.4337553,41.3091865],[-70.4337553,41.4963885],[-69.9334281,41.4963885],[-69.9334281,41.6230802],[-69.869857,41.6230802],[-69.869857,41.8776895],[-69.935791,41.8776895],[-69.935791,42.0032342],[-69.9975823,42.0032342],[-69.9975823,42.0650191],[-70.0606103,42.0650191],[-70.0606103,42.1294348],[-70.5572884,42.1294348],[-70.5572884,43.2487079],[-70.4974097,43.2487079],[-70.4974097,43.3092194],[-70.3704249,43.3092194],[-70.3704249,43.371963],[-70.3085701,43.371963],[-70.3085701,43.4969879],[-70.183921,43.4969879],[-70.183921,43.6223531],[-70.057583,43.6223531],[-70.057583,43.6850173],[-69.7455247,43.6850173],[-69.7455247,43.7476571],[-69.2472845,43.7476571],[-69.2472845,43.8107035],[-69.0560701,43.8107035],[-69.0560701,43.8717247],[-68.9950522,43.8717247],[-68.9950522,43.9982022],[-68.4963672,43.9982022],[-68.4963672,44.0597368],[-68.3081038,44.0597368],[-68.3081038,44.122137],[-68.1851802,44.122137],[-68.1851802,44.3081382],[-67.9956019,44.3081382],[-67.9956019,44.3727489],[-67.8103041,44.3727489],[-67.8103041,44.435178],[-67.4965289,44.435178],[-67.4965289,44.4968776],[-67.37102,44.4968776],[-67.37102,44.5600642],[-67.1848753,44.5600642],[-67.1848753,44.6213345],[-67.1221208,44.6213345],[-67.1221208,44.6867918],[-67.059365,44.6867918],[-67.059365,44.7473657],[-66.9311098,44.7473657],[-66.9311098,44.9406566],[-66.994683,44.9406566],[-66.994683,45.0024514],[-67.0595847,45.0024514],[-67.0595847,45.1273377],[-67.1201974,45.1273377],[-67.1201974,45.1910115],[-67.2469811,45.1910115],[-67.2469811,45.253442],[-67.3177546,45.253442],[-67.3177546,45.1898369],[-67.370749,45.1898369],[-67.370749,45.2534001],[-67.4326888,45.2534001],[-67.4326888,45.3083409],[-67.3708571,45.3083409],[-67.3708571,45.4396986],[-67.4305573,45.4396986],[-67.4305573,45.4950095],[-67.37099,45.4950095],[-67.37099,45.6264543],[-67.6214982,45.6264543],[-67.6214982,45.6896133],[-67.683828,45.6896133],[-67.683828,45.753259],[-67.7462097,45.753259],[-67.7462097,47.1268165],[-67.8700141,47.1268165],[-67.8700141,47.1900278],[-67.9323803,47.1900278],[-67.9323803,47.2539678],[-67.9959387,47.2539678],[-67.9959387,47.3149737],[-68.1206676,47.3149737],[-68.1206676,47.3780823],[-68.4423175,47.3780823],[-68.4423175,47.3166082],[-68.6314305,47.3166082],[-68.6314305,47.2544676],[-68.9978037,47.2544676],[-68.9978037,47.439895],[-69.0607223,47.439895],[-69.0607223,47.5047558],[-69.2538122,47.5047558],[-69.2538122,47.4398084],[-69.3179284,47.4398084],[-69.3179284,47.378601],[-69.4438546,47.378601],[-69.4438546,47.3156274],[-69.5038204,47.3156274],[-69.5038204,47.2525839],[-69.5667838,47.2525839],[-69.5667838,47.1910884],[-69.6303478,47.1910884],[-69.6303478,47.128701],[-69.6933103,47.128701],[-69.6933103,47.0654307],[-69.7557063,47.0654307],[-69.7557063,47.0042751],[-69.8180391,47.0042751],[-69.8180391,46.9415344],[-69.8804023,46.9415344],[-69.8804023,46.8792519],[-69.9421674,46.8792519],[-69.9421674,46.8177399],[-70.0063088,46.8177399],[-70.0063088,46.6920295],[-70.0704265,46.6920295],[-70.0704265,46.4425926],[-70.1945902,46.4425926],[-70.1945902,46.3785887],[-70.2562047,46.3785887],[-70.2562047,46.3152628],[-70.3203651,46.3152628],[-70.3203651,46.0651209],[-70.3814988,46.0651209],[-70.3814988,45.93552],[-70.3201618,45.93552],[-70.3201618,45.879479],[-70.4493131,45.879479],[-70.4493131,45.7538713],[-70.5070021,45.7538713],[-70.5070021,45.6916912],[-70.6316642,45.6916912],[-70.6316642,45.6291619],[-70.7575538,45.6291619],[-70.7575538,45.4414685],[-70.8809878,45.4414685],[-70.8809878,45.3780612],[-71.13328,45.3780612],[-71.13328,45.3151452],[-71.3830282,45.3151452],[-71.3830282,45.253416],[-71.5076448,45.253416],[-71.5076448,45.0655726],[-73.9418929,45.0655726],[-73.9418929,45.0031242],[-74.7469725,45.0031242],[-74.7469725,45.0649003],[-74.8800964,45.0649003],[-74.8800964,45.0029023],[-75.0662455,45.0029023],[-75.0662455,44.9415167],[-75.2539363,44.9415167],[-75.2539363,44.8776043],[-75.3789648,44.8776043],[-75.3789648,44.8153462],[-75.4431283,44.8153462],[-75.4431283,44.7536053],[-75.5666566,44.7536053],[-75.5666566,44.6909879],[-75.6290205,44.6909879],[-75.6290205,44.6284958],[-75.7540484,44.6284958],[-75.7540484,44.566385],[-75.817312,44.566385],[-75.817312,44.5028932],[-75.8799549,44.5028932],[-75.8799549,44.3784946],[-76.1300319,44.3784946],[-76.1300319,44.3159227],[-76.1926961,44.3159227],[-76.1926961,44.2534378],[-76.3182619,44.2534378],[-76.3182619,44.1916726],[-76.3792975,44.1916726],[-76.3792975,44.0653733],[-76.4427584,44.0653733],[-76.4427584,43.9963825],[-76.317027,43.9963825],[-76.317027,43.9414581],[-76.5076611,43.9414581],[-76.5076611,43.8723335],[-76.3829974,43.8723335],[-76.3829974,43.8091872],[-76.2534102,43.8091872],[-76.2534102,43.5665222],[-76.5064833,43.5665222],[-76.5064833,43.5033881],[-76.6331208,43.5033881],[-76.6331208,43.4432252],[-76.6951085,43.4432252],[-76.6951085,43.3786858],[-76.8177798,43.3786858],[-76.8177798,43.318066],[-77.682,43.318066],[-77.682,43.3789376],[-78.0565883,43.3789376],[-78.0565883,43.4396918],[-78.4389748,43.4396918],[-78.4389748,43.3794382],[-78.8803396,43.3794382],[-78.8803396,43.3149724],[-79.1298858,43.3149724],[-79.1298858,43.2429286],[-79.0669615,43.2429286],[-79.0669615,43.1299931],[-79.1298858,43.1299931],[-79.1298858,43.0577305],[-79.071264,43.0577305],[-79.071264,42.9294906],[-78.943264,42.9294906],[-78.943264,42.7542165],[-79.069439,42.7542165],[-79.069439,42.6941622],[-79.133439,42.6941622],[-79.133439,42.6296973],[-79.1947499,42.6296973],[-79.1947499,42.5663538],[-79.3786827,42.5663538],[-79.3786827,42.5033425],[-79.4442961,42.5033425],[-79.4442961,42.4410614],[-79.5679936,42.4410614],[-79.5679936,42.3775264],[-79.6906154,42.3775264],[-79.6906154,42.3171086],[-79.8164642,42.3171086],[-79.8164642,42.2534481],[-80.0052373,42.2534481],[-80.0052373,42.1909188],[-80.1916829,42.1909188],[-80.1916829,42.1272555],[-80.3167992,42.1272555],[-80.3167992,42.0669857],[-80.5063234,42.0669857],[-80.5063234,42.0034331],[-80.6930471,42.0034331],[-80.6930471,41.9415141],[-80.9440403,41.9415141],[-80.9440403,41.8781193],[-81.1942729,41.8781193],[-81.1942729,41.8166455],[-81.3190089,41.8166455],[-81.3190089,41.7545453],[-81.4418435,41.7545453],[-81.4418435,41.690965],[-81.5053523,41.690965],[-81.5053523,41.6301643],[-82.7470081,41.6301643],[-82.7470081,41.7536942],[-82.8839135,41.7536942],[-82.8839135,41.5656075],[-82.9957195,41.5656075],[-82.9957195,41.6270375],[-83.1257796,41.6270375],[-83.1257796,41.6878411],[-83.2474733,41.6878411],[-83.2474733,41.7536942],[-83.3737305,41.7536942],[-83.3737305,41.809276],[-83.3106019,41.809276],[-83.3106019,41.8716064],[-83.2474733,41.8716064],[-83.2474733,41.9361393],[-83.1843447,41.9361393],[-83.1843447,41.9960851],[-83.1207681,41.9960851],[-83.1207681,42.2464812],[-83.0589194,42.2464812],[-83.0589194,42.3089555],[-82.8685328,42.3089555],[-82.8685328,42.3717652],[-82.8072219,42.3717652],[-82.8072219,42.558553],[-82.7553745,42.558553],[-82.7553745,42.4954945],[-82.5599041,42.4954945],[-82.5599041,42.558553],[-82.4967755,42.558553],[-82.4967755,42.6833607],[-82.4328863,42.6833607],[-82.4328863,42.9342196],[-82.3700552,42.9342196],[-82.3700552,43.0648071],[-82.4328863,43.0648071],[-82.4328863,43.1917566],[-82.4947464,43.1917566],[-82.4947464,43.5034627],[-82.557133,43.5034627],[-82.557133,43.8160901],[-82.6197884,43.8160901],[-82.6197884,43.9422098],[-82.6839499,43.9422098],[-82.6839499,44.0022641],[-82.7465346,44.0022641],[-82.7465346,44.0670545],[-82.8708696,44.0670545],[-82.8708696,44.1291935],[-83.008517,44.1291935],[-83.008517,44.0664786],[-83.1336086,44.0664786],[-83.1336086,44.0053949],[-83.2414522,44.0053949],[-83.2414522,44.9962034],[-83.1806112,44.9962034],[-83.1806112,45.067302],[-83.2455172,45.067302],[-83.2455172,45.1287382],[-83.3065878,45.1287382],[-83.3065878,45.2551509],[-83.3706087,45.2551509],[-83.3706087,45.3165923],[-83.4325644,45.3165923],[-83.4325644,45.3792105],[-83.6178415,45.3792105],[-83.6178415,45.4419665],[-83.8084291,45.4419665],[-83.8084291,45.5036189],[-84.0550718,45.5036189],[-84.0550718,45.5647907],[-84.1235181,45.5647907],[-84.1235181,45.6287845],[-84.1807534,45.6287845],[-84.1807534,45.6914688],[-84.3111554,45.6914688],[-84.3111554,45.9337076],[-83.8209974,45.9337076],[-83.8209974,45.8725113],[-83.4968086,45.8725113],[-83.4968086,45.9337076],[-83.4338066,45.9337076],[-83.4338066,46.0016863],[-83.4962697,46.0016863],[-83.4962697,46.0668178],[-83.5599956,46.0668178],[-83.5599956,46.1261576],[-83.9954558,46.1261576],[-83.9954558,46.1931747],[-84.0591816,46.1931747],[-84.0591816,46.3814972],[-84.1152614,46.3814972],[-84.1152614,46.4953584],[-84.0591816,46.4953584],[-84.0591816,46.5682653],[-84.2579545,46.5682653],[-84.2579545,46.5051232],[-84.3071879,46.5051232],[-84.3071879,46.5682653],[-84.4415364,46.5682653],[-84.4415364,46.504525],[-84.9965729,46.504525],[-84.9965729,46.6842882],[-84.9298158,46.6842882],[-84.9298158,46.818077],[-85.3165894,46.818077],[-85.3165894,46.7535825],[-87.5562645,46.7535825],[-87.5562645,47.4407371],[-87.6825361,47.4407371],[-87.6825361,47.5035554],[-88.2560738,47.5035554],[-88.2560738,47.4433716],[-88.4417419,47.4433716],[-88.4417419,47.3789949],[-88.50683,47.3789949],[-88.50683,47.3153881],[-88.6312821,47.3153881],[-88.6312821,47.2539782],[-88.7569636,47.2539782],[-88.7569636,47.1934682],[-88.8838253,47.1934682],[-88.8838253,47.1284735],[-88.9434208,47.1284735],[-88.9434208,47.0662127],[-89.0708726,47.0662127],[-89.0708726,47.0026826],[-89.2565553,47.0026826],[-89.2565553,46.9410806],[-90.3677669,46.9410806],[-90.3677669,47.6844827],[-90.3069978,47.6844827],[-90.3069978,47.7460174],[-89.994859,47.7460174],[-89.994859,47.8082719],[-89.8048615,47.8082719],[-89.8048615,47.8700562],[-89.6797699,47.8700562],[-89.6797699,47.9339637],[-89.4933757,47.9339637],[-89.4933757,47.9957956],[-89.4284697,47.9957956],[-89.4284697,48.0656377],[-89.9932739,48.0656377],[-89.9932739,48.1282966],[-90.7455933,48.1282966],[-90.7455933,48.1893056],[-90.8087291,48.1893056],[-90.8087291,48.2522065],[-91.067763,48.2522065],[-91.067763,48.1916658],[-91.1946247,48.1916658],[-91.1946247,48.1279027],[-91.6814196,48.1279027],[-91.6814196,48.2525994],[-91.9321927,48.2525994],[-91.9321927,48.3142454],[-91.9929683,48.3142454],[-91.9929683,48.3780845],[-92.3189383,48.3780845],[-92.3189383,48.2529081],[-92.3732233,48.2529081],[-92.3732233,48.3153385],[-92.4322288,48.3153385],[-92.4322288,48.4411448],[-92.4977248,48.4411448],[-92.4977248,48.501781],[-92.5679413,48.501781],[-92.5679413,48.439579],[-92.6210462,48.439579],[-92.6210462,48.5650783],[-92.8086835,48.5650783],[-92.8086835,48.6286865],[-92.8086835,48.6267365],[-92.933185,48.6267365],[-92.933185,48.6922145],[-93.0051716,48.6922145],[-93.0051716,48.6282965],[-93.1225924,48.6282965],[-93.1225924,48.6922145],[-93.3190806,48.6922145],[-93.3190806,48.6267365],[-93.5049477,48.6267365],[-93.5049477,48.5635164],[-93.7474601,48.5635164],[-93.7474601,48.6267365],[-93.8135461,48.6267365],[-93.8135461,48.6898775],[-94.2453121,48.6898775],[-94.2453121,48.7554327],[-94.6183171,48.7554327],[-94.6183171,48.941036],[-94.6809018,48.941036],[-94.6809018,49.0029737],[-94.7441532,49.0029737],[-94.7441532,49.2536079],[-94.8084069,49.2536079],[-94.8084069,49.3784134],[-95.1192391,49.3784134],[-95.1192391,49.4425264],[-95.1934341,49.4425264],[-95.1934341,49.0035292],[-96.87069,49.0035292],[-96.87069,49.0656063],[-99.0049312,49.0656063],[-99.0049312,49.0050714],[-109.3699257,49.0050714],[-109.3699257,49.0668231],[-109.5058746,49.0668231],[-109.5058746,49.0050714],[-114.1830014,49.0050714],[-114.1830014,49.0687317],[-114.7578709,49.0687317],[-114.7578709,49.0050714],[-115.433731,49.0050714],[-115.433731,49.0671412],[-116.5062706,49.0671412],[-116.5062706,49.0050714],[-117.3089504,49.0050714],[-117.3089504,49.0659803],[-119.882945,49.0659803],[-119.882945,49.0050714],[-120.1208555,49.0050714],[-120.1208555,49.0678367],[-121.4451636,49.0678367],[-121.4451636,49.0050714],[-121.9311808,49.0050714],[-121.9311808,49.0656099],[-122.817484,49.0656099],[-122.817484,49.0029143],[-122.8795155,49.0029143],[-122.8795155,48.9347018],[-122.8174629,48.9347018],[-122.8174629,48.8101998],[-122.7538859,48.8101998],[-122.7538859,48.7533758],[-122.8712937,48.7533758],[-122.8712937,48.8153948],[-123.0055391,48.8153948],[-123.0055391,48.7529529],[-123.1296926,48.7529529],[-123.1296926,48.6902201],[-123.1838197,48.6902201],[-123.1838197,48.7529029],[-123.2549305,48.7529029]],[[-122.9341743,37.7521547],[-122.9347457,37.6842013],[-123.0679013,37.6849023],[-123.0673747,37.7475251],[-123.1292603,37.7478506],[-123.1286894,37.815685],[-123.0590687,37.8153192],[-123.0595947,37.7528143],[-122.9341743,37.7521547]],[[-71.6299464,41.2540893],[-71.4966465,41.2541393],[-71.4965596,41.122965],[-71.6298594,41.1229149],[-71.6299464,41.2540893]],[[-70.3184265,41.3775196],[-70.3183384,41.2448243],[-70.1906612,41.2448722],[-70.1906239,41.1886019],[-69.9336025,41.1886984],[-69.933729,41.3791941],[-69.9950664,41.3791712],[-69.995109,41.443159],[-70.0707828,41.4431307],[-70.0706972,41.3144915],[-70.2461667,41.3144258],[-70.2462087,41.3775467],[-70.3184265,41.3775196]],[[-68.9403374,43.9404062],[-68.6856948,43.9404977],[-68.6856475,43.8721797],[-68.7465405,43.8721577],[-68.7464976,43.8102529],[-68.8090782,43.8102304],[-68.8090343,43.746728],[-68.8773094,43.7467034],[-68.8773544,43.8117826],[-68.9402483,43.8117599],[-68.9403374,43.9404062]],[[-123.1291466,49.0645144],[-122.9954224,49.0645144],[-122.9954224,48.9343243],[-123.1291466,48.9343243],[-123.1291466,49.0645144]],[[-82.9407144,24.7535913],[-82.8719398,24.7535913],[-82.8719398,24.6905653],[-82.7446233,24.6905653],[-82.7446233,24.6214593],[-82.8088038,24.6214593],[-82.8088038,24.5594908],[-82.9407144,24.5594908],[-82.9407144,24.7535913]]]},{"id":"USGS-Scanned_Topographic","name":"USGS Topographic Maps","type":"tms","template":"http://caltopo.s3.amazonaws.com/topo/{zoom}/{x}/{y}.png","scaleExtent":[0,16],"polygon":[[[-55.9959409871,52.00107125754],[-112.02896100663,52.00107125754],[-112.03994733476,56.01308253302],[-120.0049439862,56.00592357111],[-120.01711631014,60.01202439709],[-132.00196823895,60.00239237126],[-132.01208445818,63.00193292546],[-133.96882922149,63.00050478005],[-133.97240257168,63.9922484722],[-141.04429430438,63.98726254018],[-141.06879354491,69.92045693283],[-156.24893170976,71.51583202984],[-160.44570905351,70.83527373985],[-167.08145124101,68.42906280103],[-164.08218366288,67.03913532024],[-169.01504499101,65.68268604273],[-166.57608014726,64.50777504773],[-161.82998639726,64.0500622981],[-165.08193952226,63.26030016403],[-168.02627545976,59.7862264253],[-162.53311139726,59.73089435789],[-162.35733014726,58.55904663221],[-157.83096295976,58.31752983705],[-158.00674420976,57.52404350658],[-168.22402936601,53.51022153947],[-166.55410749101,53.14277307072],[-158.77578717851,54.88541314654],[-158.68240338944,55.7496444805],[-156.55105573319,56.00847621073],[-156.15554792069,56.7746616888],[-154.70535260819,56.14336689443],[-152.07412702226,57.37034511851],[-151.62918073319,58.22653323066],[-152.00820905351,58.98055685754],[-145.98770124101,60.24740887373],[-140.38467389726,59.48634241018],[-136.53945905351,57.80610084736],[-133.79287702226,54.83482554482],[-133.33145124101,53.14277307072],[-131.46377545976,51.69838238021],[-128.52493268632,51.74602265442],[-129.79385358476,50.90159054062],[-124.56436139726,47.49785657441],[-124.03701764726,45.48627362525],[-124.69619733476,42.90428451679],[-124.49844342851,40.3414647251],[-122.80654889726,37.53929308709],[-119.99404889726,33.37084692374],[-117.24746686601,32.54119524801],[-111.13906842851,31.19770451575],[-106.70059186601,31.23528720858],[-103.20693952226,28.64618215851],[-101.84463483476,29.81580068657],[-99.20791608476,26.28743998885],[-96.79092389726,25.75431753335],[-96.92275983476,27.96911213371],[-93.47305280351,29.68226300815],[-88.94668561601,28.87732407469],[-88.61709577226,30.17736083469],[-86.20010358476,30.3671253082],[-84.96963483476,29.43379356715],[-84.09072858476,30.06332630046],[-82.97012311601,28.95425748047],[-82.97012311601,27.26823750278],[-81.25625592851,25.07956298739],[-82.09121686601,24.5610471236],[-80.06973249101,24.76073298597],[-79.85000592851,27.11188091684],[-81.27822858476,30.70777424386],[-78.99307233476,33.20554049136],[-75.03799420976,35.59830000028],[-75.85098249101,37.2425160052],[-73.74160749101,40.4585957587],[-69.89639264726,41.60224497127],[-70.68740827226,43.17628724449],[-66.93008405351,44.69516042167],[-66.53457624101,43.08006996122],[-64.20547467851,43.35229243812],[-59.50332624101,45.73220792131],[-59.51431256913,46.24761804024],[-60.00320417069,46.25901313529],[-59.99221784257,47.24505773341],[-59.00894147538,47.23759898478],[-58.99795514726,47.50266941922],[-56.51504499101,47.50266941922],[-56.52603131913,46.74770404019],[-53.99917585038,46.74770404019],[-53.97720319413,46.48358117386],[-52.49404889726,46.46354265729],[-52.50503522538,48.75360583388],[-52.99667340898,48.75451123442],[-53.01315290116,49.99551104004],[-55.00167829179,50.00610367548],[-55.03738385819,53.74720613495],[-56.00418073319,53.73421061801],[-55.9959409871,52.00107125754]],[[-59.50126630448,43.7495431608],[-60.50239545487,43.7495431608],[-60.50239545487,43.99999882251],[-59.99839765214,43.99999882251],[-59.99839765214,44.2494016836],[-59.50126630448,44.2494016836],[-59.50126630448,43.7495431608]],[[-155.95024091386,20.49523373356],[-157.3267518687,20.49153389084],[-157.32902509355,21.23181053727],[-155.95251413871,21.23549220541],[-155.95024091386,20.49523373356]],[[-157.64488202714,21.24845058596],[-158.28534362719,21.24673774522],[-158.28689557694,21.7499618541],[-157.6464339769,21.75166877943],[-157.64488202714,21.24845058596]],[[-156.12602216386,20.32469602374],[-154.7461696274,20.3284088686],[-154.74174482011,18.87578125335],[-156.12159735656,18.87203473488],[-156.12602216386,20.32469602374]],[[-159.29077130937,22.24504086823],[-159.2892966564,21.76857042389],[-160.28916841131,21.76590592196],[-160.29064306428,22.24238530626],[-159.29077130937,22.24504086823]]],"terms_url":"https://caltopo.com/","terms_text":"© Caltopo"},{"id":"sjcgis.org-General_Basemap_WM","name":"Vector Streetmap for San Juan County WA","type":"tms","template":"http://sjcgis.org/arcgis/rest/services/Basemaps/General_Basemap_WM/MapServer/tile/{zoom}/{y}/{x}","description":"Public domain street and address data from the San Juan County, WA. Updated at least quarterly.","scaleExtent":[0,19],"polygon":[[[-123.274024,48.692975],[-123.007726,48.767256],[-123.007619,48.831577],[-122.783495,48.758416],[-122.693402,48.658522],[-122.767451,48.603606],[-122.744842,48.387083],[-123.248221,48.283531],[-123.114524,48.422614],[-123.219035,48.548575],[-123.274024,48.692975]]],"best":true},{"id":"Vejmidte_Denmark","name":"Vejmidte (Denmark)","type":"tms","template":"http://{switch:a,b,c}.tile.openstreetmap.dk/danmark/vejmidte/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[8.3743941,54.9551655],[8.3683809,55.4042149],[8.2103997,55.4039795],[8.2087314,55.4937345],[8.0502655,55.4924731],[8.0185123,56.7501399],[8.1819161,56.7509948],[8.1763274,57.0208898],[8.3413329,57.0219872],[8.3392467,57.1119574],[8.5054433,57.1123212],[8.5033923,57.2020499],[9.3316304,57.2027636],[9.3319079,57.2924835],[9.4978864,57.2919578],[9.4988593,57.3820608],[9.6649749,57.3811615],[9.6687295,57.5605591],[9.8351961,57.5596265],[9.8374896,57.6493322],[10.1725726,57.6462818],[10.1754245,57.7367768],[10.5118282,57.7330269],[10.5152095,57.8228945],[10.6834853,57.8207722],[10.6751613,57.6412021],[10.5077045,57.6433097],[10.5039992,57.5535088],[10.671038,57.5514113],[10.6507805,57.1024538],[10.4857673,57.1045138],[10.4786236,56.9249051],[10.3143981,56.9267573],[10.3112341,56.8369269],[10.4750295,56.83509],[10.4649016,56.5656681],[10.9524239,56.5589761],[10.9479249,56.4692243],[11.1099335,56.4664675],[11.1052639,56.376833],[10.9429901,56.3795284],[10.9341235,56.1994768],[10.7719685,56.2020244],[10.7694751,56.1120103],[10.6079695,56.1150259],[10.4466742,56.116717],[10.2865948,56.118675],[10.2831527,56.0281851],[10.4439274,56.0270388],[10.4417713,55.7579243],[10.4334961,55.6693533],[10.743814,55.6646861],[10.743814,55.5712253],[10.8969041,55.5712253],[10.9051793,55.3953852],[11.0613726,55.3812841],[11.0593038,55.1124061],[11.0458567,55.0318621],[11.2030844,55.0247474],[11.2030844,55.117139],[11.0593038,55.1124061],[11.0613726,55.3812841],[11.0789572,55.5712253],[10.8969041,55.5712253],[10.9258671,55.6670198],[10.743814,55.6646861],[10.7562267,55.7579243],[10.4417713,55.7579243],[10.4439274,56.0270388],[10.4466742,56.116717],[10.6079695,56.1150259],[10.6052053,56.0247462],[10.9258671,56.0201215],[10.9197132,55.9309388],[11.0802782,55.92792],[11.0858066,56.0178284],[11.7265047,56.005058],[11.7319981,56.0952142],[12.0540333,56.0871256],[12.0608477,56.1762576],[12.7023469,56.1594405],[12.6611131,55.7114318],[12.9792318,55.7014026],[12.9612912,55.5217294],[12.3268659,55.5412096],[12.3206071,55.4513655],[12.4778226,55.447067],[12.4702432,55.3570479],[12.6269738,55.3523837],[12.6200898,55.2632576],[12.4627339,55.26722],[12.4552949,55.1778223],[12.2987046,55.1822303],[12.2897344,55.0923641],[12.6048608,55.0832904],[12.5872011,54.9036285],[12.2766618,54.9119031],[12.2610181,54.7331602],[12.1070691,54.7378161],[12.0858621,54.4681655],[11.7794953,54.4753579],[11.7837381,54.5654783],[11.1658525,54.5782155],[11.1706443,54.6686508],[10.8617173,54.6733956],[10.8651245,54.7634667],[10.7713646,54.7643888],[10.7707276,54.7372807],[10.7551428,54.7375776],[10.7544039,54.7195666],[10.7389074,54.7197588],[10.7384368,54.7108482],[10.7074486,54.7113045],[10.7041094,54.6756741],[10.5510973,54.6781698],[10.5547184,54.7670245],[10.2423994,54.7705935],[10.2459845,54.8604673],[10.0902268,54.8622134],[10.0873731,54.7723851],[9.1555798,54.7769557],[9.1562752,54.8675369],[8.5321973,54.8663765],[8.531432,54.95516],[8.3743941,54.9551655]],[[11.4577738,56.819554],[11.7849181,56.8127385],[11.7716715,56.6332796],[11.4459621,56.6401087],[11.4577738,56.819554]],[[11.3274736,57.3612962],[11.3161808,57.1818004],[11.1508692,57.1847276],[11.1456628,57.094962],[10.8157703,57.1001693],[10.8290599,57.3695272],[11.3274736,57.3612962]],[[11.5843266,56.2777928],[11.5782882,56.1880397],[11.7392309,56.1845765],[11.7456428,56.2743186],[11.5843266,56.2777928]],[[14.6825922,55.3639405],[14.8395247,55.3565231],[14.8263755,55.2671261],[15.1393406,55.2517359],[15.1532015,55.3410836],[15.309925,55.3330556],[15.295719,55.2437356],[15.1393406,55.2517359],[15.1255631,55.1623802],[15.2815819,55.1544167],[15.2535578,54.9757646],[14.6317464,55.0062496],[14.6825922,55.3639405]]],"terms_url":"http://wiki.openstreetmap.org/wiki/Vejmidte","terms_text":"Danish municipalities"},{"id":"wien.gv.at-labels","name":"Vienna: Beschriftungen (annotations)","type":"tms","template":"https://maps.wien.gv.at/wmts/beschriftung/normal/google3857/{zoom}/{y}/{x}.png","scaleExtent":[12,19],"polygon":[[[16.17,48.1],[16.17,48.33],[16.58,48.33],[16.58,48.1],[16.17,48.1]]],"terms_url":"https://data.wien.gv.at/","terms_text":"Stadt Wien"},{"id":"wien.gv.at-gp","name":"Vienna: Mehrzweckkarte (general purpose)","type":"tms","template":"https://maps.wien.gv.at/wmts/fmzk/pastell/google3857/{zoom}/{y}/{x}.jpeg","scaleExtent":[10,19],"polygon":[[[16.17,48.1],[16.17,48.33],[16.58,48.33],[16.58,48.1],[16.17,48.1]]],"terms_url":"https://data.wien.gv.at/","terms_text":"Stadt Wien"},{"id":"wien.gv.at-aerial_image","name":"Vienna: Orthofoto (aerial image)","type":"tms","template":"https://maps.wien.gv.at/wmts/lb/farbe/google3857/{zoom}/{y}/{x}.jpeg","scaleExtent":[10,19],"polygon":[[[16.17,48.1],[16.17,48.33],[16.58,48.33],[16.58,48.1],[16.17,48.1]]],"terms_url":"https://data.wien.gv.at/","terms_text":"Stadt Wien"}];
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":"beer","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["beer","bier"],"tags":{"craft":"brewery"},"name":"Brewery"},"craft/carpenter":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["woodworker"],"tags":{"craft":"carpenter"},"name":"Carpenter"},"craft/carpet_layer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"carpet_layer"},"name":"Carpet Layer"},"craft/caterer":{"icon":"restaurant","fields":["cuisine","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"caterer"},"name":"Caterer"},"craft/clockmaker":{"icon":"poi-clock","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"clockmaker"},"name":"Clockmaker"},"craft/confectionery":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sweets","candy"],"tags":{"craft":"confectionery"},"name":"Confectionery"},"craft/dressmaker":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["seamstress"],"tags":{"craft":"dressmaker"},"name":"Dressmaker"},"craft/electrician":{"icon":"poi-power","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["power","wire"],"tags":{"craft":"electrician"},"name":"Electrician"},"craft/gardener":{"icon":"garden","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["landscaper","grounds keeper"],"tags":{"craft":"gardener"},"name":"Gardener"},"craft/glaziery":{"icon":"fire-station","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["glass","stained-glass","window"],"tags":{"craft":"glaziery"},"name":"Glaziery"},"craft/handicraft":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"handicraft"},"name":"Handicraft"},"craft/hvac":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["heat*","vent*","air conditioning"],"tags":{"craft":"hvac"},"name":"HVAC"},"craft/insulator":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"insulation"},"name":"Insulator"},"craft/key_cutter":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"key_cutter"},"name":"Key Cutter"},"craft/metal_construction":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"metal_construction"},"name":"Metal Construction"},"craft/painter":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"painter"},"name":"Painter"},"craft/photographer":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"photographer"},"name":"Photographer"},"craft/photographic_laboratory":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["film"],"tags":{"craft":"photographic_laboratory"},"name":"Photographic Laboratory"},"craft/plasterer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"plasterer"},"name":"Plasterer"},"craft/plumber":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["pipe"],"tags":{"craft":"plumber"},"name":"Plumber"},"craft/pottery":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ceramic"],"tags":{"craft":"pottery"},"name":"Pottery"},"craft/rigger":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"rigger"},"name":"Rigger"},"craft/roofer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"roofer"},"name":"Roofer"},"craft/saddler":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"saddler"},"name":"Saddler"},"craft/sailmaker":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sailmaker"},"name":"Sailmaker"},"craft/sawmill":{"icon":"logging","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["lumber"],"tags":{"craft":"sawmill"},"name":"Sawmill"},"craft/scaffolder":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"scaffolder"},"name":"Scaffolder"},"craft/sculpter":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sculpter"},"name":"Sculpter"},"craft/shoemaker":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["cobbler"],"tags":{"craft":"shoemaker"},"name":"Shoemaker"},"craft/stonemason":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["masonry"],"tags":{"craft":"stonemason"},"name":"Stonemason"},"craft/sweep":{"icon":"poi-chimney","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sweep"},"name":"Chimney Sweep"},"craft/tiler":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"tiler"},"name":"Tiler"},"craft/tinsmith":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"tinsmith"},"name":"Tinsmith"},"craft/upholsterer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"upholsterer"},"name":"Upholsterer"},"craft/watchmaker":{"icon":"poi-clock","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"watchmaker"},"name":"Watchmaker"},"craft/window_construction":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["glass"],"tags":{"craft":"window_construction"},"name":"Window Construction"},"craft/winery":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"winery"},"name":"Winery"},"embankment":{"geometry":["line"],"tags":{"embankment":"yes"},"name":"Embankment","matchScore":0.2},"emergency/designated":{"fields":[],"geometry":["line"],"tags":{"emergency":"designated"},"terms":[],"name":"Emergency Access Designated","searchable":false,"matchScore":0.01},"emergency/destination":{"fields":[],"geometry":["line"],"tags":{"emergency":"destination"},"terms":[],"name":"Emergency Access Destination","searchable":false,"matchScore":0.01},"emergency/no":{"fields":[],"geometry":["line"],"tags":{"emergency":"no"},"terms":[],"name":"Emergency Access No","searchable":false,"matchScore":0.01},"emergency/official":{"fields":[],"geometry":["line"],"tags":{"emergency":"official"},"terms":[],"name":"Emergency Access Official","searchable":false,"matchScore":0.01},"emergency/private":{"fields":[],"geometry":["line"],"tags":{"emergency":"private"},"terms":[],"name":"Emergency Access Private","searchable":false,"matchScore":0.01},"emergency/yes":{"fields":[],"geometry":["line"],"tags":{"emergency":"yes"},"terms":[],"name":"Emergency Access Yes","searchable":false,"matchScore":0.01},"emergency/ambulance_station":{"icon":"hospital","fields":["operator","building_area","address"],"geometry":["point","area"],"terms":["EMS","EMT","rescue"],"tags":{"emergency":"ambulance_station"},"name":"Ambulance Station"},"emergency/defibrillator":{"icon":"defibrillator","fields":["access","opening_hours","indoor","phone"],"geometry":["point"],"terms":["AED"],"tags":{"emergency":"defibrillator"},"name":"Defibrillator"},"emergency/fire_hydrant":{"icon":"poi-fire-hydrant","fields":["fire_hydrant/type","fire_hydrant/position","ref","operator"],"geometry":["point","vertex"],"terms":["fire plug"],"tags":{"emergency":"fire_hydrant"},"name":"Fire Hydrant"},"emergency/phone":{"icon":"emergency-phone","fields":["operator"],"geometry":["point","vertex"],"tags":{"emergency":"phone"},"name":"Emergency Phone"},"entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"entrance":"*"},"fields":["entrance","access_simple","address"],"name":"Entrance/Exit"},"footway/crossing":{"fields":["crossing","access","surface","kerb","tactile_paving"],"geometry":["line"],"tags":{"highway":"footway","footway":"crossing"},"reference":{"key":"footway","value":"crossing"},"terms":[],"name":"Street Crossing"},"footway/crosswalk":{"icon":"highway-footway","fields":["crossing","access","surface","kerb","tactile_paving"],"geometry":["line"],"tags":{"highway":"footway","footway":"crossing","crossing":"zebra"},"reference":{"key":"highway","value":"crossing"},"terms":["zebra crossing"],"name":"Pedestrian Crosswalk"},"footway/sidewalk":{"icon":"highway-footway","fields":["surface","lit","width","structure","access"],"geometry":["line"],"tags":{"highway":"footway","footway":"sidewalk"},"reference":{"key":"footway","value":"sidewalk"},"terms":[],"name":"Sidewalk"},"ford":{"geometry":["vertex"],"tags":{"ford":"yes"},"name":"Ford"},"golf/bunker":{"icon":"golf","geometry":["area"],"tags":{"golf":"bunker","natural":"sand"},"terms":["hazard","bunker"],"reference":{"key":"golf","value":"bunker"},"name":"Sand Trap"},"golf/fairway":{"icon":"golf","geometry":["area"],"tags":{"golf":"fairway","landuse":"grass"},"reference":{"key":"golf","value":"fairway"},"name":"Fairway"},"golf/green":{"icon":"golf","geometry":["area"],"tags":{"golf":"green","landuse":"grass","leisure":"pitch","sport":"golf"},"reference":{"key":"golf","value":"green"},"name":"Putting Green"},"golf/hole":{"icon":"golf","fields":["golf_hole","par","handicap"],"geometry":["line"],"tags":{"golf":"hole"},"name":"Golf Hole"},"golf/lateral_water_hazard_area":{"icon":"golf","geometry":["area"],"tags":{"golf":"lateral_water_hazard","natural":"water"},"reference":{"key":"golf","value":"lateral_water_hazard"},"name":"Lateral Water Hazard"},"golf/lateral_water_hazard_line":{"icon":"golf","geometry":["line"],"tags":{"golf":"lateral_water_hazard"},"name":"Lateral Water Hazard"},"golf/rough":{"icon":"golf","geometry":["area"],"tags":{"golf":"rough","landuse":"grass"},"reference":{"key":"golf","value":"rough"},"name":"Rough"},"golf/tee":{"icon":"golf","geometry":["area"],"tags":{"golf":"tee","landuse":"grass"},"terms":["teeing ground"],"reference":{"key":"golf","value":"tee"},"name":"Tee Box"},"golf/water_hazard_area":{"icon":"golf","geometry":["area"],"tags":{"golf":"water_hazard","natural":"water"},"reference":{"key":"golf","value":"water_hazard"},"name":"Water Hazard"},"golf/water_hazard_line":{"icon":"golf","geometry":["line"],"tags":{"golf":"water_hazard"},"name":"Water Hazard"},"healthcare/blood_donation":{"icon":"blood-bank","fields":["operator","address","blood_components","opening_hours","ref"],"geometry":["point","area"],"terms":["blood bank","blood donation","blood transfusion","apheresis","plasmapheresis","plateletpheresis","stem cell donation"],"tags":{"healthcare":"blood_donation"},"name":"Blood Donor Center"},"highway/bridleway":{"fields":["surface","width","structure","access"],"icon":"highway-bridleway","geometry":["line"],"tags":{"highway":"bridleway"},"terms":["bridleway","equestrian","horse"],"name":"Bridle Path"},"highway/bus_stop":{"icon":"bus","fields":["network","operator","bench","shelter"],"geometry":["point","vertex"],"tags":{"highway":"bus_stop"},"terms":[],"name":"Bus Stop"},"highway/corridor":{"icon":"highway-footway","fields":["width","level","access_simple"],"geometry":["line"],"tags":{"highway":"corridor"},"terms":["gallery","hall","hallway","indoor","passage","passageway"],"name":"Indoor Corridor"},"highway/crossing":{"fields":["crossing","kerb","tactile_paving"],"geometry":["vertex"],"tags":{"highway":"crossing"},"reference":{"key":"footway","value":"crossing"},"terms":[],"name":"Street Crossing"},"highway/crosswalk":{"icon":"poi-foot","fields":["crossing","kerb","tactile_paving"],"geometry":["vertex"],"tags":{"highway":"crossing","crossing":"zebra"},"reference":{"key":"highway","value":"crossing"},"terms":["zebra crossing"],"name":"Pedestrian Crosswalk"},"highway/cycleway":{"icon":"highway-cycleway","fields":["oneway","surface","lit","width","structure","access"],"geometry":["line"],"tags":{"highway":"cycleway"},"terms":["bike"],"name":"Cycle Path"},"highway/footway":{"icon":"highway-footway","fields":["surface","lit","width","structure","access"],"geometry":["line","area"],"terms":["hike","hiking","trackway","trail","walk"],"tags":{"highway":"footway"},"name":"Foot Path"},"highway/give_way":{"icon":"poi-yield","fields":["parallel_direction"],"geometry":["vertex"],"tags":{"highway":"give_way"},"terms":["give way","yield","sign"],"name":"Yield Sign"},"highway/living_street":{"icon":"highway-living-street","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","access","cycleway"],"geometry":["line"],"tags":{"highway":"living_street"},"name":"Living Street"},"highway/mini_roundabout":{"icon":"circle-stroked","geometry":["vertex"],"tags":{"highway":"mini_roundabout"},"fields":["clock_direction"],"name":"Mini-Roundabout"},"highway/motorway_junction":{"icon":"poi-junction","geometry":["vertex"],"tags":{"highway":"motorway_junction"},"fields":["ref"],"name":"Motorway Junction / Exit"},"highway/motorway_link":{"icon":"highway-motorway-link","fields":["ref","oneway_yes","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"motorway_link"},"addTags":{"highway":"motorway_link","oneway":"yes"},"removeTags":{"highway":"motorway_link","oneway":"yes"},"terms":["ramp","on ramp","off ramp"],"name":"Motorway Link"},"highway/motorway":{"icon":"highway-motorway","fields":["ref","oneway_yes","maxspeed","lanes","surface","structure","maxheight","toll","access"],"geometry":["line"],"tags":{"highway":"motorway"},"terms":["autobahn","expressway","freeway","highway","interstate","parkway","thruway","turnpike"],"name":"Motorway"},"highway/path":{"icon":"highway-path","fields":["surface","width","structure","access","incline","sac_scale","trail_visibility","mtb/scale","mtb/scale/uphill","mtb/scale/imba","ref"],"geometry":["line"],"terms":["hike","hiking","trackway","trail","walk"],"tags":{"highway":"path"},"name":"Path"},"highway/pedestrian":{"icon":"highway-footway","fields":["surface","lit","width","oneway","structure","access"],"geometry":["line","area"],"tags":{"highway":"pedestrian"},"terms":[],"name":"Pedestrian Street"},"highway/primary_link":{"icon":"highway-primary-link","fields":["oneway","maxspeed","lanes","surface","maxheight","ref","cycleway","structure","access"],"geometry":["line"],"tags":{"highway":"primary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Primary Link"},"highway/primary":{"icon":"highway-primary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"primary"},"terms":[],"name":"Primary Road"},"highway/raceway":{"icon":"highway-unclassified","fields":["oneway","surface","sport_racing_motor","lit","width","lanes","structure"],"geometry":["point","line","area"],"tags":{"highway":"raceway"},"addTags":{"highway":"raceway","sport":"motor"},"terms":["auto*","formula one","kart","motocross","nascar","race*","track"],"name":"Racetrack (Motorsport)"},"highway/residential":{"icon":"highway-residential","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","cycleway","access"],"geometry":["line"],"tags":{"highway":"residential"},"terms":[],"name":"Residential Road"},"highway/rest_area":{"icon":"car","geometry":["point","vertex","area"],"tags":{"highway":"rest_area"},"terms":["rest stop"],"name":"Rest Area"},"highway/road":{"icon":"highway-road","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"road"},"terms":[],"name":"Unknown Road"},"highway/secondary_link":{"icon":"highway-secondary-link","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"secondary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Secondary Link"},"highway/secondary":{"icon":"highway-secondary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"secondary"},"terms":[],"name":"Secondary Road"},"highway/service":{"icon":"highway-service","fields":["service","oneway","maxspeed","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"service"},"terms":[],"name":"Service Road"},"highway/service/alley":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"alley"},"reference":{"key":"service","value":"alley"},"name":"Alley"},"highway/service/drive-through":{"icon":"highway-service","fields":["oneway","covered","maxheight","maxspeed","structure","access","surface"],"geometry":["line"],"tags":{"highway":"service","service":"drive-through"},"reference":{"key":"service","value":"drive-through"},"name":"Drive-Through"},"highway/service/driveway":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"driveway"},"reference":{"key":"service","value":"driveway"},"name":"Driveway"},"highway/service/emergency_access":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"emergency_access"},"reference":{"key":"service","value":"emergency_access"},"name":"Emergency Access"},"highway/service/parking_aisle":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"parking_aisle"},"reference":{"key":"service","value":"parking_aisle"},"name":"Parking Aisle"},"highway/services":{"icon":"car","geometry":["point","vertex","area"],"tags":{"highway":"services"},"terms":["services","travel plaza","service station"],"name":"Service Area"},"highway/speed_camera":{"icon":"attraction","geometry":["point"],"fields":["ref"],"tags":{"highway":"speed_camera"},"terms":[],"name":"Speed Camera"},"highway/steps":{"icon":"highway-steps","fields":["surface","lit","width","incline_steps","handrail","step_count"],"geometry":["line"],"tags":{"highway":"steps"},"terms":["stairs","staircase"],"name":"Steps"},"highway/stop":{"icon":"poi-stop","fields":["stop","parallel_direction"],"geometry":["vertex"],"tags":{"highway":"stop"},"terms":["stop","halt","sign"],"name":"Stop Sign"},"highway/street_lamp":{"icon":"poi-street-lamp","geometry":["point","vertex"],"tags":{"highway":"street_lamp"},"fields":["lamp_type","ref"],"terms":["streetlight","street light","lamp","light","gaslight"],"name":"Street Lamp"},"highway/tertiary_link":{"icon":"highway-tertiary-link","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"tertiary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Tertiary Link"},"highway/tertiary":{"icon":"highway-tertiary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"tertiary"},"terms":[],"name":"Tertiary Road"},"highway/track":{"icon":"highway-track","fields":["tracktype","surface","width","structure","access","incline","smoothness","mtb/scale","mtb/scale/uphill","mtb/scale/imba"],"geometry":["line"],"tags":{"highway":"track"},"terms":["woods road","forest road","logging road","fire road","farm road","agricultural road","ranch road","carriage road","primitive","unmaintained","rut","offroad","4wd","4x4","four wheel drive","atv","quad","jeep","double track","two track"],"name":"Unmaintained Track Road"},"highway/traffic_mirror":{"geometry":["point"],"tags":{"highway":"traffic_mirror"},"terms":["blind spot","convex","corner","curved","roadside","round","safety","sphere","visibility"],"name":"Traffic Mirror"},"highway/traffic_signals":{"icon":"poi-traffic-signals","geometry":["vertex"],"tags":{"highway":"traffic_signals"},"fields":["traffic_signals"],"terms":["light","stoplight","traffic light"],"name":"Traffic Signals"},"highway/trunk_link":{"icon":"highway-trunk-link","fields":["ref","oneway","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"trunk_link"},"terms":["ramp","on ramp","off ramp"],"name":"Trunk Link"},"highway/trunk":{"icon":"highway-trunk","fields":["ref","oneway","maxspeed","lanes","surface","structure","maxheight","toll","access"],"geometry":["line"],"tags":{"highway":"trunk"},"terms":[],"name":"Trunk Road"},"highway/turning_circle":{"icon":"circle-stroked","geometry":["vertex"],"tags":{"highway":"turning_circle"},"terms":["cul-de-sac"],"name":"Turning Circle"},"highway/turning_loop":{"icon":"circle","geometry":["vertex"],"tags":{"highway":"turning_loop"},"terms":["cul-de-sac"],"name":"Turning Loop (Island)"},"highway/unclassified":{"icon":"highway-unclassified","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","cycleway","access"],"geometry":["line"],"tags":{"highway":"unclassified"},"terms":[],"name":"Minor/Unclassified Road"},"historic":{"icon":"poi-ruins","fields":["historic","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"*"},"name":"Historic Site"},"historic/archaeological_site":{"icon":"poi-ruins","fields":["historic/civilization","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"archaeological_site"},"name":"Archaeological Site"},"historic/boundary_stone":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex"],"tags":{"historic":"boundary_stone"},"name":"Boundary Stone"},"historic/castle":{"icon":"castle","fields":["castle_type","building_area","historic/civilization"],"geometry":["point","area"],"tags":{"historic":"castle"},"name":"Castle"},"historic/memorial":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"memorial"},"name":"Memorial"},"historic/monument":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"monument"},"name":"Monument"},"historic/ruins":{"icon":"poi-ruins","fields":["historic/civilization","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"ruins"},"name":"Ruins"},"historic/tomb":{"icon":"cemetery","fields":["tomb","building_area","inscription"],"geometry":["point","area"],"tags":{"historic":"tomb"},"name":"Tomb"},"historic/wayside_cross":{"icon":"religious-christian","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"wayside_cross"},"name":"Wayside Cross"},"historic/wayside_shrine":{"icon":"landmark","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"wayside_shrine"},"name":"Wayside Shrine"},"junction":{"icon":"poi-junction","geometry":["vertex","area"],"tags":{"junction":"yes"},"name":"Junction"},"landuse":{"fields":["landuse"],"geometry":["area"],"tags":{"landuse":"*"},"matchScore":0.9,"name":"Land Use"},"landuse/farm":{"icon":"farm","fields":["operator","crop"],"geometry":["point","area"],"tags":{"landuse":"farm"},"terms":[],"name":"Farmland","searchable":false},"landuse/allotments":{"geometry":["area"],"tags":{"landuse":"allotments"},"terms":["allotment","garden"],"name":"Community Garden"},"landuse/aquaculture":{"icon":"aquarium","fields":["operator","produce"],"geometry":["area"],"tags":{"landuse":"aquaculture"},"terms":["fish farm","crustacean","algae","aquafarming","shrimp farm","oyster farm","mariculture","algaculture"],"name":"Aquaculture"},"landuse/basin":{"icon":"water","geometry":["area"],"tags":{"landuse":"basin"},"terms":[],"name":"Basin"},"landuse/cemetery":{"icon":"cemetery","fields":["religion","denomination"],"geometry":["area"],"tags":{"landuse":"cemetery"},"terms":[],"name":"Cemetery"},"landuse/churchyard":{"fields":["religion","denomination"],"geometry":["area"],"tags":{"landuse":"churchyard"},"terms":[],"name":"Churchyard"},"landuse/commercial":{"icon":"commercial","geometry":["area"],"tags":{"landuse":"commercial"},"terms":[],"name":"Commercial Area"},"landuse/construction":{"fields":["construction","operator"],"geometry":["area"],"tags":{"landuse":"construction"},"terms":[],"name":"Construction"},"landuse/farmland":{"icon":"farm","fields":["operator","crop","produce"],"geometry":["area"],"tags":{"landuse":"farmland"},"terms":["crop","grow","plant"],"name":"Farmland"},"landuse/farmyard":{"icon":"farm","fields":["operator","crop"],"geometry":["area"],"tags":{"landuse":"farmyard"},"terms":["crop","grow","plant"],"name":"Farmyard"},"landuse/forest":{"icon":"park-alt1","fields":["leaf_type","leaf_cycle","produce"],"geometry":["area"],"tags":{"landuse":"forest"},"terms":["tree"],"name":"Forest"},"landuse/garages":{"geometry":["area"],"tags":{"landuse":"garages"},"terms":[],"name":"Garages"},"landuse/grass":{"geometry":["area"],"tags":{"landuse":"grass"},"terms":[],"name":"Grass"},"landuse/harbour":{"icon":"harbor","fields":["operator"],"geometry":["area"],"terms":["boat"],"tags":{"landuse":"harbour"},"name":"Harbor"},"landuse/industrial":{"icon":"industry","geometry":["area"],"tags":{"landuse":"industrial"},"terms":[],"matchScore":0.9,"name":"Industrial Area"},"landuse/landfill":{"geometry":["area"],"tags":{"landuse":"landfill"},"terms":["dump"],"name":"Landfill"},"landuse/meadow":{"geometry":["area"],"tags":{"landuse":"meadow"},"terms":[],"name":"Meadow"},"landuse/military":{"icon":"poi-military","geometry":["area"],"tags":{"landuse":"military"},"terms":[],"matchScore":0.9,"name":"Military Area"},"landuse/military/airfield":{"icon":"airfield","fields":["ref","iata","icao"],"geometry":["point","area"],"tags":{"military":"airfield"},"addTags":{"landuse":"military","military":"airfield"},"removeTags":{"landuse":"military","military":"airfield"},"terms":["air force","army","base","bomb","fight","force","guard","heli*","jet","marine","navy","plane","troop","war"],"name":"Military Airfield"},"landuse/military/barracks":{"icon":"poi-military","fields":["building_area"],"geometry":["point","area"],"tags":{"military":"barracks"},"addTags":{"landuse":"military","military":"barracks"},"removeTags":{"landuse":"military","military":"barracks"},"terms":["air force","army","base","fight","force","guard","marine","navy","troop","war"],"name":"Barracks"},"landuse/military/bunker":{"icon":"poi-military","fields":["bunker_type","building_area"],"geometry":["point","area"],"tags":{"military":"bunker"},"addTags":{"building":"bunker","landuse":"military","military":"bunker"},"removeTags":{"building":"bunker","landuse":"military","military":"bunker"},"terms":["air force","army","base","fight","force","guard","marine","navy","troop","war"],"name":"Military Bunker"},"landuse/military/checkpoint":{"icon":"barrier","geometry":["point","vertex","area"],"tags":{"military":"checkpoint"},"addTags":{"landuse":"military","military":"checkpoint"},"removeTags":{"landuse":"military","military":"checkpoint"},"terms":["air force","army","base","force","guard","marine","navy","troop","war"],"name":"Checkpoint"},"landuse/military/danger_area":{"icon":"danger","geometry":["point","vertex","area"],"tags":{"military":"danger_area"},"addTags":{"landuse":"military","military":"danger_area"},"removeTags":{"landuse":"military","military":"danger_area"},"terms":["air force","army","base","blast","bomb","explo*","force","guard","mine","marine","navy","troop","war"],"name":"Danger Area"},"landuse/military/naval_base":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"naval_base"},"addTags":{"landuse":"military","military":"naval_base"},"removeTags":{"landuse":"military","military":"naval_base"},"terms":["base","fight","force","guard","marine","navy","ship","sub","troop","war"],"name":"Naval Base"},"landuse/military/nuclear_explosion_site":{"icon":"danger","geometry":["point","vertex","area"],"tags":{"military":"nuclear_explosion_site"},"addTags":{"landuse":"military","military":"nuclear_explosion_site"},"removeTags":{"landuse":"military","military":"nuclear_explosion_site"},"terms":["atom","blast","bomb","detonat*","nuke","site","test"],"name":"Nuclear Explosion Site"},"landuse/military/obstacle_course":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"obstacle_course"},"addTags":{"landuse":"military","military":"obstacle_course"},"removeTags":{"landuse":"military","military":"obstacle_course"},"terms":["army","base","force","guard","marine","navy","troop","war"],"name":"Obstacle Course"},"landuse/military/office":{"icon":"poi-military","fields":["building_area"],"geometry":["point","area"],"tags":{"military":"office"},"addTags":{"landuse":"military","military":"office"},"removeTags":{"landuse":"military","military":"office"},"terms":["air force","army","base","enlist","fight","force","guard","marine","navy","recruit","troop","war"],"name":"Military Office"},"landuse/military/range":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"range"},"addTags":{"landuse":"military","military":"range"},"removeTags":{"landuse":"military","military":"range"},"terms":["air force","army","base","fight","fire","force","guard","gun","marine","navy","rifle","shoot*","snip*","train","troop","war"],"name":"Military Range"},"landuse/military/training_area":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"training_area"},"addTags":{"landuse":"military","military":"training_area"},"removeTags":{"landuse":"military","military":"training_area"},"terms":["air force","army","base","fight","fire","force","guard","gun","marine","navy","rifle","shoot*","snip*","train","troop","war"],"name":"Training Area"},"landuse/orchard":{"icon":"park-alt1","fields":["operator","trees"],"geometry":["area"],"tags":{"landuse":"orchard"},"terms":["fruit"],"name":"Orchard"},"landuse/plant_nursery":{"icon":"garden","fields":["operator","plant"],"geometry":["area"],"tags":{"landuse":"plant_nursery"},"terms":["flower","garden","grow","vivero"],"name":"Plant Nursery"},"landuse/quarry":{"geometry":["area"],"tags":{"landuse":"quarry"},"terms":[],"name":"Quarry"},"landuse/railway":{"icon":"rail","fields":["operator"],"geometry":["area"],"tags":{"landuse":"railway"},"terms":["rail","train","track"],"name":"Railway Corridor"},"landuse/recreation_ground":{"icon":"pitch","geometry":["area"],"tags":{"landuse":"recreation_ground"},"terms":["playing fields"],"name":"Recreation Ground"},"landuse/residential":{"icon":"building","geometry":["area"],"tags":{"landuse":"residential"},"terms":[],"name":"Residential Area"},"landuse/retail":{"icon":"shop","geometry":["area"],"tags":{"landuse":"retail"},"name":"Retail Area"},"landuse/vineyard":{"fields":["operator","grape_variety"],"geometry":["area"],"tags":{"landuse":"vineyard"},"addTags":{"landuse":"vineyard","crop":"grape"},"removeTags":{"landuse":"vineyard","crop":"grape","grape_variety":"*"},"terms":["grape","wine"],"name":"Vineyard"},"leisure":{"icon":"pitch","fields":["leisure"],"geometry":["point","vertex","area"],"tags":{"leisure":"*"},"name":"Leisure"},"leisure/adult_gaming_centre":{"icon":"poi-dice","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"terms":["gambling","slot machine"],"tags":{"leisure":"adult_gaming_centre"},"name":"Adult Gaming Center"},"leisure/bird_hide":{"icon":"poi-binoculars","fields":["building_area"],"geometry":["point","area"],"tags":{"leisure":"bird_hide"},"terms":["machan","ornithology"],"name":"Bird Hide"},"leisure/bowling_alley":{"icon":"poi-bowling","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"terms":[],"tags":{"leisure":"bowling_alley"},"name":"Bowling Alley"},"leisure/common":{"icon":"poi-foot","geometry":["point","area"],"terms":["open space"],"tags":{"leisure":"common"},"name":"Common"},"leisure/dance":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ballroom","jive","swing","tango","waltz"],"tags":{"leisure":"dance"},"name":"Dance Hall"},"leisure/dog_park":{"icon":"dog-park","geometry":["point","area"],"terms":[],"tags":{"leisure":"dog_park"},"name":"Dog Park"},"leisure/firepit":{"icon":"fire-station","geometry":["point","area"],"tags":{"leisure":"firepit"},"terms":["fireplace","campfire"],"name":"Firepit"},"leisure/fitness_centre":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"fitness_centre"},"terms":["health","gym","leisure","studio"],"name":"Gym / Fitness Center"},"leisure/fitness_centre/yoga":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["studio"],"tags":{"leisure":"fitness_centre","sport":"yoga"},"reference":{"key":"sport","value":"yoga"},"name":"Yoga Studio"},"leisure/fitness_station":{"icon":"pitch","fields":["sport","address","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"fitness_station"},"terms":["fitness","gym"],"name":"Outdoor Fitness Station"},"leisure/garden":{"icon":"garden","fields":["access_simple"],"geometry":["point","vertex","area"],"tags":{"leisure":"garden"},"name":"Garden"},"leisure/golf_course":{"icon":"golf","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["links"],"tags":{"leisure":"golf_course"},"name":"Golf Course"},"leisure/horse_riding":{"icon":"horse-riding","fields":["access_simple","operator","address","building"],"geometry":["point","area"],"terms":["equestrian","stable"],"tags":{"leisure":"horse_riding"},"name":"Horseback Riding Facility"},"leisure/ice_rink":{"icon":"pitch","fields":["seasonal","sport_ice","operator","address","building","opening_hours"],"geometry":["point","area"],"terms":["hockey","skating","curling"],"tags":{"leisure":"ice_rink"},"name":"Ice Rink"},"leisure/marina":{"icon":"harbor","fields":["operator","address","capacity","fee","sanitary_dump_station","power_supply","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["boat"],"tags":{"leisure":"marina"},"name":"Marina"},"leisure/miniature_golf":{"icon":"golf","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["crazy golf","mini golf","putt-putt"],"tags":{"leisure":"miniature_golf"},"name":"Miniature Golf"},"leisure/nature_reserve":{"icon":"park","geometry":["point","area"],"tags":{"leisure":"nature_reserve"},"terms":["protected","wildlife"],"name":"Nature Reserve"},"leisure/park":{"icon":"park","geometry":["point","area"],"terms":["esplanade","estate","forest","garden","grass","green","grounds","lawn","lot","meadow","parkland","place","playground","plaza","pleasure garden","recreation area","square","tract","village green","woodland"],"tags":{"leisure":"park"},"name":"Park"},"leisure/picnic_table":{"icon":"picnic-site","geometry":["point"],"tags":{"leisure":"picnic_table"},"terms":["bench"],"name":"Picnic Table"},"leisure/pitch":{"icon":"pitch","fields":["sport","surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch"},"terms":["field"],"name":"Sport Pitch"},"leisure/pitch/american_football":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"american_football"},"reference":{"key":"sport","value":"american_football"},"terms":[],"name":"American Football Field"},"leisure/pitch/baseball":{"icon":"baseball","fields":["lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"baseball"},"reference":{"key":"sport","value":"baseball"},"terms":[],"name":"Baseball Diamond"},"leisure/pitch/basketball":{"icon":"basketball","fields":["surface","hoops","lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"basketball"},"reference":{"key":"sport","value":"basketball"},"terms":[],"name":"Basketball Court"},"leisure/pitch/beachvolleyball":{"icon":"basketball","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"beachvolleyball"},"addTags":{"leisure":"pitch","sport":"beachvolleyball","surface":"sand"},"removeTags":{"leisure":"pitch","sport":"beachvolleyball","surface":"sand"},"reference":{"key":"sport","value":"beachvolleyball"},"terms":["volleyball"],"name":"Beach Volleyball Court"},"leisure/pitch/bowls":{"icon":"pitch","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"bowls"},"reference":{"key":"sport","value":"bowls"},"terms":[],"name":"Bowling Green"},"leisure/pitch/cricket":{"icon":"cricket","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"cricket"},"reference":{"key":"sport","value":"cricket"},"terms":[],"name":"Cricket Field"},"leisure/pitch/equestrian":{"icon":"horse-riding","fields":["surface","lit","building"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"equestrian"},"reference":{"key":"sport","value":"equestrian"},"terms":["dressage","equestrian","horse","horseback","riding"],"name":"Riding Arena"},"leisure/pitch/rugby_league":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"rugby_league"},"reference":{"key":"sport","value":"rugby_league"},"terms":[],"name":"Rugby League Field"},"leisure/pitch/rugby_union":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"rugby_union"},"reference":{"key":"sport","value":"rugby_union"},"terms":[],"name":"Rugby Union Field"},"leisure/pitch/skateboard":{"icon":"pitch","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"skateboard"},"reference":{"key":"sport","value":"skateboard"},"terms":[],"name":"Skate Park"},"leisure/pitch/soccer":{"icon":"soccer","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"soccer"},"reference":{"key":"sport","value":"soccer"},"terms":[],"name":"Soccer Field"},"leisure/pitch/table_tennis":{"icon":"tennis","fields":["lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"table_tennis"},"reference":{"key":"sport","value":"table_tennis"},"terms":["table tennis","ping pong"],"name":"Ping Pong Table"},"leisure/pitch/tennis":{"icon":"tennis","fields":["surface","lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"tennis"},"reference":{"key":"sport","value":"tennis"},"terms":[],"name":"Tennis Court"},"leisure/pitch/volleyball":{"icon":"basketball","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"volleyball"},"reference":{"key":"sport","value":"volleyball"},"terms":[],"name":"Volleyball Court"},"leisure/playground":{"icon":"playground","geometry":["point","area"],"terms":["jungle gym","play area"],"tags":{"leisure":"playground"},"name":"Playground"},"leisure/resort":{"icon":"lodging","fields":["operator","address","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"resort"},"name":"Resort"},"leisure/running_track":{"icon":"pitch","fields":["surface","sport_racing_nonmotor","lit","width","lanes"],"geometry":["point","line","area"],"tags":{"leisure":"track","sport":"running"},"terms":["race*","running","sprint","track"],"name":"Racetrack (Running)"},"leisure/slipway":{"icon":"poi-beach","geometry":["point","line"],"terms":["boat launch","boat ramp"],"tags":{"leisure":"slipway"},"name":"Slipway"},"leisure/sports_centre":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"sports_centre"},"terms":[],"name":"Sports Center / Complex"},"leisure/sports_centre/swimming":{"icon":"swimming","fields":["access_simple","operator","address","building"],"geometry":["point","area"],"terms":["dive","water"],"tags":{"leisure":"sports_centre","sport":"swimming"},"reference":{"key":"sport","value":"swimming"},"name":"Swimming Pool Facility"},"leisure/stadium":{"icon":"pitch","fields":["sport","address"],"geometry":["point","area"],"tags":{"leisure":"stadium"},"name":"Stadium"},"leisure/swimming_pool":{"icon":"swimming","fields":["access_simple","operator","address"],"geometry":["point","area"],"terms":["dive","water"],"tags":{"leisure":"swimming_pool"},"name":"Swimming Pool"},"leisure/track":{"icon":"highway-road","fields":["surface","sport_racing_nonmotor","lit","width","lanes"],"geometry":["point","line","area"],"tags":{"leisure":"track"},"terms":["cycle","dog","greyhound","horse","race*","track"],"name":"Racetrack (Non-Motorsport)"},"leisure/water_park":{"icon":"swimming","fields":["operator","address"],"geometry":["point","area"],"terms":["swim","pool","dive"],"tags":{"leisure":"water_park"},"name":"Water Park"},"line":{"name":"Line","tags":{},"geometry":["line"],"matchScore":0.1},"man_made":{"icon":"poi-storage-tank","fields":["man_made"],"geometry":["point","vertex","line","area"],"tags":{"man_made":"*"},"name":"Man Made"},"man_made/embankment":{"geometry":["line"],"tags":{"man_made":"embankment"},"name":"Embankment","searchable":false},"man_made/adit":{"icon":"triangle","geometry":["point","area"],"fields":["operator"],"terms":["entrance","underground","mine","cave"],"tags":{"man_made":"adit"},"name":"Adit"},"man_made/breakwater":{"geometry":["line","area"],"tags":{"man_made":"breakwater"},"name":"Breakwater"},"man_made/bridge":{"geometry":["area"],"tags":{"man_made":"bridge"},"name":"Bridge"},"man_made/chimney":{"icon":"poi-chimney","geometry":["point","area"],"tags":{"man_made":"chimney"},"name":"Chimney"},"man_made/cutline":{"geometry":["line"],"tags":{"man_made":"cutline"},"name":"Cut line"},"man_made/flagpole":{"icon":"embassy","geometry":["point"],"tags":{"man_made":"flagpole"},"name":"Flagpole"},"man_made/gasometer":{"icon":"poi-storage-tank","geometry":["point","area"],"terms":["gas holder"],"tags":{"man_made":"gasometer"},"name":"Gasometer"},"man_made/groyne":{"geometry":["line","area"],"tags":{"man_made":"groyne"},"name":"Groyne"},"man_made/lighthouse":{"icon":"lighthouse","fields":["building_area"],"geometry":["point","area"],"tags":{"man_made":"lighthouse"},"name":"Lighthouse"},"man_made/mast":{"icon":"poi-mast","fields":["tower/type","tower/construction","height","communication_multi"],"geometry":["point"],"terms":["antenna","broadcast tower","cell phone tower","cell tower","communication mast","communication tower","guyed tower","mobile phone tower","radio mast","radio tower","television tower","transmission mast","transmission tower","tv tower"],"tags":{"man_made":"mast"},"name":"Mast"},"man_made/observation":{"icon":"poi-tower","geometry":["point","area"],"terms":["lookout tower","fire tower"],"tags":{"man_made":"tower","tower:type":"observation"},"name":"Observation Tower"},"man_made/petroleum_well":{"icon":"poi-storage-tank","geometry":["point"],"terms":["drilling rig","oil derrick","oil drill","oil horse","oil rig","oil pump","petroleum well","pumpjack"],"tags":{"man_made":"petroleum_well"},"name":"Oil Well"},"man_made/pier":{"geometry":["line","area"],"terms":["dock"],"tags":{"man_made":"pier"},"name":"Pier"},"man_made/pipeline":{"icon":"pipeline-line","fields":["location","operator"],"geometry":["line"],"tags":{"man_made":"pipeline"},"name":"Pipeline"},"man_made/pumping_station":{"icon":"water","geometry":["point","area"],"tags":{"man_made":"pumping_station"},"name":"Pumping Station"},"man_made/silo":{"icon":"poi-silo","fields":["building_area","crop"],"geometry":["point","area"],"terms":["grain","corn","wheat"],"tags":{"man_made":"silo"},"name":"Silo"},"man_made/storage_tank":{"icon":"poi-storage-tank","fields":["building_area","content"],"geometry":["point","area"],"terms":["water","oil","gas","petrol"],"tags":{"man_made":"storage_tank"},"name":"Storage Tank"},"man_made/surveillance_camera":{"icon":"attraction","geometry":["point"],"fields":["surveillance","surveillance/type","camera/type","camera/mount","camera/direction","surveillance/zone","contact/webcam"],"terms":["anpr","alpr","camera","car plate recognition","cctv","guard","license plate recognition","monitoring","number plate recognition","security","video","webcam"],"tags":{"man_made":"surveillance","surveillance:type":"camera"},"name":"Surveillance Camera"},"man_made/surveillance":{"icon":"attraction","geometry":["point"],"fields":["surveillance","surveillance/type","surveillance/zone"],"terms":["anpr","alpr","camera","car plate recognition","cctv","guard","license plate recognition","monitoring","number plate recognition","security","video","webcam"],"tags":{"man_made":"surveillance"},"name":"Surveillance"},"man_made/survey_point":{"icon":"monument","fields":["ref"],"geometry":["point","vertex"],"tags":{"man_made":"survey_point"},"name":"Survey Point"},"man_made/tower":{"icon":"poi-tower","fields":["tower/type","tower/construction","height"],"geometry":["point","area"],"tags":{"man_made":"tower"},"name":"Tower"},"man_made/wastewater_plant":{"icon":"water","fields":["operator","address"],"geometry":["point","area"],"terms":["sewage*","water treatment plant","reclamation plant"],"tags":{"man_made":"wastewater_plant"},"name":"Wastewater Plant"},"man_made/water_tower":{"icon":"water","fields":["operator"],"geometry":["point","area"],"tags":{"man_made":"water_tower"},"name":"Water Tower"},"man_made/water_well":{"icon":"water","fields":["operator"],"geometry":["point","area"],"tags":{"man_made":"water_well"},"name":"Water Well"},"man_made/water_works":{"icon":"water","fields":["operator","address"],"geometry":["point","area"],"tags":{"man_made":"water_works"},"name":"Water Works"},"man_made/works":{"icon":"industry","fields":["operator","address","building_area","product"],"geometry":["point","area"],"terms":["assembly","build","brewery","car","plant","plastic","processing","manufacture","refinery"],"tags":{"man_made":"works"},"name":"Factory"},"natural":{"icon":"natural","fields":["natural"],"geometry":["point","vertex","area"],"tags":{"natural":"*"},"name":"Natural"},"natural/bare_rock":{"geometry":["area"],"tags":{"natural":"bare_rock"},"terms":["rock"],"name":"Bare Rock"},"natural/bay":{"icon":"poi-beach","geometry":["point","area"],"tags":{"natural":"bay"},"terms":[],"name":"Bay"},"natural/beach":{"icon":"poi-beach","fields":["surface"],"geometry":["point","area"],"tags":{"natural":"beach"},"terms":["shore"],"name":"Beach"},"natural/cave_entrance":{"icon":"triangle","geometry":["point","area"],"fields":["fee","access_simple"],"tags":{"natural":"cave_entrance"},"terms":["cavern","hollow","grotto","shelter","cavity"],"name":"Cave Entrance"},"natural/cliff":{"icon":"triangle","geometry":["point","vertex","line","area"],"tags":{"natural":"cliff"},"terms":["escarpment"],"name":"Cliff"},"natural/coastline":{"geometry":["line"],"tags":{"natural":"coastline"},"terms":["shore"],"name":"Coastline"},"natural/fell":{"geometry":["area"],"tags":{"natural":"fell"},"terms":[],"name":"Fell"},"natural/glacier":{"geometry":["area"],"tags":{"natural":"glacier"},"terms":[],"name":"Glacier"},"natural/grassland":{"geometry":["area"],"tags":{"natural":"grassland"},"terms":["prairie","savanna"],"name":"Grassland"},"natural/heath":{"geometry":["area"],"tags":{"natural":"heath"},"terms":[],"name":"Heath"},"natural/peak":{"icon":"mountain","fields":["elevation"],"geometry":["point","vertex"],"tags":{"natural":"peak"},"terms":["acme","aiguille","alp","climax","crest","crown","hill","mount","mountain","pinnacle","summit","tip","top"],"name":"Peak"},"natural/ridge":{"geometry":["line"],"tags":{"natural":"ridge"},"terms":["crest"],"name":"Ridge"},"natural/saddle":{"icon":"triangle-stroked","fields":["elevation"],"geometry":["point","vertex"],"tags":{"natural":"saddle"},"terms":["pass","mountain pass","top"],"name":"Saddle"},"natural/sand":{"geometry":["area"],"tags":{"natural":"sand"},"terms":["desert"],"name":"Sand"},"natural/scree":{"geometry":["area"],"tags":{"natural":"scree"},"terms":["loose rocks"],"name":"Scree"},"natural/scrub":{"geometry":["area"],"tags":{"natural":"scrub"},"terms":["bush","shrubs"],"name":"Scrub"},"natural/spring":{"icon":"water","geometry":["point","vertex"],"tags":{"natural":"spring"},"terms":[],"name":"Spring"},"natural/tree_row":{"icon":"park","fields":["leaf_type","leaf_cycle","denotation"],"geometry":["line"],"tags":{"natural":"tree_row"},"terms":[],"name":"Tree row"},"natural/tree":{"icon":"park","fields":["leaf_type_singular","leaf_cycle_singular","denotation"],"geometry":["point","vertex"],"tags":{"natural":"tree"},"terms":[],"name":"Tree"},"natural/volcano":{"icon":"volcano","fields":["elevation"],"geometry":["point","vertex"],"tags":{"natural":"volcano"},"terms":["mountain","crater"],"name":"Volcano"},"natural/water":{"icon":"water","fields":["water"],"geometry":["area"],"tags":{"natural":"water"},"name":"Water"},"natural/water/lake":{"icon":"water","geometry":["area"],"tags":{"natural":"water","water":"lake"},"reference":{"key":"natural","value":"water"},"terms":["lakelet","loch","mere"],"name":"Lake"},"natural/water/pond":{"icon":"water","geometry":["area"],"tags":{"natural":"water","water":"pond"},"reference":{"key":"natural","value":"water"},"terms":["lakelet","millpond","tarn","pool","mere"],"name":"Pond"},"natural/water/reservoir":{"icon":"water","geometry":["area"],"tags":{"natural":"water","water":"reservoir"},"reference":{"key":"natural","value":"water"},"name":"Reservoir"},"natural/wetland":{"icon":"wetland","fields":["wetland"],"geometry":["point","area"],"tags":{"natural":"wetland"},"terms":[],"name":"Wetland"},"natural/wood":{"icon":"park-alt1","fields":["leaf_type","leaf_cycle"],"geometry":["point","area"],"tags":{"natural":"wood"},"terms":["tree"],"name":"Wood"},"noexit/yes":{"icon":"barrier","geometry":["vertex"],"terms":["no exit","road end","dead end"],"tags":{"noexit":"yes"},"reference":{"key":"noexit","value":"*"},"name":"No Exit"},"office":{"icon":"commercial","fields":["office","address","building_area","opening_hours","smoking"],"geometry":["point","vertex","area"],"tags":{"office":"*"},"terms":[],"name":"Office"},"office/travel_agent":{"icon":"suitcase","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"travel_agent"},"reference":{"key":"shop","value":"travel_agency"},"terms":[],"name":"Travel Agency","searchable":false},"office/accountant":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"accountant"},"terms":[],"name":"Accountant"},"office/administrative":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"administrative"},"terms":[],"name":"Administrative Office"},"office/architect":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"architect"},"terms":[],"name":"Architect"},"office/company":{"icon":"commercial","fields":["address","building_area","opening_hours","smoking"],"geometry":["point","vertex","area"],"tags":{"office":"company"},"terms":[],"name":"Company Office"},"office/coworking":{"icon":"commercial","fields":["address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"terms":["coworking","office"],"tags":{"office":"coworking"},"reference":{"key":"amenity","value":"coworking_space"},"name":"Coworking Space"},"office/educational_institution":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"educational_institution"},"terms":[],"name":"Educational Institution"},"office/employment_agency":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"employment_agency"},"terms":["job"],"name":"Employment Agency"},"office/estate_agent":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"estate_agent"},"terms":[],"name":"Real Estate Office"},"office/financial":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"financial"},"terms":[],"name":"Financial Office"},"office/government":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"government"},"terms":[],"name":"Government Office"},"office/government/register_office":{"icon":"town-hall","fields":["address","building_area","opening_hours","operator"],"geometry":["point","area"],"terms":["clerk","marriage","death","birth","certificate"],"tags":{"office":"government","government":"register_office"},"reference":{"key":"government","value":"register_office"},"name":"Register Office"},"office/insurance":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"insurance"},"terms":[],"name":"Insurance Office"},"office/it":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"it"},"terms":[],"name":"IT Office"},"office/lawyer":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"lawyer"},"terms":[],"name":"Law Office"},"office/lawyer/notary":{"icon":"suitcase","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"lawyer","lawyer":"notary"},"reference":{"key":"office","value":"notary"},"terms":["clerk","signature","wills","deeds","estate"],"name":"Notary Office"},"office/newspaper":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"newspaper"},"terms":[],"name":"Newspaper"},"office/ngo":{"icon":"commercial","fields":["address","building_area","opening_hours","smoking"],"geometry":["point","vertex","area"],"tags":{"office":"ngo"},"terms":[],"name":"NGO Office"},"office/physician":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"physician"},"terms":[],"name":"Physician"},"office/political_party":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"political_party"},"terms":[],"name":"Political Party"},"office/research":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"research"},"terms":[],"name":"Research Office"},"office/telecommunication":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"telecommunication"},"terms":[],"name":"Telecom Office"},"office/therapist":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"therapist"},"terms":[],"name":"Therapist"},"piste":{"icon":"skiing","fields":["piste/type","piste/difficulty","piste/grooming","oneway","lit"],"geometry":["point","line","area"],"terms":["ski","sled","sleigh","snowboard","nordic","downhill","snowmobile"],"tags":{"piste:type":"*"},"name":"Piste/Ski Trail"},"place/farm":{"icon":"farm","geometry":["point","area"],"tags":{"place":"farm"},"name":"Farm","searchable":false},"place/city":{"icon":"city","fields":["population"],"geometry":["point","area"],"tags":{"place":"city"},"name":"City"},"place/hamlet":{"icon":"triangle-stroked","fields":["population"],"geometry":["point","area"],"tags":{"place":"hamlet"},"name":"Hamlet"},"place/island":{"icon":"mountain","geometry":["point","area"],"terms":["archipelago","atoll","bar","cay","isle","islet","key","reef"],"tags":{"place":"island"},"name":"Island"},"place/isolated_dwelling":{"icon":"home","geometry":["point","area"],"tags":{"place":"isolated_dwelling"},"name":"Isolated Dwelling"},"place/locality":{"icon":"triangle-stroked","geometry":["point","area"],"tags":{"place":"locality"},"name":"Locality"},"place/neighbourhood":{"icon":"triangle-stroked","fields":["population"],"geometry":["point","area"],"tags":{"place":"neighbourhood"},"terms":["neighbourhood"],"name":"Neighborhood"},"place/quarter":{"icon":"triangle-stroked","fields":["population"],"geometry":["point","area"],"tags":{"place":"quarter"},"terms":["boro","borough","quarter"],"name":"Sub-Borough / Quarter"},"place/square":{"icon":"poi-foot","geometry":["point","area"],"tags":{"place":"square"},"name":"Square"},"place/suburb":{"icon":"triangle-stroked","fields":["population"],"geometry":["point","area"],"tags":{"place":"suburb"},"terms":["boro","borough","quarter"],"name":"Borough / Suburb"},"place/town":{"icon":"town","fields":["population"],"geometry":["point","area"],"tags":{"place":"town"},"name":"Town"},"place/village":{"icon":"village","fields":["population"],"geometry":["point","area"],"tags":{"place":"village"},"name":"Village"},"point":{"name":"Point","tags":{},"geometry":["point"],"matchScore":0.1},"power/sub_station":{"fields":["substation","operator","building"],"geometry":["point","area"],"tags":{"power":"sub_station"},"reference":{"key":"power","value":"substation"},"name":"Substation","searchable":false},"power/generator":{"icon":"poi-power","fields":["operator","generator/source","generator/method","generator/type"],"geometry":["point","vertex","area"],"tags":{"power":"generator"},"name":"Power Generator"},"power/line":{"icon":"power-line","geometry":["line"],"tags":{"power":"line"},"name":"Power Line"},"power/minor_line":{"icon":"power-line","geometry":["line"],"tags":{"power":"minor_line"},"name":"Minor Power Line"},"power/plant":{"icon":"industry","fields":["operator"],"geometry":["area"],"tags":{"power":"plant"},"addTags":{"power":"plant","landuse":"industrial"},"removeTags":{"power":"plant","landuse":"industrial"},"terms":["coal","gas","generat*","hydro","nuclear","power","station"],"name":"Power Station Grounds"},"power/pole":{"geometry":["vertex"],"tags":{"power":"pole"},"name":"Power Pole"},"power/substation":{"icon":"poi-power","fields":["substation","operator","building"],"geometry":["point","area"],"tags":{"power":"substation"},"name":"Substation"},"power/tower":{"geometry":["vertex"],"tags":{"power":"tower"},"name":"High-Voltage Tower"},"power/transformer":{"icon":"poi-power","geometry":["point","vertex","area"],"tags":{"power":"transformer"},"name":"Transformer"},"public_transport/platform":{"icon":"bus","fields":["ref","network","operator","shelter"],"geometry":["point","vertex","line","area"],"tags":{"public_transport":"platform"},"name":"Platform"},"public_transport/stop_position":{"icon":"bus","fields":["ref","network","operator"],"geometry":["vertex"],"tags":{"public_transport":"stop_position"},"name":"Stop Position"},"railway/abandoned":{"icon":"railway-abandoned","geometry":["line"],"tags":{"railway":"abandoned"},"fields":["structure","service_rail"],"terms":[],"name":"Abandoned Railway"},"railway/crossing":{"icon":"cross","geometry":["vertex"],"tags":{"railway":"crossing"},"terms":["crossing","pedestrian crossing","railroad crossing","level crossing","grade crossing","path through railroad","train crossing"],"name":"Railway Crossing (Path)"},"railway/disused":{"icon":"railway-disused","geometry":["line"],"tags":{"railway":"disused"},"fields":["structure","service_rail"],"terms":[],"name":"Disused Railway"},"railway/funicular":{"icon":"railway-rail","geometry":["line"],"terms":["venicular","cliff railway","cable car","cable railway","funicular railway"],"fields":["structure","gauge","service_rail"],"tags":{"railway":"funicular"},"name":"Funicular"},"railway/halt":{"icon":"rail","geometry":["point","vertex"],"tags":{"railway":"halt"},"name":"Railway Halt","terms":["break","interrupt","rest","wait","interruption"]},"railway/level_crossing":{"icon":"cross","geometry":["vertex"],"tags":{"railway":"level_crossing"},"terms":["crossing","railroad crossing","level crossing","grade crossing","road through railroad","train crossing"],"name":"Railway Crossing (Road)"},"railway/monorail":{"icon":"railway-monorail","geometry":["line"],"tags":{"railway":"monorail"},"fields":["structure","electrified","service_rail"],"terms":[],"name":"Monorail"},"railway/narrow_gauge":{"icon":"railway-rail","geometry":["line"],"tags":{"railway":"narrow_gauge"},"fields":["structure","gauge","electrified","service_rail"],"terms":["narrow gauge railway","narrow gauge railroad"],"name":"Narrow Gauge Rail"},"railway/platform":{"icon":"rail","geometry":["point","vertex","line","area"],"tags":{"railway":"platform"},"name":"Railway Platform"},"railway/rail":{"icon":"railway-rail","geometry":["line"],"tags":{"railway":"rail"},"fields":["structure","gauge","electrified","maxspeed","service_rail"],"terms":[],"name":"Rail"},"railway/station":{"icon":"rail","fields":["network","operator","address","building_area","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"tags":{"railway":"station"},"terms":["train station","station"],"name":"Railway Station"},"railway/subway_entrance":{"icon":"entrance","geometry":["point"],"tags":{"railway":"subway_entrance"},"terms":[],"name":"Subway Entrance"},"railway/subway":{"icon":"railway-subway","geometry":["line"],"tags":{"railway":"subway"},"fields":["structure","gauge","electrified","service_rail"],"terms":[],"name":"Subway"},"railway/tram_stop":{"icon":"rail-light","fields":["network","operator"],"geometry":["vertex"],"tags":{"railway":"tram_stop"},"terms":["light rail","streetcar","tram","trolley"],"name":"Tram Stop"},"railway/tram":{"icon":"railway-light-rail","geometry":["line"],"tags":{"railway":"tram"},"fields":["structure","gauge","electrified","service_rail"],"terms":["light rail","streetcar","tram","trolley"],"name":"Tram"},"relation":{"name":"Relation","icon":"relation","tags":{},"geometry":["relation"],"fields":["relation"]},"route/ferry":{"icon":"ferry-line","geometry":["line"],"tags":{"route":"ferry"},"name":"Ferry Route"},"shop":{"icon":"shop","fields":["shop","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"*"},"terms":[],"name":"Shop"},"shop/fishmonger":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"fishmonger"},"reference":{"key":"shop","value":"seafood"},"name":"Fishmonger","searchable":false},"shop/vacant":{"icon":"shop","fields":["address","building_area"],"geometry":["point","area"],"tags":{"shop":"vacant"},"name":"Vacant Shop","searchable":false},"shop/alcohol":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours","drive_through"],"geometry":["point","area"],"terms":["alcohol","beer","booze","wine"],"tags":{"shop":"alcohol"},"name":"Liquor Store"},"shop/anime":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"anime"},"terms":["manga","japan","cosplay","figurine","dakimakura"],"name":"Anime Shop"},"shop/antiques":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"antiques"},"name":"Antiques Shop"},"shop/art":{"icon":"shop","fields":["artwork_type","operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["art*","exhibit*","gallery"],"tags":{"shop":"art"},"name":"Art Store"},"shop/baby_goods":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"baby_goods"},"name":"Baby Goods Store"},"shop/bag":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["handbag","purse"],"tags":{"shop":"bag"},"name":"Bag/Luggage Store"},"shop/bakery":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"bakery"},"name":"Bakery"},"shop/bathroom_furnishing":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"bathroom_furnishing"},"name":"Bathroom Furnishing Store"},"shop/beauty":{"icon":"shop","fields":["operator","address","building_area","opening_hours","beauty"],"geometry":["point","area"],"terms":["spa","salon","tanning"],"tags":{"shop":"beauty"},"name":"Beauty Shop"},"shop/beauty/nails":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["manicure","pedicure"],"tags":{"shop":"beauty","beauty":"nails"},"reference":{"key":"shop","value":"beauty"},"name":"Nail Salon"},"shop/beauty/tanning":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"beauty","beauty":"tanning"},"reference":{"key":"leisure","value":"tanning_salon"},"name":"Tanning Salon"},"shop/bed":{"icon":"lodging","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"bed"},"name":"Bedding/Mattress Store"},"shop/beverages":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"beverages"},"name":"Beverage Store"},"shop/bicycle":{"icon":"bicycle","fields":["operator","address","building_area","opening_hours","service/bicycle"],"geometry":["point","area"],"terms":["bike","repair"],"tags":{"shop":"bicycle"},"name":"Bicycle Shop"},"shop/bookmaker":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["betting"],"tags":{"shop":"bookmaker"},"name":"Bookmaker"},"shop/books":{"icon":"shop","fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"shop":"books"},"name":"Book Store"},"shop/boutique":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"boutique"},"name":"Boutique"},"shop/butcher":{"icon":"slaughterhouse","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["meat"],"tags":{"shop":"butcher"},"name":"Butcher"},"shop/candles":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"candles"},"name":"Candle Shop"},"shop/car_parts":{"icon":"car","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["auto"],"tags":{"shop":"car_parts"},"name":"Car Parts Store"},"shop/car_repair":{"icon":"car","fields":["operator","address","building_area","opening_hours","service/vehicle"],"geometry":["point","area"],"terms":["auto","garage","service"],"tags":{"shop":"car_repair"},"name":"Car Repair Shop"},"shop/car":{"icon":"car","fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"geometry":["point","area"],"terms":["auto"],"tags":{"shop":"car"},"name":"Car Dealership"},"shop/carpet":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["rug"],"tags":{"shop":"carpet"},"name":"Carpet Store"},"shop/charity":{"icon":"shop","fields":["operator","address","building_area","opening_hours","second_hand"],"geometry":["point","area"],"terms":["thrift","op shop","nonprofit"],"tags":{"shop":"charity"},"name":"Charity Store"},"shop/cheese":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"cheese"},"name":"Cheese Store"},"shop/chemist":{"icon":"grocery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"chemist"},"terms":["med*","drug*","gift"],"name":"Drugstore"},"shop/chocolate":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"chocolate"},"name":"Chocolate Store"},"shop/clothes":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"clothes"},"name":"Clothing Store"},"shop/coffee":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"coffee"},"name":"Coffee Store"},"shop/computer":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"computer"},"name":"Computer Store"},"shop/confectionery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"confectionery"},"name":"Candy Store"},"shop/convenience":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"convenience"},"name":"Convenience Store"},"shop/copyshop":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"copyshop"},"name":"Copy Store"},"shop/cosmetics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"cosmetics"},"name":"Cosmetics Store"},"shop/craft":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"craft"},"terms":["art*","paint*","frame"],"name":"Arts and Crafts Store"},"shop/curtain":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["drape*","window"],"tags":{"shop":"curtain"},"name":"Curtain Store"},"shop/dairy":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["milk","egg","cheese"],"tags":{"shop":"dairy"},"name":"Dairy Store"},"shop/deli":{"icon":"restaurant","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["lunch","meat","sandwich"],"tags":{"shop":"deli"},"name":"Deli"},"shop/department_store":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"department_store"},"name":"Department Store"},"shop/doityourself":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"doityourself"},"name":"DIY Store"},"shop/dry_cleaning":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"dry_cleaning"},"name":"Dry Cleaner"},"shop/e-cigarette":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"e-cigarette"},"terms":["electronic","vapor"],"name":"E-Cigarette Shop"},"shop/electronics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["appliance","audio","computer","tv"],"tags":{"shop":"electronics"},"name":"Electronics Store"},"shop/erotic":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sex","porn"],"tags":{"shop":"erotic"},"name":"Erotic Store"},"shop/fabric":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sew"],"tags":{"shop":"fabric"},"name":"Fabric Store"},"shop/farm":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["farm shop","farm stand"],"tags":{"shop":"farm"},"name":"Produce Stand"},"shop/fashion":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"fashion"},"name":"Fashion Store"},"shop/florist":{"icon":"florist","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["flower"],"tags":{"shop":"florist"},"name":"Florist"},"shop/frame":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"frame"},"terms":["art*","paint*","photo*","frame"],"name":"Framing Shop"},"shop/funeral_directors":{"icon":"cemetery","fields":["operator","address","building_area","religion","denomination"],"geometry":["point","area"],"terms":["undertaker","memorial home"],"tags":{"shop":"funeral_directors"},"name":"Funeral Home"},"shop/furnace":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["oven","stove"],"tags":{"shop":"furnace"},"name":"Furnace Store"},"shop/furniture":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["chair","sofa","table"],"tags":{"shop":"furniture"},"name":"Furniture Store"},"shop/garden_centre":{"icon":"garden-center","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["landscape","mulch","shrub","tree"],"tags":{"shop":"garden_centre"},"name":"Garden Center"},"shop/gas":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["cng","lpg","natural gas","propane","refill","tank"],"tags":{"shop":"gas"},"name":"Bottled Gas Shop"},"shop/gift":{"icon":"gift","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["souvenir"],"tags":{"shop":"gift"},"name":"Gift Shop"},"shop/greengrocer":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["fruit","vegetable"],"tags":{"shop":"greengrocer"},"name":"Greengrocer"},"shop/hairdresser":{"icon":"hairdresser","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["barber"],"tags":{"shop":"hairdresser"},"name":"Hairdresser"},"shop/hardware":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"hardware"},"name":"Hardware Store"},"shop/hearing_aids":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"hearing_aids"},"name":"Hearing Aids Store"},"shop/herbalist":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"herbalist"},"name":"Herbalist"},"shop/hifi":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["stereo","video"],"tags":{"shop":"hifi"},"name":"Hifi Store"},"shop/houseware":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["home","household"],"tags":{"shop":"houseware"},"name":"Houseware Store"},"shop/interior_decoration":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"interior_decoration"},"name":"Interior Decoration Store"},"shop/jewelry":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["diamond","gem","ring"],"tags":{"shop":"jewelry"},"name":"Jeweler"},"shop/kiosk":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"kiosk"},"name":"News Kiosk"},"shop/kitchen":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"kitchen"},"name":"Kitchen Design Store"},"shop/laundry":{"icon":"laundry","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"laundry"},"name":"Laundry"},"shop/leather":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"leather"},"name":"Leather Store"},"shop/locksmith":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["key","lockpick"],"tags":{"shop":"locksmith"},"name":"Locksmith"},"shop/lottery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"lottery"},"name":"Lottery Shop"},"shop/mall":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["shopping"],"tags":{"shop":"mall"},"name":"Mall"},"shop/massage":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"massage"},"name":"Massage Shop"},"shop/medical_supply":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"medical_supply"},"name":"Medical Supply Store"},"shop/mobile_phone":{"icon":"mobile-phone","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"mobile_phone"},"name":"Mobile Phone Store"},"shop/money_lender":{"icon":"bank","fields":["operator","address","building_area","opening_hours","currency_multi"],"geometry":["point","area"],"tags":{"shop":"money_lender"},"name":"Money Lender"},"shop/motorcycle":{"icon":"scooter","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["bike"],"tags":{"shop":"motorcycle"},"name":"Motorcycle Dealership"},"shop/music":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["CD","vinyl"],"tags":{"shop":"music"},"name":"Music Store"},"shop/musical_instrument":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["guitar"],"tags":{"shop":"musical_instrument"},"name":"Musical Instrument Store"},"shop/newsagent":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"newsagent"},"name":"Newspaper/Magazine Shop"},"shop/nutrition_supplements":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"nutrition_supplements"},"name":"Nutrition Supplements Store"},"shop/optician":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["eye","glasses"],"tags":{"shop":"optician"},"name":"Optician"},"shop/organic":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"supermarket","organic":"only"},"name":"Organic Goods Store"},"shop/outdoor":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["camping","climbing","hiking"],"tags":{"shop":"outdoor"},"name":"Outdoors Store"},"shop/paint":{"icon":"water","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"paint"},"name":"Paint Store"},"shop/pastry":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"pastry"},"terms":["patisserie","cake shop","cakery"],"name":"Pastry Shop"},"shop/pawnbroker":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"pawnbroker"},"name":"Pawn Shop"},"shop/perfumery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"perfumery"},"name":"Perfume Store"},"shop/pet":{"icon":"dog-park","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["animal","cat","dog","fish","kitten","puppy","reptile"],"tags":{"shop":"pet"},"name":"Pet Store"},"shop/photo":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["camera","film"],"tags":{"shop":"photo"},"name":"Photography Store"},"shop/pyrotechnics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"pyrotechnics"},"name":"Fireworks Store"},"shop/radiotechnics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"radiotechnics"},"name":"Radio/Electronic Component Store"},"shop/religion":{"icon":"shop","fields":["operator","address","building_area","opening_hours","religion","denomination"],"geometry":["point","area"],"tags":{"shop":"religion"},"name":"Religious Store"},"shop/scuba_diving":{"icon":"swimming","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"scuba_diving"},"name":"Scuba Diving Shop"},"shop/seafood":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["fishmonger"],"tags":{"shop":"seafood"},"name":"Seafood Shop"},"shop/second_hand":{"icon":"shop","fields":["operator","address","building_area","opening_hours","second_hand"],"geometry":["point","area"],"terms":["secondhand","second hand","resale","thrift","used"],"tags":{"shop":"second_hand"},"name":"Consignment/Thrift Store"},"shop/shoes":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"shoes"},"name":"Shoe Store"},"shop/sports":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"sports"},"name":"Sporting Goods Store"},"shop/stationery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["card","paper"],"tags":{"shop":"stationery"},"name":"Stationery Store"},"shop/storage_rental":{"icon":"shop","fields":["operator","address","building","opening_hours"],"geometry":["point","area"],"tags":{"shop":"storage_rental"},"name":"Storage Rental"},"shop/supermarket":{"icon":"grocery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["grocery","store","shop"],"tags":{"shop":"supermarket"},"name":"Supermarket"},"shop/tailor":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["clothes","suit"],"tags":{"shop":"tailor"},"name":"Tailor"},"shop/tattoo":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tattoo"},"name":"Tattoo Parlor"},"shop/tea":{"icon":"teahouse","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tea"},"name":"Tea Store"},"shop/ticket":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"ticket"},"name":"Ticket Seller"},"shop/tobacco":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tobacco"},"name":"Tobacco Shop"},"shop/toys":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"toys"},"name":"Toy Store"},"shop/travel_agency":{"icon":"suitcase","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"travel_agency"},"name":"Travel Agency"},"shop/tyres":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tyres"},"name":"Tire Store"},"shop/vacuum_cleaner":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"vacuum_cleaner"},"name":"Vacuum Cleaner Store"},"shop/variety_store":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"variety_store"},"name":"Variety Store"},"shop/video_games":{"icon":"gaming","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"video_games"},"name":"Video Game Store"},"shop/video":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["DVD"],"tags":{"shop":"video"},"name":"Video Store"},"shop/watches":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"watches"},"name":"Watches Shop"},"shop/water_sports":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"water_sports"},"name":"Watersport/Swim Shop"},"shop/weapons":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ammo","gun","knife","knives"],"tags":{"shop":"weapons"},"name":"Weapon Shop"},"shop/window_blind":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"window_blind"},"name":"Window Blind Store"},"shop/wine":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"wine"},"name":"Wine Shop"},"tourism":{"icon":"attraction","fields":["tourism"],"geometry":["point","vertex","area"],"tags":{"tourism":"*"},"name":"Tourism"},"tourism/alpine_hut":{"icon":"lodging","fields":["operator","address","building_area","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"alpine_hut"},"name":"Alpine Hut"},"tourism/apartment":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"apartment"},"name":"Guest Apartment / Condo"},"tourism/aquarium":{"icon":"aquarium","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["fish","sea","water"],"tags":{"tourism":"aquarium"},"name":"Aquarium"},"tourism/artwork":{"icon":"art-gallery","fields":["artwork_type","artist"],"geometry":["point","vertex","area"],"tags":{"tourism":"artwork"},"terms":["mural","sculpture","statue"],"name":"Artwork"},"tourism/attraction":{"icon":"monument","fields":["operator","address"],"geometry":["point","vertex","area"],"tags":{"tourism":"attraction"},"name":"Tourist Attraction"},"tourism/camp_site":{"icon":"campsite","fields":["operator","address","capacity","fee","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["tent","rv"],"tags":{"tourism":"camp_site"},"name":"Campground"},"tourism/caravan_site":{"icon":"bus","fields":["operator","address","capacity","fee","sanitary_dump_station","power_supply","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["Motor Home","Camper"],"tags":{"tourism":"caravan_site"},"name":"RV Park"},"tourism/chalet":{"icon":"lodging","fields":["operator","address","building_area","smoking","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"chalet"},"name":"Chalet"},"tourism/gallery":{"icon":"art-gallery","fields":["artwork_type","operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["art*","exhibit*","paint*","photo*","sculpt*"],"tags":{"tourism":"gallery"},"name":"Art Gallery"},"tourism/guest_house":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"guest_house"},"terms":["B&B","Bed and Breakfast"],"name":"Guest House"},"tourism/hostel":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"hostel"},"name":"Hostel"},"tourism/hotel":{"icon":"lodging","fields":["operator","address","building_area","smoking","stars","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"hotel"},"name":"Hotel"},"tourism/information":{"icon":"information","fields":["information","operator","address","building_area"],"geometry":["point","vertex","area"],"tags":{"tourism":"information"},"name":"Information"},"tourism/information/board":{"icon":"information","fields":["operator","board_type"],"geometry":["point","vertex"],"tags":{"tourism":"information","information":"board"},"reference":{"key":"information","value":"board"},"name":"Information Board"},"tourism/information/guidepost":{"icon":"information","fields":["operator","ref"],"geometry":["point","vertex"],"tags":{"tourism":"information","information":"guidepost"},"reference":{"key":"information","value":"guidepost"},"name":"Guidepost"},"tourism/information/map":{"icon":"information","fields":["operator","map_type","map_size"],"geometry":["point","vertex"],"tags":{"tourism":"information","information":"map"},"reference":{"key":"information","value":"map"},"name":"Map"},"tourism/information/office":{"icon":"information","fields":["operator","address","building_area"],"geometry":["point","vertex","area"],"tags":{"tourism":"information","information":"office"},"reference":{"key":"information","value":"office"},"name":"Tourist Information Office"},"tourism/motel":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"motel"},"name":"Motel"},"tourism/museum":{"icon":"museum","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["art*","exhibit*","gallery","foundation","hall","institution","paint*","photo*","sculpt*"],"tags":{"tourism":"museum"},"name":"Museum"},"tourism/picnic_site":{"icon":"picnic-site","fields":["operator","address","smoking"],"geometry":["point","vertex","area"],"terms":["camp"],"tags":{"tourism":"picnic_site"},"name":"Picnic Site"},"tourism/theme_park":{"icon":"amusement-park","fields":["operator","address","opening_hours"],"geometry":["point","area"],"tags":{"tourism":"theme_park"},"name":"Theme Park"},"tourism/viewpoint":{"icon":"poi-binoculars","geometry":["point","vertex"],"tags":{"tourism":"viewpoint"},"name":"Viewpoint"},"tourism/zoo":{"icon":"zoo","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["animal"],"tags":{"tourism":"zoo"},"name":"Zoo"},"traffic_calming":{"icon":"poi-warning","fields":["traffic_calming","parallel_direction"],"geometry":["vertex","line"],"tags":{"traffic_calming":"*"},"terms":["bump","hump","slow","speed"],"name":"Traffic Calming"},"traffic_calming/bump":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["hump","speed","slow"],"tags":{"traffic_calming":"bump"},"name":"Speed Bump"},"traffic_calming/chicane":{"icon":"poi-warning","fields":["parallel_direction"],"geometry":["vertex","line"],"terms":["driveway link","speed","slow"],"tags":{"traffic_calming":"chicane"},"name":"Traffic Chicane"},"traffic_calming/choker":{"icon":"poi-warning","fields":["parallel_direction"],"geometry":["vertex","line"],"terms":["speed","slow"],"tags":{"traffic_calming":"choker"},"name":"Traffic Choker"},"traffic_calming/cushion":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["bump","hump","speed","slow"],"tags":{"traffic_calming":"cushion"},"name":"Speed Cushion"},"traffic_calming/dip":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["speed","slow"],"tags":{"traffic_calming":"dip"},"name":"Dip"},"traffic_calming/hump":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["bump","speed","slow"],"tags":{"traffic_calming":"hump"},"name":"Speed Hump"},"traffic_calming/island":{"icon":"poi-warning","geometry":["vertex"],"terms":["circle","roundabout","slow"],"tags":{"traffic_calming":"island"},"name":"Traffic Island"},"traffic_calming/rumble_strip":{"icon":"poi-warning","fields":["parallel_direction"],"geometry":["vertex","line"],"terms":["audible lines","sleeper lines","growlers"],"tags":{"traffic_calming":"rumble_strip"},"name":"Rumble Strip"},"traffic_calming/table":{"icon":"poi-warning","fields":["surface"],"geometry":["vertex","line"],"terms":["flat top","hump","speed","slow"],"tags":{"highway":"crossing","traffic_calming":"table"},"name":"Raised Pedestrian Crossing"},"type/multipolygon":{"geometry":["area","relation"],"tags":{"type":"multipolygon"},"removeTags":{},"name":"Multipolygon","icon":"multipolygon","searchable":false,"matchScore":0.1},"type/boundary":{"geometry":["relation"],"tags":{"type":"boundary"},"name":"Boundary","icon":"boundary","fields":["boundary"]},"type/boundary/administrative":{"icon":"boundary","fields":["admin_level"],"geometry":["relation"],"tags":{"type":"boundary","boundary":"administrative"},"reference":{"key":"boundary","value":"administrative"},"name":"Administrative Boundary"},"type/restriction":{"geometry":["relation"],"tags":{"type":"restriction"},"name":"Restriction","icon":"restriction","fields":["restriction","except"]},"type/restriction/no_left_turn":{"name":"No Left Turn","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_left_turn"},"fields":["except"],"icon":"restriction-no-left-turn"},"type/restriction/no_right_turn":{"name":"No Right Turn","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_right_turn"},"fields":["except"],"icon":"restriction-no-right-turn"},"type/restriction/no_straight_on":{"name":"No Straight On","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_straight_on"},"fields":["except"],"icon":"restriction-no-straight-on"},"type/restriction/no_u_turn":{"name":"No U-turn","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_u_turn"},"fields":["except"],"icon":"restriction-no-u-turn"},"type/restriction/only_left_turn":{"name":"Left Turn Only","geometry":["relation"],"tags":{"type":"restriction","restriction":"only_left_turn"},"fields":["except"],"icon":"restriction-only-left-turn"},"type/restriction/only_right_turn":{"name":"Right Turn Only","geometry":["relation"],"tags":{"type":"restriction","restriction":"only_right_turn"},"fields":["except"],"icon":"restriction-only-right-turn"},"type/restriction/only_straight_on":{"name":"No Turns","geometry":["relation"],"tags":{"type":"restriction","restriction":"only_straight_on"},"fields":["except"],"icon":"restriction-only-straight-on"},"type/route_master":{"geometry":["relation"],"tags":{"type":"route_master"},"name":"Route Master","icon":"route-master","fields":["route_master","ref","operator","network"]},"type/route":{"geometry":["relation"],"tags":{"type":"route"},"name":"Route","icon":"route","fields":["route","ref","operator","network"]},"type/route/bicycle":{"geometry":["relation"],"tags":{"type":"route","route":"bicycle"},"name":"Cycle Route","icon":"route-bicycle","fields":["ref","network_bicycle","cycle_network"]},"type/route/bus":{"geometry":["relation"],"tags":{"type":"route","route":"bus"},"name":"Bus Route","icon":"route-bus","fields":["ref","operator","network"]},"type/route/detour":{"geometry":["relation"],"tags":{"type":"route","route":"detour"},"name":"Detour Route","icon":"route-detour","fields":["ref"]},"type/route/ferry":{"geometry":["relation"],"tags":{"type":"route","route":"ferry"},"name":"Ferry Route","icon":"route-ferry","fields":["ref","operator","network"]},"type/route/foot":{"geometry":["relation"],"tags":{"type":"route","route":"foot"},"name":"Foot Route","icon":"route-foot","fields":["ref","operator","network_foot"]},"type/route/hiking":{"geometry":["relation"],"tags":{"type":"route","route":"hiking"},"name":"Hiking Route","icon":"route-foot","fields":["ref","operator","network_foot"]},"type/route/horse":{"geometry":["relation"],"tags":{"type":"route","route":"horse"},"name":"Riding Route","icon":"route-horse","fields":["ref","operator","network_horse"]},"type/route/pipeline":{"geometry":["relation"],"tags":{"type":"route","route":"pipeline"},"name":"Pipeline Route","icon":"route-pipeline","fields":["ref","operator"]},"type/route/power":{"geometry":["relation"],"tags":{"type":"route","route":"power"},"name":"Power Route","icon":"route-power","fields":["ref","operator"]},"type/route/road":{"geometry":["relation"],"tags":{"type":"route","route":"road"},"name":"Road Route","icon":"route-road","fields":["ref","network_road"]},"type/route/train":{"geometry":["relation"],"tags":{"type":"route","route":"train"},"name":"Train Route","icon":"route-train","fields":["ref","operator","network"]},"type/route/tram":{"geometry":["relation"],"tags":{"type":"route","route":"tram"},"name":"Tram Route","icon":"route-tram","fields":["ref","operator","network"]},"type/site":{"geometry":["relation"],"tags":{"type":"site"},"name":"Site","icon":"relation","fields":["site"]},"vertex":{"name":"Other","tags":{},"geometry":["vertex"],"matchScore":0.1},"waterway/boatyard":{"icon":"harbor","fields":["operator"],"geometry":["area","vertex","point"],"tags":{"waterway":"boatyard"},"name":"Boatyard"},"waterway/canal":{"icon":"waterway-canal","fields":["width"],"geometry":["line"],"tags":{"waterway":"canal"},"name":"Canal"},"waterway/dam":{"icon":"dam","geometry":["point","vertex","line","area"],"tags":{"waterway":"dam"},"name":"Dam"},"waterway/ditch":{"icon":"waterway-ditch","fields":["tunnel"],"geometry":["line"],"tags":{"waterway":"ditch"},"name":"Ditch"},"waterway/dock":{"icon":"harbor","fields":["dock","operator"],"geometry":["area","vertex","point"],"terms":["boat","ship","vessel","marine"],"tags":{"waterway":"dock"},"name":"Wet Dock / Dry Dock"},"waterway/drain":{"icon":"waterway-stream","fields":["tunnel"],"geometry":["line"],"tags":{"waterway":"drain"},"name":"Drain"},"waterway/fuel":{"icon":"fuel","fields":["operator","address","opening_hours","fuel_multi"],"geometry":["point","area"],"terms":["petrol","gas","diesel","boat"],"tags":{"waterway":"fuel"},"name":"Marine Fuel Station"},"waterway/river":{"icon":"waterway-river","fields":["tunnel","width"],"geometry":["line"],"terms":["beck","branch","brook","course","creek","estuary","rill","rivulet","run","runnel","stream","tributary","watercourse"],"tags":{"waterway":"river"},"name":"River"},"waterway/riverbank":{"icon":"water","geometry":["area"],"tags":{"waterway":"riverbank"},"name":"Riverbank"},"waterway/sanitary_dump_station":{"icon":"poi-storage-tank","fields":["operator","access_toilets","fee","water_point"],"geometry":["point","vertex","area"],"terms":["Boat","Watercraft","Sanitary","Dump Station","Pumpout","Pump out","Elsan","CDP","CTDP","Chemical Toilet"],"tags":{"waterway":"sanitary_dump_station"},"name":"Marine Toilet Disposal"},"waterway/stream":{"icon":"waterway-stream","fields":["tunnel","width"],"geometry":["line"],"terms":["beck","branch","brook","burn","course","creek","current","drift","flood","flow","freshet","race","rill","rindle","rivulet","run","runnel","rush","spate","spritz","surge","tide","torrent","tributary","watercourse"],"tags":{"waterway":"stream"},"name":"Stream"},"waterway/water_point":{"icon":"drinking-water","geometry":["area","vertex","point"],"tags":{"waterway":"water_point"},"name":"Marine Drinking Water"},"waterway/waterfall":{"icon":"water","fields":["height","width"],"geometry":["vertex"],"terms":["fall"],"tags":{"waterway":"waterfall"},"name":"Waterfall"},"waterway/weir":{"icon":"dam","geometry":["vertex","line"],"tags":{"waterway":"weir"},"name":"Weir"},"amenity/fuel/76":{"tags":{"name":"76","amenity":"fuel"},"name":"76","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Neste":{"tags":{"name":"Neste","amenity":"fuel"},"name":"Neste","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/BP":{"tags":{"name":"BP","amenity":"fuel"},"name":"BP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Shell":{"tags":{"name":"Shell","amenity":"fuel"},"name":"Shell","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Agip":{"tags":{"name":"Agip","amenity":"fuel"},"name":"Agip","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Migrol":{"tags":{"name":"Migrol","amenity":"fuel"},"name":"Migrol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Avia":{"tags":{"name":"Avia","amenity":"fuel"},"name":"Avia","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Texaco":{"tags":{"name":"Texaco","amenity":"fuel"},"name":"Texaco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Total":{"tags":{"name":"Total","amenity":"fuel"},"name":"Total","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Statoil":{"tags":{"name":"Statoil","amenity":"fuel"},"name":"Statoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Esso":{"tags":{"name":"Esso","amenity":"fuel"},"name":"Esso","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Jet":{"tags":{"name":"Jet","amenity":"fuel"},"name":"Jet","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Avanti":{"tags":{"name":"Avanti","amenity":"fuel"},"name":"Avanti","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OMV":{"tags":{"name":"OMV","amenity":"fuel"},"name":"OMV","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Aral":{"tags":{"name":"Aral","amenity":"fuel"},"name":"Aral","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/JET":{"tags":{"name":"JET","amenity":"fuel"},"name":"JET","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/United":{"tags":{"name":"United","amenity":"fuel"},"name":"United","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Mobil":{"tags":{"name":"Mobil","amenity":"fuel"},"name":"Mobil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Caltex":{"tags":{"name":"Caltex","amenity":"fuel"},"name":"Caltex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sunoco":{"tags":{"name":"Sunoco","amenity":"fuel"},"name":"Sunoco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Q8":{"tags":{"name":"Q8","amenity":"fuel"},"name":"Q8","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ARAL":{"tags":{"name":"ARAL","amenity":"fuel"},"name":"ARAL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CEPSA":{"tags":{"name":"CEPSA","amenity":"fuel"},"name":"CEPSA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/BFT":{"tags":{"name":"BFT","amenity":"fuel"},"name":"BFT","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petron":{"tags":{"name":"Petron","amenity":"fuel"},"name":"Petron","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Total Access":{"tags":{"name":"Total Access","amenity":"fuel"},"name":"Total Access","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Elf":{"tags":{"name":"Elf","amenity":"fuel"},"name":"Elf","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Station Service E. Leclerc":{"tags":{"name":"Station Service E. Leclerc","amenity":"fuel"},"name":"Station Service E. Leclerc","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Shell Express":{"tags":{"name":"Shell Express","amenity":"fuel"},"name":"Shell Express","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Hess":{"tags":{"name":"Hess","amenity":"fuel"},"name":"Hess","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Flying V":{"tags":{"name":"Flying V","amenity":"fuel"},"name":"Flying V","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/bft":{"tags":{"name":"bft","amenity":"fuel"},"name":"bft","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Gulf":{"tags":{"name":"Gulf","amenity":"fuel"},"name":"Gulf","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/PTT":{"tags":{"name":"PTT","amenity":"fuel"},"name":"PTT","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/St1":{"tags":{"name":"St1","amenity":"fuel"},"name":"St1","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Teboil":{"tags":{"name":"Teboil","amenity":"fuel"},"name":"Teboil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/HEM":{"tags":{"name":"HEM","amenity":"fuel"},"name":"HEM","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/GALP":{"tags":{"name":"GALP","amenity":"fuel"},"name":"GALP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OK":{"tags":{"name":"OK","amenity":"fuel"},"name":"OK","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ÖMV":{"tags":{"name":"ÖMV","amenity":"fuel"},"name":"ÖMV","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tinq":{"tags":{"name":"Tinq","amenity":"fuel"},"name":"Tinq","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OKQ8":{"tags":{"name":"OKQ8","amenity":"fuel"},"name":"OKQ8","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Repsol":{"tags":{"name":"Repsol","amenity":"fuel"},"name":"Repsol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Westfalen":{"tags":{"name":"Westfalen","amenity":"fuel"},"name":"Westfalen","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Esso Express":{"tags":{"name":"Esso Express","amenity":"fuel"},"name":"Esso Express","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tamoil":{"tags":{"name":"Tamoil","amenity":"fuel"},"name":"Tamoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Engen":{"tags":{"name":"Engen","amenity":"fuel"},"name":"Engen","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sasol":{"tags":{"name":"Sasol","amenity":"fuel"},"name":"Sasol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Topaz":{"tags":{"name":"Topaz","amenity":"fuel"},"name":"Topaz","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/LPG":{"tags":{"name":"LPG","amenity":"fuel"},"name":"LPG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Orlen":{"tags":{"name":"Orlen","amenity":"fuel"},"name":"Orlen","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Oilibya":{"tags":{"name":"Oilibya","amenity":"fuel"},"name":"Oilibya","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tango":{"tags":{"name":"Tango","amenity":"fuel"},"name":"Tango","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Star":{"tags":{"name":"Star","amenity":"fuel"},"name":"Star","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Петрол":{"tags":{"name":"Петрол","amenity":"fuel"},"name":"Петрол","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Cepsa":{"tags":{"name":"Cepsa","amenity":"fuel"},"name":"Cepsa","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OIL!":{"tags":{"name":"OIL!","amenity":"fuel"},"name":"OIL!","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Ultramar":{"tags":{"name":"Ultramar","amenity":"fuel"},"name":"Ultramar","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Irving":{"tags":{"name":"Irving","amenity":"fuel"},"name":"Irving","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Lukoil":{"tags":{"name":"Lukoil","amenity":"fuel"},"name":"Lukoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petro-Canada":{"tags":{"name":"Petro-Canada","amenity":"fuel"},"name":"Petro-Canada","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Agrola":{"tags":{"name":"Agrola","amenity":"fuel"},"name":"Agrola","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Husky":{"tags":{"name":"Husky","amenity":"fuel"},"name":"Husky","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Slovnaft":{"tags":{"name":"Slovnaft","amenity":"fuel"},"name":"Slovnaft","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sheetz":{"tags":{"name":"Sheetz","amenity":"fuel"},"name":"Sheetz","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Mol":{"tags":{"name":"Mol","amenity":"fuel"},"name":"Mol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petronas":{"tags":{"name":"Petronas","amenity":"fuel"},"name":"Petronas","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Газпромнефть":{"tags":{"name":"Газпромнефть","amenity":"fuel"},"name":"Газпромнефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Лукойл":{"tags":{"name":"Лукойл","amenity":"fuel"},"name":"Лукойл","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Elan":{"tags":{"name":"Elan","amenity":"fuel"},"name":"Elan","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Роснефть":{"tags":{"name":"Роснефть","amenity":"fuel"},"name":"Роснефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Turmöl":{"tags":{"name":"Turmöl","amenity":"fuel"},"name":"Turmöl","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Neste A24":{"tags":{"name":"Neste A24","amenity":"fuel"},"name":"Neste A24","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Marathon":{"tags":{"name":"Marathon","amenity":"fuel"},"name":"Marathon","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Valero":{"tags":{"name":"Valero","amenity":"fuel"},"name":"Valero","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Eni":{"tags":{"name":"Eni","amenity":"fuel"},"name":"Eni","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Chevron":{"tags":{"name":"Chevron","amenity":"fuel"},"name":"Chevron","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ТНК":{"tags":{"name":"ТНК","amenity":"fuel"},"name":"ТНК","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/REPSOL":{"tags":{"name":"REPSOL","amenity":"fuel"},"name":"REPSOL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/MOL":{"tags":{"name":"MOL","amenity":"fuel"},"name":"MOL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Bliska":{"tags":{"name":"Bliska","amenity":"fuel"},"name":"Bliska","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Api":{"tags":{"name":"Api","amenity":"fuel"},"name":"Api","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Arco":{"tags":{"name":"Arco","amenity":"fuel"},"name":"Arco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Pemex":{"tags":{"name":"Pemex","amenity":"fuel"},"name":"Pemex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Exxon":{"tags":{"name":"Exxon","amenity":"fuel"},"name":"Exxon","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Coles Express":{"tags":{"name":"Coles Express","amenity":"fuel"},"name":"Coles Express","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petrom":{"tags":{"name":"Petrom","amenity":"fuel"},"name":"Petrom","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/PETRONOR":{"tags":{"name":"PETRONOR","amenity":"fuel"},"name":"PETRONOR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Rompetrol":{"tags":{"name":"Rompetrol","amenity":"fuel"},"name":"Rompetrol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Lotos":{"tags":{"name":"Lotos","amenity":"fuel"},"name":"Lotos","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ОМВ":{"tags":{"name":"ОМВ","amenity":"fuel"},"name":"ОМВ","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/BR":{"tags":{"name":"BR","amenity":"fuel"},"name":"BR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Copec":{"tags":{"name":"Copec","amenity":"fuel"},"name":"Copec","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petrobras":{"tags":{"name":"Petrobras","amenity":"fuel"},"name":"Petrobras","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Liberty":{"tags":{"name":"Liberty","amenity":"fuel"},"name":"Liberty","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/IP":{"tags":{"name":"IP","amenity":"fuel"},"name":"IP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Erg":{"tags":{"name":"Erg","amenity":"fuel"},"name":"Erg","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Eneos":{"tags":{"name":"Eneos","amenity":"fuel"},"name":"Eneos","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Citgo":{"tags":{"name":"Citgo","amenity":"fuel"},"name":"Citgo","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Metano":{"tags":{"name":"Metano","amenity":"fuel"},"name":"Metano","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Сургутнефтегаз":{"tags":{"name":"Сургутнефтегаз","amenity":"fuel"},"name":"Сургутнефтегаз","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/EKO":{"tags":{"name":"EKO","amenity":"fuel"},"name":"EKO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Eko":{"tags":{"name":"Eko","amenity":"fuel"},"name":"Eko","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Indipend.":{"tags":{"name":"Indipend.","amenity":"fuel"},"name":"Indipend.","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/IES":{"tags":{"name":"IES","amenity":"fuel"},"name":"IES","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/TotalErg":{"tags":{"name":"TotalErg","amenity":"fuel"},"name":"TotalErg","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Cenex":{"tags":{"name":"Cenex","amenity":"fuel"},"name":"Cenex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ПТК":{"tags":{"name":"ПТК","amenity":"fuel"},"name":"ПТК","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/HP":{"tags":{"name":"HP","amenity":"fuel"},"name":"HP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Phillips 66":{"tags":{"name":"Phillips 66","amenity":"fuel"},"name":"Phillips 66","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CARREFOUR":{"tags":{"name":"CARREFOUR","amenity":"fuel"},"name":"CARREFOUR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ERG":{"tags":{"name":"ERG","amenity":"fuel"},"name":"ERG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Speedway":{"tags":{"name":"Speedway","amenity":"fuel"},"name":"Speedway","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Benzina":{"tags":{"name":"Benzina","amenity":"fuel"},"name":"Benzina","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Татнефть":{"tags":{"name":"Татнефть","amenity":"fuel"},"name":"Татнефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Terpel":{"tags":{"name":"Terpel","amenity":"fuel"},"name":"Terpel","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/WOG":{"tags":{"name":"WOG","amenity":"fuel"},"name":"WOG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Seaoil":{"tags":{"name":"Seaoil","amenity":"fuel"},"name":"Seaoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/АЗС":{"tags":{"name":"АЗС","amenity":"fuel"},"name":"АЗС","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Kwik Trip":{"tags":{"name":"Kwik Trip","amenity":"fuel"},"name":"Kwik Trip","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Pertamina":{"tags":{"name":"Pertamina","amenity":"fuel"},"name":"Pertamina","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/COSMO":{"tags":{"name":"COSMO","amenity":"fuel"},"name":"COSMO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Z":{"tags":{"name":"Z","amenity":"fuel"},"name":"Z","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Indian Oil":{"tags":{"name":"Indian Oil","amenity":"fuel"},"name":"Indian Oil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/АГЗС":{"tags":{"name":"АГЗС","amenity":"fuel"},"name":"АГЗС","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/INA":{"tags":{"name":"INA","amenity":"fuel"},"name":"INA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/JOMO":{"tags":{"name":"JOMO","amenity":"fuel"},"name":"JOMO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Holiday":{"tags":{"name":"Holiday","amenity":"fuel"},"name":"Holiday","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/YPF":{"tags":{"name":"YPF","amenity":"fuel"},"name":"YPF","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/IDEMITSU":{"tags":{"name":"IDEMITSU","amenity":"fuel"},"name":"IDEMITSU","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ENEOS":{"tags":{"name":"ENEOS","amenity":"fuel"},"name":"ENEOS","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Bharat Petroleum":{"tags":{"name":"Bharat Petroleum","amenity":"fuel"},"name":"Bharat Petroleum","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CAMPSA":{"tags":{"name":"CAMPSA","amenity":"fuel"},"name":"CAMPSA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Casey's General Store":{"tags":{"name":"Casey's General Store","amenity":"fuel"},"name":"Casey's General Store","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Башнефть":{"tags":{"name":"Башнефть","amenity":"fuel"},"name":"Башнефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Kangaroo":{"tags":{"name":"Kangaroo","amenity":"fuel"},"name":"Kangaroo","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/コスモ石油 (COSMO)":{"tags":{"name":"コスモ石油 (COSMO)","amenity":"fuel"},"name":"コスモ石油 (COSMO)","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/MEROIL":{"tags":{"name":"MEROIL","amenity":"fuel"},"name":"MEROIL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/1-2-3":{"tags":{"name":"1-2-3","amenity":"fuel"},"name":"1-2-3","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/出光":{"tags":{"name":"出光","name:en":"IDEMITSU","amenity":"fuel"},"name":"出光","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/НК Альянс":{"tags":{"name":"НК Альянс","amenity":"fuel"},"name":"НК Альянс","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sinclair":{"tags":{"name":"Sinclair","amenity":"fuel"},"name":"Sinclair","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Conoco":{"tags":{"name":"Conoco","amenity":"fuel"},"name":"Conoco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/SPBU":{"tags":{"name":"SPBU","amenity":"fuel"},"name":"SPBU","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Макпетрол":{"tags":{"name":"Макпетрол","amenity":"fuel"},"name":"Макпетрол","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto Ipiranga":{"tags":{"name":"Posto Ipiranga","amenity":"fuel"},"name":"Posto Ipiranga","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto Shell":{"tags":{"name":"Posto Shell","amenity":"fuel"},"name":"Posto Shell","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Phoenix":{"tags":{"name":"Phoenix","amenity":"fuel"},"name":"Phoenix","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Ipiranga":{"tags":{"name":"Ipiranga","amenity":"fuel"},"name":"Ipiranga","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OKKO":{"tags":{"name":"OKKO","amenity":"fuel"},"name":"OKKO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ОККО":{"tags":{"name":"ОККО","amenity":"fuel"},"name":"ОККО","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/บางจาก":{"tags":{"name":"บางจาก","amenity":"fuel"},"name":"บางจาก","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/QuikTrip":{"tags":{"name":"QuikTrip","amenity":"fuel"},"name":"QuikTrip","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto BR":{"tags":{"name":"Posto BR","amenity":"fuel"},"name":"Posto BR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ป ต ท":{"tags":{"name":"ป ต ท","amenity":"fuel"},"name":"ป ต ท","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ปตท":{"tags":{"name":"ปตท","amenity":"fuel"},"name":"ปตท","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ANP":{"tags":{"name":"ANP","amenity":"fuel"},"name":"ANP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Kum & Go":{"tags":{"name":"Kum & Go","amenity":"fuel"},"name":"Kum & Go","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petrolimex":{"tags":{"name":"Petrolimex","amenity":"fuel"},"name":"Petrolimex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sokimex":{"tags":{"name":"Sokimex","amenity":"fuel"},"name":"Sokimex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tela":{"tags":{"name":"Tela","amenity":"fuel"},"name":"Tela","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto":{"tags":{"name":"Posto","amenity":"fuel"},"name":"Posto","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Укрнафта":{"tags":{"name":"Укрнафта","amenity":"fuel"},"name":"Укрнафта","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Татнефтепродукт":{"tags":{"name":"Татнефтепродукт","amenity":"fuel"},"name":"Татнефтепродукт","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Afriquia":{"tags":{"name":"Afriquia","amenity":"fuel"},"name":"Afriquia","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Murphy USA":{"tags":{"name":"Murphy USA","amenity":"fuel"},"name":"Murphy USA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/昭和シェル (Showa-shell)":{"tags":{"name":"昭和シェル (Showa-shell)","amenity":"fuel"},"name":"昭和シェル (Showa-shell)","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/エネオス":{"tags":{"name":"エネオス","amenity":"fuel"},"name":"エネオス","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CNG":{"tags":{"name":"CNG","amenity":"fuel"},"name":"CNG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/pub/Kings Arms":{"tags":{"name":"Kings Arms","amenity":"pub"},"name":"Kings Arms","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Ship":{"tags":{"name":"The Ship","amenity":"pub"},"name":"The Ship","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The White Horse":{"tags":{"name":"The White Horse","amenity":"pub"},"name":"The White Horse","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The White Hart":{"tags":{"name":"The White Hart","amenity":"pub"},"name":"The White Hart","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Royal Oak":{"tags":{"name":"Royal Oak","amenity":"pub"},"name":"Royal Oak","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Red Lion":{"tags":{"name":"The Red Lion","amenity":"pub"},"name":"The Red Lion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Kings Arms":{"tags":{"name":"The Kings Arms","amenity":"pub"},"name":"The Kings Arms","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Star":{"tags":{"name":"The Star","amenity":"pub"},"name":"The Star","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Anchor":{"tags":{"name":"The Anchor","amenity":"pub"},"name":"The Anchor","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Cross Keys":{"tags":{"name":"The Cross Keys","amenity":"pub"},"name":"The Cross Keys","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Wheatsheaf":{"tags":{"name":"The Wheatsheaf","amenity":"pub"},"name":"The Wheatsheaf","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Crown Inn":{"tags":{"name":"The Crown Inn","amenity":"pub"},"name":"The Crown Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Kings Head":{"tags":{"name":"The Kings Head","amenity":"pub"},"name":"The Kings Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Castle":{"tags":{"name":"The Castle","amenity":"pub"},"name":"The Castle","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Railway":{"tags":{"name":"The Railway","amenity":"pub"},"name":"The Railway","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The White Lion":{"tags":{"name":"The White Lion","amenity":"pub"},"name":"The White Lion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Bell":{"tags":{"name":"The Bell","amenity":"pub"},"name":"The Bell","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Bull":{"tags":{"name":"The Bull","amenity":"pub"},"name":"The Bull","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Plough":{"tags":{"name":"The Plough","amenity":"pub"},"name":"The Plough","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The George":{"tags":{"name":"The George","amenity":"pub"},"name":"The George","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Royal Oak":{"tags":{"name":"The Royal Oak","amenity":"pub"},"name":"The Royal Oak","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Fox":{"tags":{"name":"The Fox","amenity":"pub"},"name":"The Fox","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Prince of Wales":{"tags":{"name":"Prince of Wales","amenity":"pub"},"name":"Prince of Wales","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Rising Sun":{"tags":{"name":"The Rising Sun","amenity":"pub"},"name":"The Rising Sun","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Prince of Wales":{"tags":{"name":"The Prince of Wales","amenity":"pub"},"name":"The Prince of Wales","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Crown":{"tags":{"name":"The Crown","amenity":"pub"},"name":"The Crown","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Chequers":{"tags":{"name":"The Chequers","amenity":"pub"},"name":"The Chequers","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Swan":{"tags":{"name":"The Swan","amenity":"pub"},"name":"The Swan","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Rose and Crown":{"tags":{"name":"Rose and Crown","amenity":"pub"},"name":"Rose and Crown","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Victoria":{"tags":{"name":"The Victoria","amenity":"pub"},"name":"The Victoria","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/New Inn":{"tags":{"name":"New Inn","amenity":"pub"},"name":"New Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Royal Hotel":{"tags":{"name":"Royal Hotel","amenity":"pub"},"name":"Royal Hotel","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Red Lion":{"tags":{"name":"Red Lion","amenity":"pub"},"name":"Red Lion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Cross Keys":{"tags":{"name":"Cross Keys","amenity":"pub"},"name":"Cross Keys","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Greyhound":{"tags":{"name":"The Greyhound","amenity":"pub"},"name":"The Greyhound","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Black Horse":{"tags":{"name":"The Black Horse","amenity":"pub"},"name":"The Black Horse","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The New Inn":{"tags":{"name":"The New Inn","amenity":"pub"},"name":"The New Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Kings Head":{"tags":{"name":"Kings Head","amenity":"pub"},"name":"Kings Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Albion":{"tags":{"name":"The Albion","amenity":"pub"},"name":"The Albion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Angel":{"tags":{"name":"The Angel","amenity":"pub"},"name":"The Angel","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Queens Head":{"tags":{"name":"The Queens Head","amenity":"pub"},"name":"The Queens Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Ship Inn":{"tags":{"name":"The Ship Inn","amenity":"pub"},"name":"The Ship Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Rose & Crown":{"tags":{"name":"Rose & Crown","amenity":"pub"},"name":"Rose & Crown","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Queens Head":{"tags":{"name":"Queens Head","amenity":"pub"},"name":"Queens Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Irish Pub":{"tags":{"name":"Irish Pub","amenity":"pub"},"name":"Irish Pub","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Quick":{"tags":{"name":"Quick","amenity":"fast_food"},"name":"Quick","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/McDonald's":{"tags":{"name":"McDonald's","cuisine":"burger","amenity":"fast_food"},"name":"McDonald's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Subway":{"tags":{"name":"Subway","cuisine":"sandwich","amenity":"fast_food"},"name":"Subway","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Burger King":{"tags":{"name":"Burger King","cuisine":"burger","amenity":"fast_food"},"name":"Burger King","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Ali Baba":{"tags":{"name":"Ali Baba","amenity":"fast_food"},"name":"Ali Baba","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hungry Jacks":{"tags":{"name":"Hungry Jacks","cuisine":"burger","amenity":"fast_food"},"name":"Hungry Jacks","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Red Rooster":{"tags":{"name":"Red Rooster","amenity":"fast_food"},"name":"Red Rooster","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/KFC":{"tags":{"name":"KFC","cuisine":"chicken","amenity":"fast_food"},"name":"KFC","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Domino's Pizza":{"tags":{"name":"Domino's Pizza","cuisine":"pizza","amenity":"fast_food"},"name":"Domino's Pizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Chowking":{"tags":{"name":"Chowking","amenity":"fast_food"},"name":"Chowking","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jollibee":{"tags":{"name":"Jollibee","amenity":"fast_food"},"name":"Jollibee","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hesburger":{"tags":{"name":"Hesburger","amenity":"fast_food"},"name":"Hesburger","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/肯德基":{"tags":{"name":"肯德基","amenity":"fast_food"},"name":"肯德基","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Wendy's":{"tags":{"name":"Wendy's","cuisine":"burger","amenity":"fast_food"},"name":"Wendy's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Tim Hortons":{"tags":{"name":"Tim Hortons","amenity":"fast_food"},"name":"Tim Hortons","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Steers":{"tags":{"name":"Steers","amenity":"fast_food"},"name":"Steers","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hardee's":{"tags":{"name":"Hardee's","cuisine":"burger","amenity":"fast_food"},"name":"Hardee's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Arby's":{"tags":{"name":"Arby's","amenity":"fast_food"},"name":"Arby's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/A&W":{"tags":{"name":"A&W","amenity":"fast_food"},"name":"A&W","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Dairy Queen":{"tags":{"name":"Dairy Queen","amenity":"fast_food"},"name":"Dairy Queen","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hallo Pizza":{"tags":{"name":"Hallo Pizza","amenity":"fast_food"},"name":"Hallo Pizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Fish & Chips":{"tags":{"name":"Fish & Chips","amenity":"fast_food"},"name":"Fish & Chips","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Harvey's":{"tags":{"name":"Harvey's","amenity":"fast_food"},"name":"Harvey's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/麥當勞":{"tags":{"name":"麥當勞","amenity":"fast_food"},"name":"麥當勞","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Pizza Pizza":{"tags":{"name":"Pizza Pizza","amenity":"fast_food"},"name":"Pizza Pizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Kotipizza":{"tags":{"name":"Kotipizza","amenity":"fast_food"},"name":"Kotipizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jack in the Box":{"tags":{"name":"Jack in the Box","cuisine":"burger","amenity":"fast_food"},"name":"Jack in the Box","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Istanbul":{"tags":{"name":"Istanbul","amenity":"fast_food"},"name":"Istanbul","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Kochlöffel":{"tags":{"name":"Kochlöffel","amenity":"fast_food"},"name":"Kochlöffel","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Döner":{"tags":{"name":"Döner","amenity":"fast_food"},"name":"Döner","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Telepizza":{"tags":{"name":"Telepizza","amenity":"fast_food"},"name":"Telepizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Sibylla":{"tags":{"name":"Sibylla","amenity":"fast_food"},"name":"Sibylla","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Carl's Jr.":{"tags":{"name":"Carl's Jr.","cuisine":"burger","amenity":"fast_food"},"name":"Carl's Jr.","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Quiznos":{"tags":{"name":"Quiznos","cuisine":"sandwich","amenity":"fast_food"},"name":"Quiznos","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Wimpy":{"tags":{"name":"Wimpy","amenity":"fast_food"},"name":"Wimpy","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Sonic":{"tags":{"name":"Sonic","cuisine":"burger","amenity":"fast_food"},"name":"Sonic","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Taco Bell":{"tags":{"name":"Taco Bell","cuisine":"mexican","amenity":"fast_food"},"name":"Taco Bell","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Pizza Nova":{"tags":{"name":"Pizza Nova","amenity":"fast_food"},"name":"Pizza Nova","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Papa John's":{"tags":{"name":"Papa John's","cuisine":"pizza","amenity":"fast_food"},"name":"Papa John's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Nordsee":{"tags":{"name":"Nordsee","amenity":"fast_food"},"name":"Nordsee","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Mr. Sub":{"tags":{"name":"Mr. Sub","amenity":"fast_food"},"name":"Mr. Sub","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Макдоналдс":{"tags":{"name":"Макдоналдс","name:en":"McDonald's","amenity":"fast_food"},"name":"Макдоналдс","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Asia Imbiss":{"tags":{"name":"Asia Imbiss","amenity":"fast_food"},"name":"Asia Imbiss","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Chipotle":{"tags":{"name":"Chipotle","cuisine":"mexican","amenity":"fast_food"},"name":"Chipotle","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/マクドナルド":{"tags":{"name":"マクドナルド","name:en":"McDonald's","cuisine":"burger","amenity":"fast_food"},"name":"マクドナルド","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/In-N-Out Burger":{"tags":{"name":"In-N-Out Burger","amenity":"fast_food"},"name":"In-N-Out Burger","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jimmy John's":{"tags":{"name":"Jimmy John's","amenity":"fast_food"},"name":"Jimmy John's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jamba Juice":{"tags":{"name":"Jamba Juice","amenity":"fast_food"},"name":"Jamba Juice","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Робин Сдобин":{"tags":{"name":"Робин Сдобин","amenity":"fast_food"},"name":"Робин Сдобин","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Baskin Robbins":{"tags":{"name":"Baskin Robbins","amenity":"fast_food"},"name":"Baskin Robbins","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/ケンタッキーフライドチキン":{"tags":{"name":"ケンタッキーフライドチキン","name:en":"KFC","cuisine":"chicken","amenity":"fast_food"},"name":"ケンタッキーフライドチキン","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/吉野家":{"tags":{"name":"吉野家","amenity":"fast_food"},"name":"吉野家","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Taco Time":{"tags":{"name":"Taco Time","amenity":"fast_food"},"name":"Taco Time","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/松屋":{"tags":{"name":"松屋","name:en":"Matsuya","amenity":"fast_food"},"name":"松屋","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Little Caesars":{"tags":{"name":"Little Caesars","amenity":"fast_food"},"name":"Little Caesars","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/El Pollo Loco":{"tags":{"name":"El Pollo Loco","amenity":"fast_food"},"name":"El Pollo Loco","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Del Taco":{"tags":{"name":"Del Taco","amenity":"fast_food"},"name":"Del Taco","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/White Castle":{"tags":{"name":"White Castle","amenity":"fast_food"},"name":"White Castle","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Boston Market":{"tags":{"name":"Boston Market","amenity":"fast_food"},"name":"Boston Market","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Chick-fil-A":{"tags":{"name":"Chick-fil-A","cuisine":"chicken","amenity":"fast_food"},"name":"Chick-fil-A","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Panda Express":{"tags":{"name":"Panda Express","cuisine":"chinese","amenity":"fast_food"},"name":"Panda Express","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Whataburger":{"tags":{"name":"Whataburger","amenity":"fast_food"},"name":"Whataburger","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Taco John's":{"tags":{"name":"Taco John's","amenity":"fast_food"},"name":"Taco John's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Теремок":{"tags":{"name":"Теремок","amenity":"fast_food"},"name":"Теремок","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Culver's":{"tags":{"name":"Culver's","amenity":"fast_food"},"name":"Culver's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Five Guys":{"tags":{"name":"Five Guys","amenity":"fast_food"},"name":"Five Guys","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Church's Chicken":{"tags":{"name":"Church's Chicken","amenity":"fast_food"},"name":"Church's Chicken","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Popeye's":{"tags":{"name":"Popeye's","cuisine":"chicken","amenity":"fast_food"},"name":"Popeye's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Long John Silver's":{"tags":{"name":"Long John Silver's","amenity":"fast_food"},"name":"Long John Silver's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Pollo Campero":{"tags":{"name":"Pollo Campero","amenity":"fast_food"},"name":"Pollo Campero","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Zaxby's":{"tags":{"name":"Zaxby's","amenity":"fast_food"},"name":"Zaxby's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/すき家":{"tags":{"name":"すき家","name:en":"SUKIYA","amenity":"fast_food"},"name":"すき家","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/モスバーガー":{"tags":{"name":"モスバーガー","name:en":"MOS BURGER","amenity":"fast_food"},"name":"モスバーガー","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Русский Аппетит":{"tags":{"name":"Русский Аппетит","amenity":"fast_food"},"name":"Русский Аппетит","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/なか卯":{"tags":{"name":"なか卯","amenity":"fast_food"},"name":"なか卯","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Pizza Hut":{"tags":{"name":"Pizza Hut","cuisine":"pizza","amenity":"restaurant"},"name":"Pizza Hut","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Little Chef":{"tags":{"name":"Little Chef","amenity":"restaurant"},"name":"Little Chef","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Adler":{"tags":{"name":"Adler","amenity":"restaurant"},"name":"Adler","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Krone":{"tags":{"name":"Zur Krone","amenity":"restaurant"},"name":"Zur Krone","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Deutsches Haus":{"tags":{"name":"Deutsches Haus","amenity":"restaurant"},"name":"Deutsches Haus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Krone":{"tags":{"name":"Krone","amenity":"restaurant"},"name":"Krone","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Akropolis":{"tags":{"name":"Akropolis","amenity":"restaurant"},"name":"Akropolis","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Schützenhaus":{"tags":{"name":"Schützenhaus","amenity":"restaurant"},"name":"Schützenhaus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kreuz":{"tags":{"name":"Kreuz","amenity":"restaurant"},"name":"Kreuz","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Waldschänke":{"tags":{"name":"Waldschänke","amenity":"restaurant"},"name":"Waldschänke","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Piazza":{"tags":{"name":"La Piazza","amenity":"restaurant"},"name":"La Piazza","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Lamm":{"tags":{"name":"Lamm","amenity":"restaurant"},"name":"Lamm","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Sonne":{"tags":{"name":"Zur Sonne","amenity":"restaurant"},"name":"Zur Sonne","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Linde":{"tags":{"name":"Zur Linde","amenity":"restaurant"},"name":"Zur Linde","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Poseidon":{"tags":{"name":"Poseidon","amenity":"restaurant"},"name":"Poseidon","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Shanghai":{"tags":{"name":"Shanghai","amenity":"restaurant"},"name":"Shanghai","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Red Lobster":{"tags":{"name":"Red Lobster","amenity":"restaurant"},"name":"Red Lobster","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zum Löwen":{"tags":{"name":"Zum Löwen","amenity":"restaurant"},"name":"Zum Löwen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Swiss Chalet":{"tags":{"name":"Swiss Chalet","amenity":"restaurant"},"name":"Swiss Chalet","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Olympia":{"tags":{"name":"Olympia","amenity":"restaurant"},"name":"Olympia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Wagamama":{"tags":{"name":"Wagamama","amenity":"restaurant"},"name":"Wagamama","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Frankie & Benny's":{"tags":{"name":"Frankie & Benny's","amenity":"restaurant"},"name":"Frankie & Benny's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hooters":{"tags":{"name":"Hooters","amenity":"restaurant"},"name":"Hooters","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sternen":{"tags":{"name":"Sternen","amenity":"restaurant"},"name":"Sternen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hirschen":{"tags":{"name":"Hirschen","amenity":"restaurant"},"name":"Hirschen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Denny's":{"tags":{"name":"Denny's","amenity":"restaurant"},"name":"Denny's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Athen":{"tags":{"name":"Athen","amenity":"restaurant"},"name":"Athen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sonne":{"tags":{"name":"Sonne","amenity":"restaurant"},"name":"Sonne","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hirsch":{"tags":{"name":"Hirsch","amenity":"restaurant"},"name":"Hirsch","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Ratskeller":{"tags":{"name":"Ratskeller","amenity":"restaurant"},"name":"Ratskeller","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Cantina":{"tags":{"name":"La Cantina","amenity":"restaurant"},"name":"La Cantina","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Gasthaus Krone":{"tags":{"name":"Gasthaus Krone","amenity":"restaurant"},"name":"Gasthaus Krone","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/El Greco":{"tags":{"name":"El Greco","amenity":"restaurant"},"name":"El Greco","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Gasthof zur Post":{"tags":{"name":"Gasthof zur Post","amenity":"restaurant"},"name":"Gasthof zur Post","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Nando's":{"tags":{"name":"Nando's","amenity":"restaurant"},"name":"Nando's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Löwen":{"tags":{"name":"Löwen","amenity":"restaurant"},"name":"Löwen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Pataterie":{"tags":{"name":"La Pataterie","amenity":"restaurant"},"name":"La Pataterie","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bella Napoli":{"tags":{"name":"Bella Napoli","amenity":"restaurant"},"name":"Bella Napoli","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Pizza Express":{"tags":{"name":"Pizza Express","amenity":"restaurant"},"name":"Pizza Express","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mandarin":{"tags":{"name":"Mandarin","amenity":"restaurant"},"name":"Mandarin","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hong Kong":{"tags":{"name":"Hong Kong","amenity":"restaurant"},"name":"Hong Kong","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zizzi":{"tags":{"name":"Zizzi","amenity":"restaurant"},"name":"Zizzi","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Cracker Barrel":{"tags":{"name":"Cracker Barrel","amenity":"restaurant"},"name":"Cracker Barrel","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Rhodos":{"tags":{"name":"Rhodos","amenity":"restaurant"},"name":"Rhodos","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Lindenhof":{"tags":{"name":"Lindenhof","amenity":"restaurant"},"name":"Lindenhof","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Milano":{"tags":{"name":"Milano","amenity":"restaurant"},"name":"Milano","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Dolce Vita":{"tags":{"name":"Dolce Vita","amenity":"restaurant"},"name":"Dolce Vita","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kirchenwirt":{"tags":{"name":"Kirchenwirt","amenity":"restaurant"},"name":"Kirchenwirt","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kantine":{"tags":{"name":"Kantine","amenity":"restaurant"},"name":"Kantine","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Ochsen":{"tags":{"name":"Ochsen","amenity":"restaurant"},"name":"Ochsen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Spur":{"tags":{"name":"Spur","amenity":"restaurant"},"name":"Spur","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mykonos":{"tags":{"name":"Mykonos","amenity":"restaurant"},"name":"Mykonos","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Lotus":{"tags":{"name":"Lotus","amenity":"restaurant"},"name":"Lotus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Applebee's":{"tags":{"name":"Applebee's","amenity":"restaurant"},"name":"Applebee's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Flunch":{"tags":{"name":"Flunch","amenity":"restaurant"},"name":"Flunch","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Post":{"tags":{"name":"Zur Post","amenity":"restaurant"},"name":"Zur Post","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/China Town":{"tags":{"name":"China Town","amenity":"restaurant"},"name":"China Town","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Dolce Vita":{"tags":{"name":"La Dolce Vita","amenity":"restaurant"},"name":"La Dolce Vita","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Waffle House":{"tags":{"name":"Waffle House","amenity":"restaurant"},"name":"Waffle House","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Delphi":{"tags":{"name":"Delphi","amenity":"restaurant"},"name":"Delphi","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Linde":{"tags":{"name":"Linde","amenity":"restaurant"},"name":"Linde","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Outback Steakhouse":{"tags":{"name":"Outback Steakhouse","amenity":"restaurant"},"name":"Outback Steakhouse","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Dionysos":{"tags":{"name":"Dionysos","amenity":"restaurant"},"name":"Dionysos","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kelsey's":{"tags":{"name":"Kelsey's","amenity":"restaurant"},"name":"Kelsey's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Boston Pizza":{"tags":{"name":"Boston Pizza","amenity":"restaurant"},"name":"Boston Pizza","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bella Italia":{"tags":{"name":"Bella Italia","amenity":"restaurant"},"name":"Bella Italia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sizzler":{"tags":{"name":"Sizzler","amenity":"restaurant"},"name":"Sizzler","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Grüner Baum":{"tags":{"name":"Grüner Baum","amenity":"restaurant"},"name":"Grüner Baum","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Taj Mahal":{"tags":{"name":"Taj Mahal","amenity":"restaurant"},"name":"Taj Mahal","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Rössli":{"tags":{"name":"Rössli","amenity":"restaurant"},"name":"Rössli","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Traube":{"tags":{"name":"Traube","amenity":"restaurant"},"name":"Traube","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Adria":{"tags":{"name":"Adria","amenity":"restaurant"},"name":"Adria","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Red Robin":{"tags":{"name":"Red Robin","amenity":"restaurant"},"name":"Red Robin","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Roma":{"tags":{"name":"Roma","amenity":"restaurant"},"name":"Roma","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/San Marco":{"tags":{"name":"San Marco","amenity":"restaurant"},"name":"San Marco","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hellas":{"tags":{"name":"Hellas","amenity":"restaurant"},"name":"Hellas","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Perla":{"tags":{"name":"La Perla","amenity":"restaurant"},"name":"La Perla","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Vips":{"tags":{"name":"Vips","amenity":"restaurant"},"name":"Vips","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Panera Bread":{"tags":{"name":"Panera Bread","amenity":"restaurant"},"name":"Panera Bread","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Da Vinci":{"tags":{"name":"Da Vinci","amenity":"restaurant"},"name":"Da Vinci","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hippopotamus":{"tags":{"name":"Hippopotamus","amenity":"restaurant"},"name":"Hippopotamus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Prezzo":{"tags":{"name":"Prezzo","amenity":"restaurant"},"name":"Prezzo","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Courtepaille":{"tags":{"name":"Courtepaille","amenity":"restaurant"},"name":"Courtepaille","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hard Rock Cafe":{"tags":{"name":"Hard Rock Cafe","amenity":"restaurant"},"name":"Hard Rock Cafe","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Panorama":{"tags":{"name":"Panorama","amenity":"restaurant"},"name":"Panorama","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/デニーズ":{"tags":{"name":"デニーズ","amenity":"restaurant"},"name":"デニーズ","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sportheim":{"tags":{"name":"Sportheim","amenity":"restaurant"},"name":"Sportheim","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/餃子の王将":{"tags":{"name":"餃子の王将","amenity":"restaurant"},"name":"餃子の王将","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bären":{"tags":{"name":"Bären","amenity":"restaurant"},"name":"Bären","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Alte Post":{"tags":{"name":"Alte Post","amenity":"restaurant"},"name":"Alte Post","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Pizzeria Roma":{"tags":{"name":"Pizzeria Roma","amenity":"restaurant"},"name":"Pizzeria Roma","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/China Garden":{"tags":{"name":"China Garden","amenity":"restaurant"},"name":"China Garden","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Vapiano":{"tags":{"name":"Vapiano","amenity":"restaurant"},"name":"Vapiano","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mamma Mia":{"tags":{"name":"Mamma Mia","amenity":"restaurant"},"name":"Mamma Mia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Schwarzer Adler":{"tags":{"name":"Schwarzer Adler","amenity":"restaurant"},"name":"Schwarzer Adler","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/IHOP":{"tags":{"name":"IHOP","amenity":"restaurant"},"name":"IHOP","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Chili's":{"tags":{"name":"Chili's","amenity":"restaurant"},"name":"Chili's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Asia":{"tags":{"name":"Asia","amenity":"restaurant"},"name":"Asia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Olive Garden":{"tags":{"name":"Olive Garden","amenity":"restaurant"},"name":"Olive Garden","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/TGI Friday's":{"tags":{"name":"TGI Friday's","amenity":"restaurant"},"name":"TGI Friday's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Friendly's":{"tags":{"name":"Friendly's","amenity":"restaurant"},"name":"Friendly's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Buffalo Grill":{"tags":{"name":"Buffalo Grill","amenity":"restaurant"},"name":"Buffalo Grill","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Texas Roadhouse":{"tags":{"name":"Texas Roadhouse","amenity":"restaurant"},"name":"Texas Roadhouse","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/ガスト":{"tags":{"name":"ガスト","name:en":"Gusto","amenity":"restaurant"},"name":"ガスト","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sakura":{"tags":{"name":"Sakura","amenity":"restaurant"},"name":"Sakura","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mensa":{"tags":{"name":"Mensa","amenity":"restaurant"},"name":"Mensa","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/The Keg":{"tags":{"name":"The Keg","amenity":"restaurant"},"name":"The Keg","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/サイゼリヤ":{"tags":{"name":"サイゼリヤ","amenity":"restaurant"},"name":"サイゼリヤ","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Strada":{"tags":{"name":"La Strada","amenity":"restaurant"},"name":"La Strada","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Village Inn":{"tags":{"name":"Village Inn","amenity":"restaurant"},"name":"Village Inn","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Buffalo Wild Wings":{"tags":{"name":"Buffalo Wild Wings","amenity":"restaurant"},"name":"Buffalo Wild Wings","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Peking":{"tags":{"name":"Peking","amenity":"restaurant"},"name":"Peking","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Round Table Pizza":{"tags":{"name":"Round Table Pizza","amenity":"restaurant"},"name":"Round Table Pizza","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/California Pizza Kitchen":{"tags":{"name":"California Pizza Kitchen","amenity":"restaurant"},"name":"California Pizza Kitchen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Якитория":{"tags":{"name":"Якитория","amenity":"restaurant"},"name":"Якитория","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Golden Corral":{"tags":{"name":"Golden Corral","amenity":"restaurant"},"name":"Golden Corral","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Perkins":{"tags":{"name":"Perkins","amenity":"restaurant"},"name":"Perkins","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Ruby Tuesday":{"tags":{"name":"Ruby Tuesday","amenity":"restaurant"},"name":"Ruby Tuesday","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Shari's":{"tags":{"name":"Shari's","amenity":"restaurant"},"name":"Shari's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bob Evans":{"tags":{"name":"Bob Evans","amenity":"restaurant"},"name":"Bob Evans","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/바다횟집 (Bada Fish Restaurant)":{"tags":{"name":"바다횟집 (Bada Fish Restaurant)","amenity":"restaurant"},"name":"바다횟집 (Bada Fish Restaurant)","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mang Inasal":{"tags":{"name":"Mang Inasal","amenity":"restaurant"},"name":"Mang Inasal","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Евразия":{"tags":{"name":"Евразия","amenity":"restaurant"},"name":"Евразия","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/ジョナサン":{"tags":{"name":"ジョナサン","amenity":"restaurant"},"name":"ジョナサン","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Longhorn Steakhouse":{"tags":{"name":"Longhorn Steakhouse","amenity":"restaurant"},"name":"Longhorn Steakhouse","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/bank/Chase":{"tags":{"name":"Chase","amenity":"bank"},"name":"Chase","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Commonwealth Bank":{"tags":{"name":"Commonwealth Bank","amenity":"bank"},"name":"Commonwealth Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Citibank":{"tags":{"name":"Citibank","amenity":"bank"},"name":"Citibank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/HSBC":{"tags":{"name":"HSBC","amenity":"bank"},"name":"HSBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Barclays":{"tags":{"name":"Barclays","amenity":"bank"},"name":"Barclays","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Westpac":{"tags":{"name":"Westpac","amenity":"bank"},"name":"Westpac","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/NAB":{"tags":{"name":"NAB","amenity":"bank"},"name":"NAB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ANZ":{"tags":{"name":"ANZ","amenity":"bank"},"name":"ANZ","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Lloyds Bank":{"tags":{"name":"Lloyds Bank","amenity":"bank"},"name":"Lloyds Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Landbank":{"tags":{"name":"Landbank","amenity":"bank"},"name":"Landbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparkasse":{"tags":{"name":"Sparkasse","amenity":"bank"},"name":"Sparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/UCPB":{"tags":{"name":"UCPB","amenity":"bank"},"name":"UCPB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PNB":{"tags":{"name":"PNB","amenity":"bank"},"name":"PNB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Metrobank":{"tags":{"name":"Metrobank","amenity":"bank"},"name":"Metrobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BDO":{"tags":{"name":"BDO","amenity":"bank"},"name":"BDO","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Volksbank":{"tags":{"name":"Volksbank","amenity":"bank"},"name":"Volksbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BPI":{"tags":{"name":"BPI","amenity":"bank"},"name":"BPI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Postbank":{"tags":{"name":"Postbank","amenity":"bank"},"name":"Postbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/NatWest":{"tags":{"name":"NatWest","amenity":"bank"},"name":"NatWest","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Raiffeisenbank":{"tags":{"name":"Raiffeisenbank","amenity":"bank"},"name":"Raiffeisenbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Yorkshire Bank":{"tags":{"name":"Yorkshire Bank","amenity":"bank"},"name":"Yorkshire Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ABSA":{"tags":{"name":"ABSA","amenity":"bank"},"name":"ABSA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Standard Bank":{"tags":{"name":"Standard Bank","amenity":"bank"},"name":"Standard Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/FNB":{"tags":{"name":"FNB","amenity":"bank"},"name":"FNB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Deutsche Bank":{"tags":{"name":"Deutsche Bank","amenity":"bank"},"name":"Deutsche Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/SEB":{"tags":{"name":"SEB","amenity":"bank"},"name":"SEB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Commerzbank":{"tags":{"name":"Commerzbank","amenity":"bank"},"name":"Commerzbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Targobank":{"tags":{"name":"Targobank","amenity":"bank"},"name":"Targobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ABN AMRO":{"tags":{"name":"ABN AMRO","amenity":"bank"},"name":"ABN AMRO","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Handelsbanken":{"tags":{"name":"Handelsbanken","amenity":"bank"},"name":"Handelsbanken","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Swedbank":{"tags":{"name":"Swedbank","amenity":"bank"},"name":"Swedbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Kreissparkasse":{"tags":{"name":"Kreissparkasse","amenity":"bank"},"name":"Kreissparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/UniCredit Bank":{"tags":{"name":"UniCredit Bank","amenity":"bank"},"name":"UniCredit Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Monte dei Paschi di Siena":{"tags":{"name":"Monte dei Paschi di Siena","amenity":"bank"},"name":"Monte dei Paschi di Siena","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Rural":{"tags":{"name":"Caja Rural","amenity":"bank"},"name":"Caja Rural","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Dresdner Bank":{"tags":{"name":"Dresdner Bank","amenity":"bank"},"name":"Dresdner Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparda-Bank":{"tags":{"name":"Sparda-Bank","amenity":"bank"},"name":"Sparda-Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/VÚB":{"tags":{"name":"VÚB","amenity":"bank"},"name":"VÚB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Slovenská sporiteľňa":{"tags":{"name":"Slovenská sporiteľňa","amenity":"bank"},"name":"Slovenská sporiteľňa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of Montreal":{"tags":{"name":"Bank of Montreal","amenity":"bank"},"name":"Bank of Montreal","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/KBC":{"tags":{"name":"KBC","amenity":"bank"},"name":"KBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Royal Bank of Scotland":{"tags":{"name":"Royal Bank of Scotland","amenity":"bank"},"name":"Royal Bank of Scotland","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/TSB":{"tags":{"name":"TSB","amenity":"bank"},"name":"TSB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/US Bank":{"tags":{"name":"US Bank","amenity":"bank"},"name":"US Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/HypoVereinsbank":{"tags":{"name":"HypoVereinsbank","amenity":"bank"},"name":"HypoVereinsbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank Austria":{"tags":{"name":"Bank Austria","amenity":"bank"},"name":"Bank Austria","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ING":{"tags":{"name":"ING","amenity":"bank"},"name":"ING","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Erste Bank":{"tags":{"name":"Erste Bank","amenity":"bank"},"name":"Erste Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/CIBC":{"tags":{"name":"CIBC","amenity":"bank"},"name":"CIBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Scotiabank":{"tags":{"name":"Scotiabank","amenity":"bank"},"name":"Scotiabank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caisse d'Épargne":{"tags":{"name":"Caisse d'Épargne","amenity":"bank"},"name":"Caisse d'Épargne","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Santander":{"tags":{"name":"Santander","amenity":"bank"},"name":"Santander","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of Scotland":{"tags":{"name":"Bank of Scotland","amenity":"bank"},"name":"Bank of Scotland","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/TD Canada Trust":{"tags":{"name":"TD Canada Trust","amenity":"bank"},"name":"TD Canada Trust","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BMO":{"tags":{"name":"BMO","amenity":"bank"},"name":"BMO","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Danske Bank":{"tags":{"name":"Danske Bank","amenity":"bank"},"name":"Danske Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/OTP":{"tags":{"name":"OTP","amenity":"bank"},"name":"OTP","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit Agricole":{"tags":{"name":"Crédit Agricole","amenity":"bank"},"name":"Crédit Agricole","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/LCL":{"tags":{"name":"LCL","amenity":"bank"},"name":"LCL","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/VR-Bank":{"tags":{"name":"VR-Bank","amenity":"bank"},"name":"VR-Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ČSOB":{"tags":{"name":"ČSOB","amenity":"bank"},"name":"ČSOB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Česká spořitelna":{"tags":{"name":"Česká spořitelna","amenity":"bank"},"name":"Česká spořitelna","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNP":{"tags":{"name":"BNP","amenity":"bank"},"name":"BNP","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Royal Bank":{"tags":{"name":"Royal Bank","amenity":"bank"},"name":"Royal Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Nationwide":{"tags":{"name":"Nationwide","amenity":"bank"},"name":"Nationwide","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Halifax":{"tags":{"name":"Halifax","amenity":"bank"},"name":"Halifax","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BAWAG PSK":{"tags":{"name":"BAWAG PSK","amenity":"bank"},"name":"BAWAG PSK","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/National Bank":{"tags":{"name":"National Bank","amenity":"bank"},"name":"National Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Nedbank":{"tags":{"name":"Nedbank","amenity":"bank"},"name":"Nedbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/First National Bank":{"tags":{"name":"First National Bank","amenity":"bank"},"name":"First National Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Nordea":{"tags":{"name":"Nordea","amenity":"bank"},"name":"Nordea","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Rabobank":{"tags":{"name":"Rabobank","amenity":"bank"},"name":"Rabobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparkasse KölnBonn":{"tags":{"name":"Sparkasse KölnBonn","amenity":"bank"},"name":"Sparkasse KölnBonn","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Tatra banka":{"tags":{"name":"Tatra banka","amenity":"bank"},"name":"Tatra banka","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Berliner Sparkasse":{"tags":{"name":"Berliner Sparkasse","amenity":"bank"},"name":"Berliner Sparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Berliner Volksbank":{"tags":{"name":"Berliner Volksbank","amenity":"bank"},"name":"Berliner Volksbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Wells Fargo":{"tags":{"name":"Wells Fargo","amenity":"bank"},"name":"Wells Fargo","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Credit Suisse":{"tags":{"name":"Credit Suisse","amenity":"bank"},"name":"Credit Suisse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Société Générale":{"tags":{"name":"Société Générale","amenity":"bank"},"name":"Société Générale","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Osuuspankki":{"tags":{"name":"Osuuspankki","amenity":"bank"},"name":"Osuuspankki","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparkasse Aachen":{"tags":{"name":"Sparkasse Aachen","amenity":"bank"},"name":"Sparkasse Aachen","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Hamburger Sparkasse":{"tags":{"name":"Hamburger Sparkasse","amenity":"bank"},"name":"Hamburger Sparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Cassa di Risparmio del Veneto":{"tags":{"name":"Cassa di Risparmio del Veneto","amenity":"bank"},"name":"Cassa di Risparmio del Veneto","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNP Paribas":{"tags":{"name":"BNP Paribas","amenity":"bank"},"name":"BNP Paribas","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banque Populaire":{"tags":{"name":"Banque Populaire","amenity":"bank"},"name":"Banque Populaire","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNP Paribas Fortis":{"tags":{"name":"BNP Paribas Fortis","amenity":"bank"},"name":"BNP Paribas Fortis","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Popular":{"tags":{"name":"Banco Popular","amenity":"bank"},"name":"Banco Popular","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancaja":{"tags":{"name":"Bancaja","amenity":"bank"},"name":"Bancaja","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banesto":{"tags":{"name":"Banesto","amenity":"bank"},"name":"Banesto","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/La Caixa":{"tags":{"name":"La Caixa","amenity":"bank"},"name":"La Caixa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Santander Consumer Bank":{"tags":{"name":"Santander Consumer Bank","amenity":"bank"},"name":"Santander Consumer Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BRD":{"tags":{"name":"BRD","amenity":"bank"},"name":"BRD","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BCR":{"tags":{"name":"BCR","amenity":"bank"},"name":"BCR","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banca Transilvania":{"tags":{"name":"Banca Transilvania","amenity":"bank"},"name":"Banca Transilvania","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BW-Bank":{"tags":{"name":"BW-Bank","amenity":"bank"},"name":"BW-Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Komerční banka":{"tags":{"name":"Komerční banka","amenity":"bank"},"name":"Komerční banka","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Pastor":{"tags":{"name":"Banco Pastor","amenity":"bank"},"name":"Banco Pastor","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Stadtsparkasse":{"tags":{"name":"Stadtsparkasse","amenity":"bank"},"name":"Stadtsparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ulster Bank":{"tags":{"name":"Ulster Bank","amenity":"bank"},"name":"Ulster Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sberbank":{"tags":{"name":"Sberbank","amenity":"bank"},"name":"Sberbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/CIC":{"tags":{"name":"CIC","amenity":"bank"},"name":"CIC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancpost":{"tags":{"name":"Bancpost","amenity":"bank"},"name":"Bancpost","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Madrid":{"tags":{"name":"Caja Madrid","amenity":"bank"},"name":"Caja Madrid","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Maybank":{"tags":{"name":"Maybank","amenity":"bank"},"name":"Maybank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/中国银行":{"tags":{"name":"中国银行","amenity":"bank"},"name":"中国银行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Unicredit Banca":{"tags":{"name":"Unicredit Banca","amenity":"bank"},"name":"Unicredit Banca","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit Mutuel":{"tags":{"name":"Crédit Mutuel","amenity":"bank"},"name":"Crédit Mutuel","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BBVA":{"tags":{"name":"BBVA","amenity":"bank"},"name":"BBVA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Intesa San Paolo":{"tags":{"name":"Intesa San Paolo","amenity":"bank"},"name":"Intesa San Paolo","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/TD Bank":{"tags":{"name":"TD Bank","amenity":"bank"},"name":"TD Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Belfius":{"tags":{"name":"Belfius","amenity":"bank"},"name":"Belfius","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of America":{"tags":{"name":"Bank of America","amenity":"bank"},"name":"Bank of America","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/RBC":{"tags":{"name":"RBC","amenity":"bank"},"name":"RBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Alpha Bank":{"tags":{"name":"Alpha Bank","amenity":"bank"},"name":"Alpha Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Сбербанк":{"tags":{"name":"Сбербанк","amenity":"bank"},"name":"Сбербанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Россельхозбанк":{"tags":{"name":"Россельхозбанк","amenity":"bank"},"name":"Россельхозбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit du Nord":{"tags":{"name":"Crédit du Nord","amenity":"bank"},"name":"Crédit du Nord","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BancoEstado":{"tags":{"name":"BancoEstado","amenity":"bank"},"name":"BancoEstado","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Millennium Bank":{"tags":{"name":"Millennium Bank","amenity":"bank"},"name":"Millennium Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/State Bank of India":{"tags":{"name":"State Bank of India","amenity":"bank"},"name":"State Bank of India","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Беларусбанк":{"tags":{"name":"Беларусбанк","amenity":"bank"},"name":"Беларусбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ING Bank Śląski":{"tags":{"name":"ING Bank Śląski","amenity":"bank"},"name":"ING Bank Śląski","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caixa Geral de Depósitos":{"tags":{"name":"Caixa Geral de Depósitos","amenity":"bank"},"name":"Caixa Geral de Depósitos","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Kreissparkasse Köln":{"tags":{"name":"Kreissparkasse Köln","amenity":"bank"},"name":"Kreissparkasse Köln","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco BCI":{"tags":{"name":"Banco BCI","amenity":"bank"},"name":"Banco BCI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de Chile":{"tags":{"name":"Banco de Chile","amenity":"bank"},"name":"Banco de Chile","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ВТБ24":{"tags":{"name":"ВТБ24","amenity":"bank"},"name":"ВТБ24","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/UBS":{"tags":{"name":"UBS","amenity":"bank"},"name":"UBS","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PKO BP":{"tags":{"name":"PKO BP","amenity":"bank"},"name":"PKO BP","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Chinabank":{"tags":{"name":"Chinabank","amenity":"bank"},"name":"Chinabank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PSBank":{"tags":{"name":"PSBank","amenity":"bank"},"name":"PSBank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Union Bank":{"tags":{"name":"Union Bank","amenity":"bank"},"name":"Union Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/China Bank":{"tags":{"name":"China Bank","amenity":"bank"},"name":"China Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/RCBC":{"tags":{"name":"RCBC","amenity":"bank"},"name":"RCBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Unicaja":{"tags":{"name":"Unicaja","amenity":"bank"},"name":"Unicaja","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BBK":{"tags":{"name":"BBK","amenity":"bank"},"name":"BBK","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ibercaja":{"tags":{"name":"Ibercaja","amenity":"bank"},"name":"Ibercaja","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/RBS":{"tags":{"name":"RBS","amenity":"bank"},"name":"RBS","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Commercial Bank of Ceylon PLC":{"tags":{"name":"Commercial Bank of Ceylon PLC","amenity":"bank"},"name":"Commercial Bank of Ceylon PLC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of Ireland":{"tags":{"name":"Bank of Ireland","amenity":"bank"},"name":"Bank of Ireland","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNL":{"tags":{"name":"BNL","amenity":"bank"},"name":"BNL","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Santander":{"tags":{"name":"Banco Santander","amenity":"bank"},"name":"Banco Santander","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Itaú":{"tags":{"name":"Banco Itaú","amenity":"bank"},"name":"Banco Itaú","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/AIB":{"tags":{"name":"AIB","amenity":"bank"},"name":"AIB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BZ WBK":{"tags":{"name":"BZ WBK","amenity":"bank"},"name":"BZ WBK","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco do Brasil":{"tags":{"name":"Banco do Brasil","amenity":"bank"},"name":"Banco do Brasil","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caixa Econômica Federal":{"tags":{"name":"Caixa Econômica Federal","amenity":"bank"},"name":"Caixa Econômica Federal","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Fifth Third Bank":{"tags":{"name":"Fifth Third Bank","amenity":"bank"},"name":"Fifth Third Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banca Popolare di Vicenza":{"tags":{"name":"Banca Popolare di Vicenza","amenity":"bank"},"name":"Banca Popolare di Vicenza","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Wachovia":{"tags":{"name":"Wachovia","amenity":"bank"},"name":"Wachovia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/OLB":{"tags":{"name":"OLB","amenity":"bank"},"name":"OLB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/みずほ銀行":{"tags":{"name":"みずほ銀行","amenity":"bank"},"name":"みずほ銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BES":{"tags":{"name":"BES","amenity":"bank"},"name":"BES","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ICICI Bank":{"tags":{"name":"ICICI Bank","amenity":"bank"},"name":"ICICI Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/HDFC Bank":{"tags":{"name":"HDFC Bank","amenity":"bank"},"name":"HDFC Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/La Banque Postale":{"tags":{"name":"La Banque Postale","amenity":"bank"},"name":"La Banque Postale","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Pekao SA":{"tags":{"name":"Pekao SA","amenity":"bank"},"name":"Pekao SA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Oberbank":{"tags":{"name":"Oberbank","amenity":"bank"},"name":"Oberbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bradesco":{"tags":{"name":"Bradesco","amenity":"bank"},"name":"Bradesco","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Oldenburgische Landesbank":{"tags":{"name":"Oldenburgische Landesbank","amenity":"bank"},"name":"Oldenburgische Landesbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bendigo Bank":{"tags":{"name":"Bendigo Bank","amenity":"bank"},"name":"Bendigo Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Argenta":{"tags":{"name":"Argenta","amenity":"bank"},"name":"Argenta","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/AXA":{"tags":{"name":"AXA","amenity":"bank"},"name":"AXA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Axis Bank":{"tags":{"name":"Axis Bank","amenity":"bank"},"name":"Axis Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Nación":{"tags":{"name":"Banco Nación","amenity":"bank"},"name":"Banco Nación","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/GE Money Bank":{"tags":{"name":"GE Money Bank","amenity":"bank"},"name":"GE Money Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Альфа-Банк":{"tags":{"name":"Альфа-Банк","amenity":"bank"},"name":"Альфа-Банк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Белагропромбанк":{"tags":{"name":"Белагропромбанк","amenity":"bank"},"name":"Белагропромбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Círculo":{"tags":{"name":"Caja Círculo","amenity":"bank"},"name":"Caja Círculo","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Galicia":{"tags":{"name":"Banco Galicia","amenity":"bank"},"name":"Banco Galicia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Eurobank":{"tags":{"name":"Eurobank","amenity":"bank"},"name":"Eurobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banca Intesa":{"tags":{"name":"Banca Intesa","amenity":"bank"},"name":"Banca Intesa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Canara Bank":{"tags":{"name":"Canara Bank","amenity":"bank"},"name":"Canara Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Cajamar":{"tags":{"name":"Cajamar","amenity":"bank"},"name":"Cajamar","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banamex":{"tags":{"name":"Banamex","amenity":"bank"},"name":"Banamex","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit Mutuel de Bretagne":{"tags":{"name":"Crédit Mutuel de Bretagne","amenity":"bank"},"name":"Crédit Mutuel de Bretagne","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Davivienda":{"tags":{"name":"Davivienda","amenity":"bank"},"name":"Davivienda","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank Spółdzielczy":{"tags":{"name":"Bank Spółdzielczy","amenity":"bank"},"name":"Bank Spółdzielczy","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Credit Agricole":{"tags":{"name":"Credit Agricole","amenity":"bank"},"name":"Credit Agricole","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bankinter":{"tags":{"name":"Bankinter","amenity":"bank"},"name":"Bankinter","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banque Nationale":{"tags":{"name":"Banque Nationale","amenity":"bank"},"name":"Banque Nationale","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of the West":{"tags":{"name":"Bank of the West","amenity":"bank"},"name":"Bank of the West","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Key Bank":{"tags":{"name":"Key Bank","amenity":"bank"},"name":"Key Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Western Union":{"tags":{"name":"Western Union","amenity":"bank"},"name":"Western Union","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Citizens Bank":{"tags":{"name":"Citizens Bank","amenity":"bank"},"name":"Citizens Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ПриватБанк":{"tags":{"name":"ПриватБанк","amenity":"bank"},"name":"ПриватБанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Security Bank":{"tags":{"name":"Security Bank","amenity":"bank"},"name":"Security Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Millenium":{"tags":{"name":"Millenium","amenity":"bank"},"name":"Millenium","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bankia":{"tags":{"name":"Bankia","amenity":"bank"},"name":"Bankia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/三菱東京UFJ銀行":{"tags":{"name":"三菱東京UFJ銀行","amenity":"bank"},"name":"三菱東京UFJ銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caixa":{"tags":{"name":"Caixa","amenity":"bank"},"name":"Caixa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de Costa Rica":{"tags":{"name":"Banco de Costa Rica","amenity":"bank"},"name":"Banco de Costa Rica","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/SunTrust Bank":{"tags":{"name":"SunTrust Bank","amenity":"bank"},"name":"SunTrust Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Itaú":{"tags":{"name":"Itaú","amenity":"bank"},"name":"Itaú","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PBZ":{"tags":{"name":"PBZ","amenity":"bank"},"name":"PBZ","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/中国工商银行":{"tags":{"name":"中国工商银行","amenity":"bank"},"name":"中国工商银行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancolombia":{"tags":{"name":"Bancolombia","amenity":"bank"},"name":"Bancolombia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Райффайзен Банк Аваль":{"tags":{"name":"Райффайзен Банк Аваль","amenity":"bank"},"name":"Райффайзен Банк Аваль","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancomer":{"tags":{"name":"Bancomer","amenity":"bank"},"name":"Bancomer","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banorte":{"tags":{"name":"Banorte","amenity":"bank"},"name":"Banorte","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Alior Bank":{"tags":{"name":"Alior Bank","amenity":"bank"},"name":"Alior Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BOC":{"tags":{"name":"BOC","amenity":"bank"},"name":"BOC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Банк Москвы":{"tags":{"name":"Банк Москвы","amenity":"bank"},"name":"Банк Москвы","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ВТБ":{"tags":{"name":"ВТБ","amenity":"bank"},"name":"ВТБ","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Getin Bank":{"tags":{"name":"Getin Bank","amenity":"bank"},"name":"Getin Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Duero":{"tags":{"name":"Caja Duero","amenity":"bank"},"name":"Caja Duero","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Regions Bank":{"tags":{"name":"Regions Bank","amenity":"bank"},"name":"Regions Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Росбанк":{"tags":{"name":"Росбанк","amenity":"bank"},"name":"Росбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Estado":{"tags":{"name":"Banco Estado","amenity":"bank"},"name":"Banco Estado","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BCI":{"tags":{"name":"BCI","amenity":"bank"},"name":"BCI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/SunTrust":{"tags":{"name":"SunTrust","amenity":"bank"},"name":"SunTrust","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PNC Bank":{"tags":{"name":"PNC Bank","amenity":"bank"},"name":"PNC Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/신한은행":{"tags":{"name":"신한은행","name:en":"Sinhan Bank","amenity":"bank"},"name":"신한은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/우리은행":{"tags":{"name":"우리은행","name:en":"Uri Bank","amenity":"bank"},"name":"우리은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/국민은행":{"tags":{"name":"국민은행","name:en":"Gungmin Bank","amenity":"bank"},"name":"국민은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/중소기업은행":{"tags":{"name":"중소기업은행","name:en":"Industrial Bank of Korea","amenity":"bank"},"name":"중소기업은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/광주은행":{"tags":{"name":"광주은행","name:en":"Gwangju Bank","amenity":"bank"},"name":"광주은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Газпромбанк":{"tags":{"name":"Газпромбанк","amenity":"bank"},"name":"Газпромбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/M&T Bank":{"tags":{"name":"M&T Bank","amenity":"bank"},"name":"M&T Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja de Burgos":{"tags":{"name":"Caja de Burgos","amenity":"bank"},"name":"Caja de Burgos","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Santander Totta":{"tags":{"name":"Santander Totta","amenity":"bank"},"name":"Santander Totta","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/УкрСиббанк":{"tags":{"name":"УкрСиббанк","amenity":"bank"},"name":"УкрСиббанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ощадбанк":{"tags":{"name":"Ощадбанк","amenity":"bank"},"name":"Ощадбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Уралсиб":{"tags":{"name":"Уралсиб","amenity":"bank"},"name":"Уралсиб","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/りそな銀行":{"tags":{"name":"りそな銀行","name:en":"Mizuho Bank","amenity":"bank"},"name":"りそな銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ecobank":{"tags":{"name":"Ecobank","amenity":"bank"},"name":"Ecobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Cajero Automatico Bancared":{"tags":{"name":"Cajero Automatico Bancared","amenity":"bank"},"name":"Cajero Automatico Bancared","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Промсвязьбанк":{"tags":{"name":"Промсвязьбанк","amenity":"bank"},"name":"Промсвязьбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/三井住友銀行":{"tags":{"name":"三井住友銀行","amenity":"bank"},"name":"三井住友銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Provincia":{"tags":{"name":"Banco Provincia","amenity":"bank"},"name":"Banco Provincia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BB&T":{"tags":{"name":"BB&T","amenity":"bank"},"name":"BB&T","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Возрождение":{"tags":{"name":"Возрождение","amenity":"bank"},"name":"Возрождение","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Capital One":{"tags":{"name":"Capital One","amenity":"bank"},"name":"Capital One","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/横浜銀行":{"tags":{"name":"横浜銀行","amenity":"bank"},"name":"横浜銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank Mandiri":{"tags":{"name":"Bank Mandiri","amenity":"bank"},"name":"Bank Mandiri","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de la Nación":{"tags":{"name":"Banco de la Nación","amenity":"bank"},"name":"Banco de la Nación","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco G&T Continental":{"tags":{"name":"Banco G&T Continental","amenity":"bank"},"name":"Banco G&T Continental","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Peoples Bank":{"tags":{"name":"Peoples Bank","amenity":"bank"},"name":"Peoples Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/工商银行":{"tags":{"name":"工商银行","amenity":"bank"},"name":"工商银行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Совкомбанк":{"tags":{"name":"Совкомбанк","amenity":"bank"},"name":"Совкомбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Provincial":{"tags":{"name":"Provincial","amenity":"bank"},"name":"Provincial","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de Desarrollo Banrural":{"tags":{"name":"Banco de Desarrollo Banrural","amenity":"bank"},"name":"Banco de Desarrollo Banrural","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Bradesco":{"tags":{"name":"Banco Bradesco","amenity":"bank"},"name":"Banco Bradesco","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bicentenario":{"tags":{"name":"Bicentenario","amenity":"bank"},"name":"Bicentenario","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ლიბერთი ბანკი":{"tags":{"name":"ლიბერთი ბანკი","name:en":"Liberty Bank","amenity":"bank"},"name":"ლიბერთი ბანკი","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banesco":{"tags":{"name":"Banesco","amenity":"bank"},"name":"Banesco","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Mercantil":{"tags":{"name":"Mercantil","amenity":"bank"},"name":"Mercantil","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank BRI":{"tags":{"name":"Bank BRI","amenity":"bank"},"name":"Bank BRI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Del Tesoro":{"tags":{"name":"Del Tesoro","amenity":"bank"},"name":"Del Tesoro","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/하나은행":{"tags":{"name":"하나은행","amenity":"bank"},"name":"하나은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/CityCommerce Bank":{"tags":{"name":"CityCommerce Bank","amenity":"bank"},"name":"CityCommerce Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/De Venezuela":{"tags":{"name":"De Venezuela","amenity":"bank"},"name":"De Venezuela","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/car_rental/Europcar":{"tags":{"name":"Europcar","amenity":"car_rental"},"name":"Europcar","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Budget":{"tags":{"name":"Budget","amenity":"car_rental"},"name":"Budget","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Sixt":{"tags":{"name":"Sixt","amenity":"car_rental"},"name":"Sixt","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Avis":{"tags":{"name":"Avis","amenity":"car_rental"},"name":"Avis","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Hertz":{"tags":{"name":"Hertz","amenity":"car_rental"},"name":"Hertz","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Enterprise":{"tags":{"name":"Enterprise","amenity":"car_rental"},"name":"Enterprise","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/stadtmobil CarSharing-Station":{"tags":{"name":"stadtmobil CarSharing-Station","amenity":"car_rental"},"name":"stadtmobil CarSharing-Station","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/pharmacy/Rowlands Pharmacy":{"tags":{"name":"Rowlands Pharmacy","amenity":"pharmacy"},"name":"Rowlands Pharmacy","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Boots":{"tags":{"name":"Boots","amenity":"pharmacy"},"name":"Boots","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Marien-Apotheke":{"tags":{"name":"Marien-Apotheke","amenity":"pharmacy"},"name":"Marien-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Mercury Drug":{"tags":{"name":"Mercury Drug","amenity":"pharmacy"},"name":"Mercury Drug","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Löwen-Apotheke":{"tags":{"name":"Löwen-Apotheke","amenity":"pharmacy"},"name":"Löwen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Superdrug":{"tags":{"name":"Superdrug","amenity":"pharmacy"},"name":"Superdrug","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Sonnen-Apotheke":{"tags":{"name":"Sonnen-Apotheke","amenity":"pharmacy"},"name":"Sonnen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rathaus-Apotheke":{"tags":{"name":"Rathaus-Apotheke","amenity":"pharmacy"},"name":"Rathaus-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Engel-Apotheke":{"tags":{"name":"Engel-Apotheke","amenity":"pharmacy"},"name":"Engel-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Hirsch-Apotheke":{"tags":{"name":"Hirsch-Apotheke","amenity":"pharmacy"},"name":"Hirsch-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Stern-Apotheke":{"tags":{"name":"Stern-Apotheke","amenity":"pharmacy"},"name":"Stern-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Lloyds Pharmacy":{"tags":{"name":"Lloyds Pharmacy","amenity":"pharmacy"},"name":"Lloyds Pharmacy","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rosen-Apotheke":{"tags":{"name":"Rosen-Apotheke","amenity":"pharmacy"},"name":"Rosen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Stadt-Apotheke":{"tags":{"name":"Stadt-Apotheke","amenity":"pharmacy"},"name":"Stadt-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Markt-Apotheke":{"tags":{"name":"Markt-Apotheke","amenity":"pharmacy"},"name":"Markt-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Аптека":{"tags":{"name":"Аптека","amenity":"pharmacy"},"name":"Аптека","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Pharmasave":{"tags":{"name":"Pharmasave","amenity":"pharmacy"},"name":"Pharmasave","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Brunnen-Apotheke":{"tags":{"name":"Brunnen-Apotheke","amenity":"pharmacy"},"name":"Brunnen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Shoppers Drug Mart":{"tags":{"name":"Shoppers Drug Mart","amenity":"pharmacy"},"name":"Shoppers Drug Mart","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Apotheke am Markt":{"tags":{"name":"Apotheke am Markt","amenity":"pharmacy"},"name":"Apotheke am Markt","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Alte Apotheke":{"tags":{"name":"Alte Apotheke","amenity":"pharmacy"},"name":"Alte Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Neue Apotheke":{"tags":{"name":"Neue Apotheke","amenity":"pharmacy"},"name":"Neue Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Gintarinė vaistinė":{"tags":{"name":"Gintarinė vaistinė","amenity":"pharmacy"},"name":"Gintarinė vaistinė","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rats-Apotheke":{"tags":{"name":"Rats-Apotheke","amenity":"pharmacy"},"name":"Rats-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Adler Apotheke":{"tags":{"name":"Adler Apotheke","amenity":"pharmacy"},"name":"Adler Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Pharmacie Centrale":{"tags":{"name":"Pharmacie Centrale","amenity":"pharmacy"},"name":"Pharmacie Centrale","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Walgreens":{"tags":{"name":"Walgreens","amenity":"pharmacy"},"name":"Walgreens","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rite Aid":{"tags":{"name":"Rite Aid","amenity":"pharmacy"},"name":"Rite Aid","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Apotheke":{"tags":{"name":"Apotheke","amenity":"pharmacy"},"name":"Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Linden-Apotheke":{"tags":{"name":"Linden-Apotheke","amenity":"pharmacy"},"name":"Linden-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Bahnhof-Apotheke":{"tags":{"name":"Bahnhof-Apotheke","amenity":"pharmacy"},"name":"Bahnhof-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Burg-Apotheke":{"tags":{"name":"Burg-Apotheke","amenity":"pharmacy"},"name":"Burg-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Jean Coutu":{"tags":{"name":"Jean Coutu","amenity":"pharmacy"},"name":"Jean Coutu","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Pharmaprix":{"tags":{"name":"Pharmaprix","amenity":"pharmacy"},"name":"Pharmaprix","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacias Ahumada":{"tags":{"name":"Farmacias Ahumada","amenity":"pharmacy"},"name":"Farmacias Ahumada","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacia Comunale":{"tags":{"name":"Farmacia Comunale","amenity":"pharmacy"},"name":"Farmacia Comunale","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacias Cruz Verde":{"tags":{"name":"Farmacias Cruz Verde","amenity":"pharmacy"},"name":"Farmacias Cruz Verde","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Cruz Verde":{"tags":{"name":"Cruz Verde","amenity":"pharmacy"},"name":"Cruz Verde","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Hubertus Apotheke":{"tags":{"name":"Hubertus Apotheke","amenity":"pharmacy"},"name":"Hubertus Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/CVS":{"tags":{"name":"CVS","amenity":"pharmacy"},"name":"CVS","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacias SalcoBrand":{"tags":{"name":"Farmacias SalcoBrand","amenity":"pharmacy"},"name":"Farmacias SalcoBrand","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Фармация":{"tags":{"name":"Фармация","amenity":"pharmacy"},"name":"Фармация","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Bären-Apotheke":{"tags":{"name":"Bären-Apotheke","amenity":"pharmacy"},"name":"Bären-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Clicks":{"tags":{"name":"Clicks","amenity":"pharmacy"},"name":"Clicks","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/セイジョー":{"tags":{"name":"セイジョー","amenity":"pharmacy"},"name":"セイジョー","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/マツモトキヨシ":{"tags":{"name":"マツモトキヨシ","amenity":"pharmacy"},"name":"マツモトキヨシ","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Dr. Max":{"tags":{"name":"Dr. Max","amenity":"pharmacy"},"name":"Dr. Max","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Вита":{"tags":{"name":"Вита","amenity":"pharmacy"},"name":"Вита","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/サンドラッグ":{"tags":{"name":"サンドラッグ","amenity":"pharmacy"},"name":"サンドラッグ","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Apteka":{"tags":{"name":"Apteka","amenity":"pharmacy"},"name":"Apteka","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Первая помощь":{"tags":{"name":"Первая помощь","amenity":"pharmacy"},"name":"Первая помощь","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Ригла":{"tags":{"name":"Ригла","amenity":"pharmacy"},"name":"Ригла","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Имплозия":{"tags":{"name":"Имплозия","amenity":"pharmacy"},"name":"Имплозия","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Kinney Drugs":{"tags":{"name":"Kinney Drugs","amenity":"pharmacy"},"name":"Kinney Drugs","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Классика":{"tags":{"name":"Классика","amenity":"pharmacy"},"name":"Классика","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Ljekarna":{"tags":{"name":"Ljekarna","amenity":"pharmacy"},"name":"Ljekarna","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/SalcoBrand":{"tags":{"name":"SalcoBrand","amenity":"pharmacy"},"name":"SalcoBrand","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Аптека 36,6":{"tags":{"name":"Аптека 36,6","amenity":"pharmacy"},"name":"Аптека 36,6","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Фармакор":{"tags":{"name":"Фармакор","amenity":"pharmacy"},"name":"Фармакор","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/スギ薬局":{"tags":{"name":"スギ薬局","amenity":"pharmacy"},"name":"スギ薬局","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Аптечный пункт":{"tags":{"name":"Аптечный пункт","amenity":"pharmacy"},"name":"Аптечный пункт","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Невис":{"tags":{"name":"Невис","amenity":"pharmacy"},"name":"Невис","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/トモズ (Tomod's)":{"tags":{"name":"トモズ (Tomod's)","amenity":"pharmacy"},"name":"トモズ (Tomod's)","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Eurovaistinė":{"tags":{"name":"Eurovaistinė","amenity":"pharmacy"},"name":"Eurovaistinė","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacity":{"tags":{"name":"Farmacity","amenity":"pharmacy"},"name":"Farmacity","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/аптека":{"tags":{"name":"аптека","amenity":"pharmacy"},"name":"аптека","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/The Generics Pharmacy":{"tags":{"name":"The Generics Pharmacy","amenity":"pharmacy"},"name":"The Generics Pharmacy","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmatodo":{"tags":{"name":"Farmatodo","amenity":"pharmacy"},"name":"Farmatodo","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Duane Reade":{"tags":{"name":"Duane Reade","amenity":"pharmacy"},"name":"Duane Reade","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Фармленд":{"tags":{"name":"Фармленд","amenity":"pharmacy"},"name":"Фармленд","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/ドラッグてらしま (Drug Terashima)":{"tags":{"name":"ドラッグてらしま (Drug Terashima)","amenity":"pharmacy"},"name":"ドラッグてらしま (Drug Terashima)","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Арніка":{"tags":{"name":"Арніка","amenity":"pharmacy"},"name":"Арніка","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/ავერსი (Aversi)":{"tags":{"name":"ავერსი (Aversi)","amenity":"pharmacy"},"name":"ავერსი (Aversi)","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmahorro":{"tags":{"name":"Farmahorro","amenity":"pharmacy"},"name":"Farmahorro","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/cafe/Starbucks":{"tags":{"name":"Starbucks","cuisine":"coffee_shop","amenity":"cafe"},"name":"Starbucks","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Cafeteria":{"tags":{"name":"Cafeteria","amenity":"cafe"},"name":"Cafeteria","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Costa":{"tags":{"name":"Costa","amenity":"cafe"},"name":"Costa","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Caffè Nero":{"tags":{"name":"Caffè Nero","amenity":"cafe"},"name":"Caffè Nero","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Кафе":{"tags":{"name":"Кафе","amenity":"cafe"},"name":"Кафе","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Café Central":{"tags":{"name":"Café Central","amenity":"cafe"},"name":"Café Central","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Second Cup":{"tags":{"name":"Second Cup","amenity":"cafe"},"name":"Second Cup","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Dunkin Donuts":{"tags":{"name":"Dunkin Donuts","cuisine":"donut","amenity":"cafe"},"name":"Dunkin Donuts","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Espresso House":{"tags":{"name":"Espresso House","amenity":"cafe"},"name":"Espresso House","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Segafredo":{"tags":{"name":"Segafredo","amenity":"cafe"},"name":"Segafredo","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Coffee Time":{"tags":{"name":"Coffee Time","amenity":"cafe"},"name":"Coffee Time","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Cafe Coffee Day":{"tags":{"name":"Cafe Coffee Day","amenity":"cafe"},"name":"Cafe Coffee Day","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Eiscafe Venezia":{"tags":{"name":"Eiscafe Venezia","amenity":"cafe"},"name":"Eiscafe Venezia","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/スターバックス":{"tags":{"name":"スターバックス","name:en":"Starbucks","amenity":"cafe"},"name":"スターバックス","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Шоколадница":{"tags":{"name":"Шоколадница","amenity":"cafe"},"name":"Шоколадница","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Pret A Manger":{"tags":{"name":"Pret A Manger","amenity":"cafe"},"name":"Pret A Manger","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Столовая":{"tags":{"name":"Столовая","amenity":"cafe"},"name":"Столовая","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/ドトール":{"tags":{"name":"ドトール","name:en":"DOUTOR","amenity":"cafe"},"name":"ドトール","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Tchibo":{"tags":{"name":"Tchibo","amenity":"cafe"},"name":"Tchibo","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Кофе Хауз":{"tags":{"name":"Кофе Хауз","amenity":"cafe"},"name":"Кофе Хауз","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Caribou Coffee":{"tags":{"name":"Caribou Coffee","amenity":"cafe"},"name":"Caribou Coffee","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Уют":{"tags":{"name":"Уют","amenity":"cafe"},"name":"Уют","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Шашлычная":{"tags":{"name":"Шашлычная","amenity":"cafe"},"name":"Шашлычная","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/คาเฟ่ อเมซอน":{"tags":{"name":"คาเฟ่ อเมซอน","amenity":"cafe"},"name":"คาเฟ่ อเมซอน","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Traveler's Coffee":{"tags":{"name":"Traveler's Coffee","amenity":"cafe"},"name":"Traveler's Coffee","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/カフェ・ド・クリエ":{"tags":{"name":"カフェ・ド・クリエ","name:en":"Cafe de CRIE","amenity":"cafe"},"name":"カフェ・ド・クリエ","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Cafe Amazon":{"tags":{"name":"Cafe Amazon","amenity":"cafe"},"name":"Cafe Amazon","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"shop/supermarket/Budgens":{"tags":{"name":"Budgens","shop":"supermarket"},"name":"Budgens","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Morrisons":{"tags":{"name":"Morrisons","shop":"supermarket"},"name":"Morrisons","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Interspar":{"tags":{"name":"Interspar","shop":"supermarket"},"name":"Interspar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Merkur":{"tags":{"name":"Merkur","shop":"supermarket"},"name":"Merkur","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sainsbury's":{"tags":{"name":"Sainsbury's","shop":"supermarket"},"name":"Sainsbury's","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Lidl":{"tags":{"name":"Lidl","shop":"supermarket"},"name":"Lidl","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Edeka":{"tags":{"name":"Edeka","shop":"supermarket"},"name":"Edeka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coles":{"tags":{"name":"Coles","shop":"supermarket"},"name":"Coles","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Iceland":{"tags":{"name":"Iceland","shop":"supermarket"},"name":"Iceland","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coop":{"tags":{"name":"Coop","shop":"supermarket"},"name":"Coop","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco":{"tags":{"name":"Tesco","shop":"supermarket"},"name":"Tesco","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Woolworths":{"tags":{"name":"Woolworths","shop":"supermarket"},"name":"Woolworths","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Zielpunkt":{"tags":{"name":"Zielpunkt","shop":"supermarket"},"name":"Zielpunkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Nahkauf":{"tags":{"name":"Nahkauf","shop":"supermarket"},"name":"Nahkauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Billa":{"tags":{"name":"Billa","shop":"supermarket"},"name":"Billa","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kaufland":{"tags":{"name":"Kaufland","shop":"supermarket"},"name":"Kaufland","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Plus":{"tags":{"name":"Plus","shop":"supermarket"},"name":"Plus","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ALDI":{"tags":{"name":"ALDI","shop":"supermarket"},"name":"ALDI","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Checkers":{"tags":{"name":"Checkers","shop":"supermarket"},"name":"Checkers","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco Metro":{"tags":{"name":"Tesco Metro","shop":"supermarket"},"name":"Tesco Metro","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/NP":{"tags":{"name":"NP","shop":"supermarket"},"name":"NP","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Penny":{"tags":{"name":"Penny","shop":"supermarket"},"name":"Penny","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Norma":{"tags":{"name":"Norma","shop":"supermarket"},"name":"Norma","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Asda":{"tags":{"name":"Asda","shop":"supermarket"},"name":"Asda","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Netto":{"tags":{"name":"Netto","shop":"supermarket"},"name":"Netto","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Rewe":{"tags":{"name":"Rewe","shop":"supermarket"},"name":"Rewe","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Aldi Süd":{"tags":{"name":"Aldi Süd","shop":"supermarket"},"name":"Aldi Süd","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Real":{"tags":{"name":"Real","shop":"supermarket"},"name":"Real","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/King Soopers":{"tags":{"name":"King Soopers","shop":"supermarket"},"name":"King Soopers","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kiwi":{"tags":{"name":"Kiwi","shop":"supermarket"},"name":"Kiwi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Pick n Pay":{"tags":{"name":"Pick n Pay","shop":"supermarket"},"name":"Pick n Pay","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ICA":{"tags":{"name":"ICA","shop":"supermarket"},"name":"ICA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tengelmann":{"tags":{"name":"Tengelmann","shop":"supermarket"},"name":"Tengelmann","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour":{"tags":{"name":"Carrefour","shop":"supermarket"},"name":"Carrefour","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Waitrose":{"tags":{"name":"Waitrose","shop":"supermarket"},"name":"Waitrose","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Spar":{"tags":{"name":"Spar","shop":"supermarket"},"name":"Spar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hofer":{"tags":{"name":"Hofer","shop":"supermarket"},"name":"Hofer","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/M-Preis":{"tags":{"name":"M-Preis","shop":"supermarket"},"name":"M-Preis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/tegut":{"tags":{"name":"tegut","shop":"supermarket"},"name":"tegut","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sainsbury's Local":{"tags":{"name":"Sainsbury's Local","shop":"supermarket"},"name":"Sainsbury's Local","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/E-Center":{"tags":{"name":"E-Center","shop":"supermarket"},"name":"E-Center","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Aldi Nord":{"tags":{"name":"Aldi Nord","shop":"supermarket"},"name":"Aldi Nord","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/nahkauf":{"tags":{"name":"nahkauf","shop":"supermarket"},"name":"nahkauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Meijer":{"tags":{"name":"Meijer","shop":"supermarket"},"name":"Meijer","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Safeway":{"tags":{"name":"Safeway","shop":"supermarket"},"name":"Safeway","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Costco":{"tags":{"name":"Costco","shop":"supermarket"},"name":"Costco","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Albert":{"tags":{"name":"Albert","shop":"supermarket"},"name":"Albert","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Jumbo":{"tags":{"name":"Jumbo","shop":"supermarket"},"name":"Jumbo","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Shoprite":{"tags":{"name":"Shoprite","shop":"supermarket"},"name":"Shoprite","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/MPreis":{"tags":{"name":"MPreis","shop":"supermarket"},"name":"MPreis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Penny Market":{"tags":{"name":"Penny Market","shop":"supermarket"},"name":"Penny Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco Extra":{"tags":{"name":"Tesco Extra","shop":"supermarket"},"name":"Tesco Extra","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Albert Heijn":{"tags":{"name":"Albert Heijn","shop":"supermarket"},"name":"Albert Heijn","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/IGA":{"tags":{"name":"IGA","shop":"supermarket"},"name":"IGA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Super U":{"tags":{"name":"Super U","shop":"supermarket"},"name":"Super U","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Metro":{"tags":{"name":"Metro","shop":"supermarket"},"name":"Metro","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Neukauf":{"tags":{"name":"Neukauf","shop":"supermarket"},"name":"Neukauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Migros":{"tags":{"name":"Migros","shop":"supermarket"},"name":"Migros","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Marktkauf":{"tags":{"name":"Marktkauf","shop":"supermarket"},"name":"Marktkauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Delikatesy Centrum":{"tags":{"name":"Delikatesy Centrum","shop":"supermarket"},"name":"Delikatesy Centrum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/C1000":{"tags":{"name":"C1000","shop":"supermarket"},"name":"C1000","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hoogvliet":{"tags":{"name":"Hoogvliet","shop":"supermarket"},"name":"Hoogvliet","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Food Basics":{"tags":{"name":"Food Basics","shop":"supermarket"},"name":"Food Basics","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Casino":{"tags":{"name":"Casino","shop":"supermarket"},"name":"Casino","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Penny Markt":{"tags":{"name":"Penny Markt","shop":"supermarket"},"name":"Penny Markt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Giant":{"tags":{"name":"Giant","shop":"supermarket"},"name":"Giant","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Rema 1000":{"tags":{"name":"Rema 1000","shop":"supermarket"},"name":"Rema 1000","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kaufpark":{"tags":{"name":"Kaufpark","shop":"supermarket"},"name":"Kaufpark","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ALDI SÜD":{"tags":{"name":"ALDI SÜD","shop":"supermarket"},"name":"ALDI SÜD","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Simply Market":{"tags":{"name":"Simply Market","shop":"supermarket"},"name":"Simply Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Konzum":{"tags":{"name":"Konzum","shop":"supermarket"},"name":"Konzum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour Express":{"tags":{"name":"Carrefour Express","shop":"supermarket"},"name":"Carrefour Express","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Eurospar":{"tags":{"name":"Eurospar","shop":"supermarket"},"name":"Eurospar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Mercator":{"tags":{"name":"Mercator","shop":"supermarket"},"name":"Mercator","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Famila":{"tags":{"name":"Famila","shop":"supermarket"},"name":"Famila","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hemköp":{"tags":{"name":"Hemköp","shop":"supermarket"},"name":"Hemköp","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/real,-":{"tags":{"name":"real,-","shop":"supermarket"},"name":"real,-","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Markant":{"tags":{"name":"Markant","shop":"supermarket"},"name":"Markant","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Volg":{"tags":{"name":"Volg","shop":"supermarket"},"name":"Volg","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Leader Price":{"tags":{"name":"Leader Price","shop":"supermarket"},"name":"Leader Price","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Treff 3000":{"tags":{"name":"Treff 3000","shop":"supermarket"},"name":"Treff 3000","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/SuperBrugsen":{"tags":{"name":"SuperBrugsen","shop":"supermarket"},"name":"SuperBrugsen","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kaiser's":{"tags":{"name":"Kaiser's","shop":"supermarket"},"name":"Kaiser's","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/K+K":{"tags":{"name":"K+K","shop":"supermarket"},"name":"K+K","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Unimarkt":{"tags":{"name":"Unimarkt","shop":"supermarket"},"name":"Unimarkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour City":{"tags":{"name":"Carrefour City","shop":"supermarket"},"name":"Carrefour City","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sobeys":{"tags":{"name":"Sobeys","shop":"supermarket"},"name":"Sobeys","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/S-Market":{"tags":{"name":"S-Market","shop":"supermarket"},"name":"S-Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Combi":{"tags":{"name":"Combi","shop":"supermarket"},"name":"Combi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Denner":{"tags":{"name":"Denner","shop":"supermarket"},"name":"Denner","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Konsum":{"tags":{"name":"Konsum","shop":"supermarket"},"name":"Konsum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Franprix":{"tags":{"name":"Franprix","shop":"supermarket"},"name":"Franprix","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Monoprix":{"tags":{"name":"Monoprix","shop":"supermarket"},"name":"Monoprix","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Diska":{"tags":{"name":"Diska","shop":"supermarket"},"name":"Diska","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/PENNY":{"tags":{"name":"PENNY","shop":"supermarket"},"name":"PENNY","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Dia":{"tags":{"name":"Dia","shop":"supermarket"},"name":"Dia","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Giant Eagle":{"tags":{"name":"Giant Eagle","shop":"supermarket"},"name":"Giant Eagle","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/NORMA":{"tags":{"name":"NORMA","shop":"supermarket"},"name":"NORMA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/AD Delhaize":{"tags":{"name":"AD Delhaize","shop":"supermarket"},"name":"AD Delhaize","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Auchan":{"tags":{"name":"Auchan","shop":"supermarket"},"name":"Auchan","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Mercadona":{"tags":{"name":"Mercadona","shop":"supermarket"},"name":"Mercadona","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Consum":{"tags":{"name":"Consum","shop":"supermarket"},"name":"Consum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour Market":{"tags":{"name":"Carrefour Market","shop":"supermarket"},"name":"Carrefour Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Whole Foods":{"tags":{"name":"Whole Foods","shop":"supermarket"},"name":"Whole Foods","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Pam":{"tags":{"name":"Pam","shop":"supermarket"},"name":"Pam","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/sky":{"tags":{"name":"sky","shop":"supermarket"},"name":"sky","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Despar":{"tags":{"name":"Despar","shop":"supermarket"},"name":"Despar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Eroski":{"tags":{"name":"Eroski","shop":"supermarket"},"name":"Eroski","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Maxi":{"tags":{"name":"Maxi","shop":"supermarket"},"name":"Maxi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Colruyt":{"tags":{"name":"Colruyt","shop":"supermarket"},"name":"Colruyt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/The Co-operative":{"tags":{"name":"The Co-operative","shop":"supermarket"},"name":"The Co-operative","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Intermarché":{"tags":{"name":"Intermarché","shop":"supermarket"},"name":"Intermarché","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Delhaize":{"tags":{"name":"Delhaize","shop":"supermarket"},"name":"Delhaize","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/CBA":{"tags":{"name":"CBA","shop":"supermarket"},"name":"CBA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Shopi":{"tags":{"name":"Shopi","shop":"supermarket"},"name":"Shopi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Walmart":{"tags":{"name":"Walmart","shop":"supermarket"},"name":"Walmart","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kroger":{"tags":{"name":"Kroger","shop":"supermarket"},"name":"Kroger","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Albertsons":{"tags":{"name":"Albertsons","shop":"supermarket"},"name":"Albertsons","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Trader Joe's":{"tags":{"name":"Trader Joe's","shop":"supermarket"},"name":"Trader Joe's","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Feneberg":{"tags":{"name":"Feneberg","shop":"supermarket"},"name":"Feneberg","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/denn's Biomarkt":{"tags":{"name":"denn's Biomarkt","shop":"supermarket"},"name":"denn's Biomarkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kvickly":{"tags":{"name":"Kvickly","shop":"supermarket"},"name":"Kvickly","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Makro":{"tags":{"name":"Makro","shop":"supermarket"},"name":"Makro","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Dico":{"tags":{"name":"Dico","shop":"supermarket"},"name":"Dico","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Nah & Frisch":{"tags":{"name":"Nah & Frisch","shop":"supermarket"},"name":"Nah & Frisch","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Champion":{"tags":{"name":"Champion","shop":"supermarket"},"name":"Champion","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ICA Supermarket":{"tags":{"name":"ICA Supermarket","shop":"supermarket"},"name":"ICA Supermarket","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Fakta":{"tags":{"name":"Fakta","shop":"supermarket"},"name":"Fakta","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Магнит":{"tags":{"name":"Магнит","shop":"supermarket"},"name":"Магнит","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Caprabo":{"tags":{"name":"Caprabo","shop":"supermarket"},"name":"Caprabo","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Famiglia Cooperativa":{"tags":{"name":"Famiglia Cooperativa","shop":"supermarket"},"name":"Famiglia Cooperativa","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Народная 7Я семьЯ":{"tags":{"name":"Народная 7Я семьЯ","shop":"supermarket"},"name":"Народная 7Я семьЯ","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Esselunga":{"tags":{"name":"Esselunga","shop":"supermarket"},"name":"Esselunga","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Maxima":{"tags":{"name":"Maxima","shop":"supermarket"},"name":"Maxima","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Wasgau":{"tags":{"name":"Wasgau","shop":"supermarket"},"name":"Wasgau","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Pingo Doce":{"tags":{"name":"Pingo Doce","shop":"supermarket"},"name":"Pingo Doce","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Match":{"tags":{"name":"Match","shop":"supermarket"},"name":"Match","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Profi":{"tags":{"name":"Profi","shop":"supermarket"},"name":"Profi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Lider":{"tags":{"name":"Lider","shop":"supermarket"},"name":"Lider","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Unimarc":{"tags":{"name":"Unimarc","shop":"supermarket"},"name":"Unimarc","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/The Co-operative Food":{"tags":{"name":"The Co-operative Food","shop":"supermarket"},"name":"The Co-operative Food","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Santa Isabel":{"tags":{"name":"Santa Isabel","shop":"supermarket"},"name":"Santa Isabel","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Седьмой континент":{"tags":{"name":"Седьмой континент","shop":"supermarket"},"name":"Седьмой континент","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/HIT":{"tags":{"name":"HIT","shop":"supermarket"},"name":"HIT","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Rimi":{"tags":{"name":"Rimi","shop":"supermarket"},"name":"Rimi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Conad":{"tags":{"name":"Conad","shop":"supermarket"},"name":"Conad","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Фуршет":{"tags":{"name":"Фуршет","shop":"supermarket"},"name":"Фуршет","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Willys":{"tags":{"name":"Willys","shop":"supermarket"},"name":"Willys","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Farmfoods":{"tags":{"name":"Farmfoods","shop":"supermarket"},"name":"Farmfoods","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/U Express":{"tags":{"name":"U Express","shop":"supermarket"},"name":"U Express","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Фора":{"tags":{"name":"Фора","shop":"supermarket"},"name":"Фора","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Dunnes Stores":{"tags":{"name":"Dunnes Stores","shop":"supermarket"},"name":"Dunnes Stores","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Сільпо":{"tags":{"name":"Сільпо","shop":"supermarket"},"name":"Сільпо","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/マルエツ":{"tags":{"name":"マルエツ","shop":"supermarket"},"name":"マルエツ","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Piggly Wiggly":{"tags":{"name":"Piggly Wiggly","shop":"supermarket"},"name":"Piggly Wiggly","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Crai":{"tags":{"name":"Crai","shop":"supermarket"},"name":"Crai","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/El Árbol":{"tags":{"name":"El Árbol","shop":"supermarket"},"name":"El Árbol","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Centre Commercial E. Leclerc":{"tags":{"name":"Centre Commercial E. Leclerc","shop":"supermarket"},"name":"Centre Commercial E. Leclerc","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Foodland":{"tags":{"name":"Foodland","shop":"supermarket"},"name":"Foodland","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Super Brugsen":{"tags":{"name":"Super Brugsen","shop":"supermarket"},"name":"Super Brugsen","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Дикси":{"tags":{"name":"Дикси","shop":"supermarket"},"name":"Дикси","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Пятёрочка":{"tags":{"name":"Пятёрочка","shop":"supermarket"},"name":"Пятёрочка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Publix":{"tags":{"name":"Publix","shop":"supermarket"},"name":"Publix","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Føtex":{"tags":{"name":"Føtex","shop":"supermarket"},"name":"Føtex","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/coop":{"tags":{"name":"coop","shop":"supermarket"},"name":"coop","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coop Konsum":{"tags":{"name":"Coop Konsum","shop":"supermarket"},"name":"Coop Konsum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour Contact":{"tags":{"name":"Carrefour Contact","shop":"supermarket"},"name":"Carrefour Contact","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/No Frills":{"tags":{"name":"No Frills","shop":"supermarket"},"name":"No Frills","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Plodine":{"tags":{"name":"Plodine","shop":"supermarket"},"name":"Plodine","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ADEG":{"tags":{"name":"ADEG","shop":"supermarket"},"name":"ADEG","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Minipreço":{"tags":{"name":"Minipreço","shop":"supermarket"},"name":"Minipreço","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Biedronka":{"tags":{"name":"Biedronka","shop":"supermarket"},"name":"Biedronka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Eurospin":{"tags":{"name":"Eurospin","shop":"supermarket"},"name":"Eurospin","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Семья":{"tags":{"name":"Семья","shop":"supermarket"},"name":"Семья","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Gadis":{"tags":{"name":"Gadis","shop":"supermarket"},"name":"Gadis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Евроопт":{"tags":{"name":"Евроопт","shop":"supermarket"},"name":"Евроопт","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Квартал":{"tags":{"name":"Квартал","shop":"supermarket"},"name":"Квартал","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/New World":{"tags":{"name":"New World","shop":"supermarket"},"name":"New World","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Countdown":{"tags":{"name":"Countdown","shop":"supermarket"},"name":"Countdown","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Reliance Fresh":{"tags":{"name":"Reliance Fresh","shop":"supermarket"},"name":"Reliance Fresh","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Stokrotka":{"tags":{"name":"Stokrotka","shop":"supermarket"},"name":"Stokrotka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coop Jednota":{"tags":{"name":"Coop Jednota","shop":"supermarket"},"name":"Coop Jednota","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Fred Meyer":{"tags":{"name":"Fred Meyer","shop":"supermarket"},"name":"Fred Meyer","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Irma":{"tags":{"name":"Irma","shop":"supermarket"},"name":"Irma","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Continente":{"tags":{"name":"Continente","shop":"supermarket"},"name":"Continente","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Price Chopper":{"tags":{"name":"Price Chopper","shop":"supermarket"},"name":"Price Chopper","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Game":{"tags":{"name":"Game","shop":"supermarket"},"name":"Game","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Soriana":{"tags":{"name":"Soriana","shop":"supermarket"},"name":"Soriana","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Alimerka":{"tags":{"name":"Alimerka","shop":"supermarket"},"name":"Alimerka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Piotr i Paweł":{"tags":{"name":"Piotr i Paweł","shop":"supermarket"},"name":"Piotr i Paweł","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Перекресток":{"tags":{"name":"Перекресток","shop":"supermarket"},"name":"Перекресток","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Maxima X":{"tags":{"name":"Maxima X","shop":"supermarket"},"name":"Maxima X","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Карусель":{"tags":{"name":"Карусель","shop":"supermarket"},"name":"Карусель","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ALDI Nord":{"tags":{"name":"ALDI Nord","shop":"supermarket"},"name":"ALDI Nord","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Condis":{"tags":{"name":"Condis","shop":"supermarket"},"name":"Condis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sam's Club":{"tags":{"name":"Sam's Club","shop":"supermarket"},"name":"Sam's Club","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Копейка":{"tags":{"name":"Копейка","shop":"supermarket"},"name":"Копейка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Géant Casino":{"tags":{"name":"Géant Casino","shop":"supermarket"},"name":"Géant Casino","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ASDA":{"tags":{"name":"ASDA","shop":"supermarket"},"name":"ASDA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Intermarche":{"tags":{"name":"Intermarche","shop":"supermarket"},"name":"Intermarche","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Stop & Shop":{"tags":{"name":"Stop & Shop","shop":"supermarket"},"name":"Stop & Shop","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Food Lion":{"tags":{"name":"Food Lion","shop":"supermarket"},"name":"Food Lion","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Harris Teeter":{"tags":{"name":"Harris Teeter","shop":"supermarket"},"name":"Harris Teeter","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Foodworks":{"tags":{"name":"Foodworks","shop":"supermarket"},"name":"Foodworks","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Polo Market":{"tags":{"name":"Polo Market","shop":"supermarket"},"name":"Polo Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Лента":{"tags":{"name":"Лента","shop":"supermarket"},"name":"Лента","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/西友 (SEIYU)":{"tags":{"name":"西友 (SEIYU)","shop":"supermarket"},"name":"西友 (SEIYU)","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/H-E-B":{"tags":{"name":"H-E-B","shop":"supermarket"},"name":"H-E-B","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Атак":{"tags":{"name":"Атак","shop":"supermarket"},"name":"Атак","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Полушка":{"tags":{"name":"Полушка","shop":"supermarket"},"name":"Полушка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Extra":{"tags":{"name":"Extra","shop":"supermarket"},"name":"Extra","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sigma":{"tags":{"name":"Sigma","shop":"supermarket"},"name":"Sigma","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/АТБ":{"tags":{"name":"АТБ","shop":"supermarket"},"name":"АТБ","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Bodega Aurrera":{"tags":{"name":"Bodega Aurrera","shop":"supermarket"},"name":"Bodega Aurrera","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco Lotus":{"tags":{"name":"Tesco Lotus","shop":"supermarket"},"name":"Tesco Lotus","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Мария-Ра":{"tags":{"name":"Мария-Ра","shop":"supermarket"},"name":"Мария-Ра","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Магнолия":{"tags":{"name":"Магнолия","shop":"supermarket"},"name":"Магнолия","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Монетка":{"tags":{"name":"Монетка","shop":"supermarket"},"name":"Монетка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hy-Vee":{"tags":{"name":"Hy-Vee","shop":"supermarket"},"name":"Hy-Vee","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Walmart Supercenter":{"tags":{"name":"Walmart Supercenter","shop":"supermarket"},"name":"Walmart Supercenter","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hannaford":{"tags":{"name":"Hannaford","shop":"supermarket"},"name":"Hannaford","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Wegmans":{"tags":{"name":"Wegmans","shop":"supermarket"},"name":"Wegmans","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/業務スーパー":{"tags":{"name":"業務スーパー","shop":"supermarket"},"name":"業務スーパー","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Norfa XL":{"tags":{"name":"Norfa XL","shop":"supermarket"},"name":"Norfa XL","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ヨークマート (YorkMart)":{"tags":{"name":"ヨークマート (YorkMart)","shop":"supermarket"},"name":"ヨークマート (YorkMart)","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Leclerc Drive":{"tags":{"name":"Leclerc Drive","shop":"supermarket"},"name":"Leclerc Drive","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Media Markt":{"tags":{"name":"Media Markt","shop":"electronics"},"name":"Media Markt","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Maplin":{"tags":{"name":"Maplin","shop":"electronics"},"name":"Maplin","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Best Buy":{"tags":{"name":"Best Buy","shop":"electronics"},"name":"Best Buy","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Future Shop":{"tags":{"name":"Future Shop","shop":"electronics"},"name":"Future Shop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Saturn":{"tags":{"name":"Saturn","shop":"electronics"},"name":"Saturn","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Currys":{"tags":{"name":"Currys","shop":"electronics"},"name":"Currys","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Radio Shack":{"tags":{"name":"Radio Shack","shop":"electronics"},"name":"Radio Shack","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Euronics":{"tags":{"name":"Euronics","shop":"electronics"},"name":"Euronics","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Expert":{"tags":{"name":"Expert","shop":"electronics"},"name":"Expert","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Эльдорадо":{"tags":{"name":"Эльдорадо","shop":"electronics"},"name":"Эльдорадо","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Darty":{"tags":{"name":"Darty","shop":"electronics"},"name":"Darty","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/М.Видео":{"tags":{"name":"М.Видео","shop":"electronics"},"name":"М.Видео","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/ヤマダ電機":{"tags":{"name":"ヤマダ電機","shop":"electronics"},"name":"ヤマダ電機","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/McColl's":{"tags":{"name":"McColl's","shop":"convenience"},"name":"McColl's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Tesco Express":{"tags":{"name":"Tesco Express","shop":"convenience"},"name":"Tesco Express","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/One Stop":{"tags":{"name":"One Stop","shop":"convenience"},"name":"One Stop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Londis":{"tags":{"name":"Londis","shop":"convenience"},"name":"Londis","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/7-Eleven":{"tags":{"name":"7-Eleven","shop":"convenience"},"name":"7-Eleven","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Sale":{"tags":{"name":"Sale","shop":"convenience"},"name":"Sale","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Siwa":{"tags":{"name":"Siwa","shop":"convenience"},"name":"Siwa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/COOP Jednota":{"tags":{"name":"COOP Jednota","shop":"convenience"},"name":"COOP Jednota","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mac's":{"tags":{"name":"Mac's","shop":"convenience"},"name":"Mac's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Alepa":{"tags":{"name":"Alepa","shop":"convenience"},"name":"Alepa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Hasty Market":{"tags":{"name":"Hasty Market","shop":"convenience"},"name":"Hasty Market","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/K-Market":{"tags":{"name":"K-Market","shop":"convenience"},"name":"K-Market","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Costcutter":{"tags":{"name":"Costcutter","shop":"convenience"},"name":"Costcutter","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Valintatalo":{"tags":{"name":"Valintatalo","shop":"convenience"},"name":"Valintatalo","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Circle K":{"tags":{"name":"Circle K","shop":"convenience"},"name":"Circle K","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/セブンイレブン":{"tags":{"name":"セブンイレブン","name:en":"7-Eleven","shop":"convenience"},"name":"セブンイレブン","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ローソン":{"tags":{"name":"ローソン","name:en":"LAWSON","shop":"convenience"},"name":"ローソン","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Petit Casino":{"tags":{"name":"Petit Casino","shop":"convenience"},"name":"Petit Casino","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mace":{"tags":{"name":"Mace","shop":"convenience"},"name":"Mace","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mini Market":{"tags":{"name":"Mini Market","shop":"convenience"},"name":"Mini Market","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Nisa Local":{"tags":{"name":"Nisa Local","shop":"convenience"},"name":"Nisa Local","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Dorfladen":{"tags":{"name":"Dorfladen","shop":"convenience"},"name":"Dorfladen","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продукты":{"tags":{"name":"Продукты","shop":"convenience"},"name":"Продукты","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mini Stop":{"tags":{"name":"Mini Stop","shop":"convenience"},"name":"Mini Stop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/LAWSON":{"tags":{"name":"LAWSON","shop":"convenience"},"name":"LAWSON","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/デイリーヤマザキ":{"tags":{"name":"デイリーヤマザキ","shop":"convenience"},"name":"デイリーヤマザキ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Надежда":{"tags":{"name":"Надежда","shop":"convenience"},"name":"Надежда","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Nisa":{"tags":{"name":"Nisa","shop":"convenience"},"name":"Nisa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Premier":{"tags":{"name":"Premier","shop":"convenience"},"name":"Premier","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ABC":{"tags":{"name":"ABC","shop":"convenience"},"name":"ABC","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ミニストップ":{"tags":{"name":"ミニストップ","name:en":"MINISTOP","shop":"convenience"},"name":"ミニストップ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/サンクス":{"tags":{"name":"サンクス","name:en":"sunkus","shop":"convenience"},"name":"サンクス","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/スリーエフ":{"tags":{"name":"スリーエフ","shop":"convenience"},"name":"スリーエフ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/8 à Huit":{"tags":{"name":"8 à Huit","shop":"convenience"},"name":"8 à Huit","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Żabka":{"tags":{"name":"Żabka","shop":"convenience"},"name":"Żabka","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Almacen":{"tags":{"name":"Almacen","shop":"convenience"},"name":"Almacen","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Vival":{"tags":{"name":"Vival","shop":"convenience"},"name":"Vival","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/FamilyMart":{"tags":{"name":"FamilyMart","shop":"convenience"},"name":"FamilyMart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ファミリーマート":{"tags":{"name":"ファミリーマート","name:en":"FamilyMart","shop":"convenience"},"name":"ファミリーマート","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Sunkus":{"tags":{"name":"Sunkus","shop":"convenience"},"name":"Sunkus","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/セブンイレブン(Seven-Eleven)":{"tags":{"name":"セブンイレブン(Seven-Eleven)","shop":"convenience"},"name":"セブンイレブン(Seven-Eleven)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Jednota":{"tags":{"name":"Jednota","shop":"convenience"},"name":"Jednota","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Магазин":{"tags":{"name":"Магазин","shop":"convenience"},"name":"Магазин","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Гастроном":{"tags":{"name":"Гастроном","shop":"convenience"},"name":"Гастроном","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Centra":{"tags":{"name":"Centra","shop":"convenience"},"name":"Centra","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/サークルK":{"tags":{"name":"サークルK","name:en":"Circle K","shop":"convenience"},"name":"サークルK","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Wawa":{"tags":{"name":"Wawa","shop":"convenience"},"name":"Wawa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Proxi":{"tags":{"name":"Proxi","shop":"convenience"},"name":"Proxi","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Универсам":{"tags":{"name":"Универсам","shop":"convenience"},"name":"Универсам","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Groszek":{"tags":{"name":"Groszek","shop":"convenience"},"name":"Groszek","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Select":{"tags":{"name":"Select","shop":"convenience"},"name":"Select","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Večerka":{"tags":{"name":"Večerka","shop":"convenience"},"name":"Večerka","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Potraviny":{"tags":{"name":"Potraviny","shop":"convenience"},"name":"Potraviny","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Смак":{"tags":{"name":"Смак","shop":"convenience"},"name":"Смак","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Эконом":{"tags":{"name":"Эконом","shop":"convenience"},"name":"Эконом","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Березка":{"tags":{"name":"Березка","shop":"convenience"},"name":"Березка","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Społem":{"tags":{"name":"Społem","shop":"convenience"},"name":"Społem","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Cumberland Farms":{"tags":{"name":"Cumberland Farms","shop":"convenience"},"name":"Cumberland Farms","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Tesco Lotus Express":{"tags":{"name":"Tesco Lotus Express","shop":"convenience"},"name":"Tesco Lotus Express","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Kiosk":{"tags":{"name":"Kiosk","shop":"convenience"},"name":"Kiosk","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Sklep spożywczy":{"tags":{"name":"Sklep spożywczy","shop":"convenience"},"name":"Sklep spożywczy","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/24 часа":{"tags":{"name":"24 часа","shop":"convenience"},"name":"24 часа","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Минимаркет":{"tags":{"name":"Минимаркет","shop":"convenience"},"name":"Минимаркет","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Oxxo":{"tags":{"name":"Oxxo","shop":"convenience"},"name":"Oxxo","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/abc":{"tags":{"name":"abc","shop":"convenience"},"name":"abc","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/7/11":{"tags":{"name":"7/11","shop":"convenience"},"name":"7/11","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Stewart's":{"tags":{"name":"Stewart's","shop":"convenience"},"name":"Stewart's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продукти":{"tags":{"name":"Продукти","shop":"convenience"},"name":"Продукти","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ローソンストア100 (LAWSON STORE 100)":{"tags":{"name":"ローソンストア100 (LAWSON STORE 100)","shop":"convenience"},"name":"ローソンストア100 (LAWSON STORE 100)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Радуга":{"tags":{"name":"Радуга","shop":"convenience"},"name":"Радуга","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ローソンストア100":{"tags":{"name":"ローソンストア100","shop":"convenience"},"name":"ローソンストア100","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/เซเว่นอีเลฟเว่น":{"tags":{"name":"เซเว่นอีเลฟเว่น","shop":"convenience"},"name":"เซเว่นอีเลฟเว่น","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Фортуна":{"tags":{"name":"Фортуна","shop":"convenience"},"name":"Фортуна","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Picard":{"tags":{"name":"Picard","shop":"convenience"},"name":"Picard","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Four Square":{"tags":{"name":"Four Square","shop":"convenience"},"name":"Four Square","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Визит":{"tags":{"name":"Визит","shop":"convenience"},"name":"Визит","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Авоська":{"tags":{"name":"Авоська","shop":"convenience"},"name":"Авоська","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Dollar General":{"tags":{"name":"Dollar General","shop":"convenience"},"name":"Dollar General","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Studenac":{"tags":{"name":"Studenac","shop":"convenience"},"name":"Studenac","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Central Convenience Store":{"tags":{"name":"Central Convenience Store","shop":"convenience"},"name":"Central Convenience Store","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/продукты":{"tags":{"name":"продукты","shop":"convenience"},"name":"продукты","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Кулинария":{"tags":{"name":"Кулинария","shop":"convenience"},"name":"Кулинария","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/全家":{"tags":{"name":"全家","shop":"convenience"},"name":"全家","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Мечта":{"tags":{"name":"Мечта","shop":"convenience"},"name":"Мечта","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Epicerie":{"tags":{"name":"Epicerie","shop":"convenience"},"name":"Epicerie","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Кировский":{"tags":{"name":"Кировский","shop":"convenience"},"name":"Кировский","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Food Mart":{"tags":{"name":"Food Mart","shop":"convenience"},"name":"Food Mart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Delikatesy":{"tags":{"name":"Delikatesy","shop":"convenience"},"name":"Delikatesy","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ポプラ":{"tags":{"name":"ポプラ","shop":"convenience"},"name":"ポプラ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Lewiatan":{"tags":{"name":"Lewiatan","shop":"convenience"},"name":"Lewiatan","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продуктовый магазин":{"tags":{"name":"Продуктовый магазин","shop":"convenience"},"name":"Продуктовый магазин","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продуктовый":{"tags":{"name":"Продуктовый","shop":"convenience"},"name":"Продуктовый","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/セイコーマート (Seicomart)":{"tags":{"name":"セイコーマート (Seicomart)","shop":"convenience"},"name":"セイコーマート (Seicomart)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Виктория":{"tags":{"name":"Виктория","shop":"convenience"},"name":"Виктория","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Весна":{"tags":{"name":"Весна","shop":"convenience"},"name":"Весна","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mini Market Non-Stop":{"tags":{"name":"Mini Market Non-Stop","shop":"convenience"},"name":"Mini Market Non-Stop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Копеечка":{"tags":{"name":"Копеечка","shop":"convenience"},"name":"Копеечка","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Royal Farms":{"tags":{"name":"Royal Farms","shop":"convenience"},"name":"Royal Farms","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Alfamart":{"tags":{"name":"Alfamart","shop":"convenience"},"name":"Alfamart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Indomaret":{"tags":{"name":"Indomaret","shop":"convenience"},"name":"Indomaret","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/магазин":{"tags":{"name":"магазин","shop":"convenience"},"name":"магазин","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/全家便利商店":{"tags":{"name":"全家便利商店","shop":"convenience"},"name":"全家便利商店","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Boutique":{"tags":{"name":"Boutique","shop":"convenience"},"name":"Boutique","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/მარკეტი (Market)":{"tags":{"name":"მარკეტი (Market)","shop":"convenience"},"name":"მარკეტი (Market)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Stores":{"tags":{"name":"Stores","shop":"convenience"},"name":"Stores","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/dm":{"tags":{"name":"dm","shop":"chemist"},"name":"dm","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Müller":{"tags":{"name":"Müller","shop":"chemist"},"name":"Müller","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Schlecker":{"tags":{"name":"Schlecker","shop":"chemist"},"name":"Schlecker","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Etos":{"tags":{"name":"Etos","shop":"chemist"},"name":"Etos","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Bipa":{"tags":{"name":"Bipa","shop":"chemist"},"name":"Bipa","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Rossmann":{"tags":{"name":"Rossmann","shop":"chemist"},"name":"Rossmann","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/DM Drogeriemarkt":{"tags":{"name":"DM Drogeriemarkt","shop":"chemist"},"name":"DM Drogeriemarkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Ihr Platz":{"tags":{"name":"Ihr Platz","shop":"chemist"},"name":"Ihr Platz","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Douglas":{"tags":{"name":"Douglas","shop":"chemist"},"name":"Douglas","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Kruidvat":{"tags":{"name":"Kruidvat","shop":"chemist"},"name":"Kruidvat","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/car_repair/Kwik Fit":{"tags":{"name":"Kwik Fit","shop":"car_repair"},"name":"Kwik Fit","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/ATU":{"tags":{"name":"ATU","shop":"car_repair"},"name":"ATU","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Midas":{"tags":{"name":"Midas","shop":"car_repair"},"name":"Midas","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Feu Vert":{"tags":{"name":"Feu Vert","shop":"car_repair"},"name":"Feu Vert","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Norauto":{"tags":{"name":"Norauto","shop":"car_repair"},"name":"Norauto","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Speedy":{"tags":{"name":"Speedy","shop":"car_repair"},"name":"Speedy","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Pit Stop":{"tags":{"name":"Pit Stop","shop":"car_repair"},"name":"Pit Stop","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Jiffy Lube":{"tags":{"name":"Jiffy Lube","shop":"car_repair"},"name":"Jiffy Lube","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Шиномонтаж":{"tags":{"name":"Шиномонтаж","shop":"car_repair"},"name":"Шиномонтаж","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/СТО":{"tags":{"name":"СТО","shop":"car_repair"},"name":"СТО","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/O'Reilly Auto Parts":{"tags":{"name":"O'Reilly Auto Parts","shop":"car_repair"},"name":"O'Reilly Auto Parts","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Carglass":{"tags":{"name":"Carglass","shop":"car_repair"},"name":"Carglass","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/шиномонтаж":{"tags":{"name":"шиномонтаж","shop":"car_repair"},"name":"шиномонтаж","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Euromaster":{"tags":{"name":"Euromaster","shop":"car_repair"},"name":"Euromaster","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Firestone":{"tags":{"name":"Firestone","shop":"car_repair"},"name":"Firestone","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Автосервис":{"tags":{"name":"Автосервис","shop":"car_repair"},"name":"Автосервис","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Advance Auto Parts":{"tags":{"name":"Advance Auto Parts","shop":"car_repair"},"name":"Advance Auto Parts","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Roady":{"tags":{"name":"Roady","shop":"car_repair"},"name":"Roady","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/furniture/IKEA":{"tags":{"name":"IKEA","shop":"furniture"},"name":"IKEA","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Jysk":{"tags":{"name":"Jysk","shop":"furniture"},"name":"Jysk","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Roller":{"tags":{"name":"Roller","shop":"furniture"},"name":"Roller","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Dänisches Bettenlager":{"tags":{"name":"Dänisches Bettenlager","shop":"furniture"},"name":"Dänisches Bettenlager","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Conforama":{"tags":{"name":"Conforama","shop":"furniture"},"name":"Conforama","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Matratzen Concord":{"tags":{"name":"Matratzen Concord","shop":"furniture"},"name":"Matratzen Concord","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Мебель":{"tags":{"name":"Мебель","shop":"furniture"},"name":"Мебель","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/But":{"tags":{"name":"But","shop":"furniture"},"name":"But","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hornbach":{"tags":{"name":"Hornbach","shop":"doityourself"},"name":"Hornbach","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/B&Q":{"tags":{"name":"B&Q","shop":"doityourself"},"name":"B&Q","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hubo":{"tags":{"name":"Hubo","shop":"doityourself"},"name":"Hubo","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Mr Bricolage":{"tags":{"name":"Mr Bricolage","shop":"doityourself"},"name":"Mr Bricolage","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Gamma":{"tags":{"name":"Gamma","shop":"doityourself"},"name":"Gamma","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/OBI":{"tags":{"name":"OBI","shop":"doityourself"},"name":"OBI","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Lowes":{"tags":{"name":"Lowes","shop":"doityourself"},"name":"Lowes","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Wickes":{"tags":{"name":"Wickes","shop":"doityourself"},"name":"Wickes","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hagebau":{"tags":{"name":"Hagebau","shop":"doityourself"},"name":"Hagebau","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Max Bahr":{"tags":{"name":"Max Bahr","shop":"doityourself"},"name":"Max Bahr","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Castorama":{"tags":{"name":"Castorama","shop":"doityourself"},"name":"Castorama","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Rona":{"tags":{"name":"Rona","shop":"doityourself"},"name":"Rona","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Home Depot":{"tags":{"name":"Home Depot","shop":"doityourself"},"name":"Home Depot","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Toom Baumarkt":{"tags":{"name":"Toom Baumarkt","shop":"doityourself"},"name":"Toom Baumarkt","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Homebase":{"tags":{"name":"Homebase","shop":"doityourself"},"name":"Homebase","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Baumax":{"tags":{"name":"Baumax","shop":"doityourself"},"name":"Baumax","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Lagerhaus":{"tags":{"name":"Lagerhaus","shop":"doityourself"},"name":"Lagerhaus","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bauhaus":{"tags":{"name":"Bauhaus","shop":"doityourself"},"name":"Bauhaus","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Canadian Tire":{"tags":{"name":"Canadian Tire","shop":"doityourself"},"name":"Canadian Tire","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Leroy Merlin":{"tags":{"name":"Leroy Merlin","shop":"doityourself"},"name":"Leroy Merlin","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hellweg":{"tags":{"name":"Hellweg","shop":"doityourself"},"name":"Hellweg","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Brico":{"tags":{"name":"Brico","shop":"doityourself"},"name":"Brico","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bricomarché":{"tags":{"name":"Bricomarché","shop":"doityourself"},"name":"Bricomarché","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Toom":{"tags":{"name":"Toom","shop":"doityourself"},"name":"Toom","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hagebaumarkt":{"tags":{"name":"Hagebaumarkt","shop":"doityourself"},"name":"Hagebaumarkt","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Praktiker":{"tags":{"name":"Praktiker","shop":"doityourself"},"name":"Praktiker","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Menards":{"tags":{"name":"Menards","shop":"doityourself"},"name":"Menards","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Weldom":{"tags":{"name":"Weldom","shop":"doityourself"},"name":"Weldom","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bunnings Warehouse":{"tags":{"name":"Bunnings Warehouse","shop":"doityourself"},"name":"Bunnings Warehouse","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Ace Hardware":{"tags":{"name":"Ace Hardware","shop":"doityourself"},"name":"Ace Hardware","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Home Hardware":{"tags":{"name":"Home Hardware","shop":"doityourself"},"name":"Home Hardware","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Стройматериалы":{"tags":{"name":"Стройматериалы","shop":"doityourself"},"name":"Стройматериалы","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bricorama":{"tags":{"name":"Bricorama","shop":"doityourself"},"name":"Bricorama","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Point P":{"tags":{"name":"Point P","shop":"doityourself"},"name":"Point P","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/Staples":{"tags":{"name":"Staples","shop":"stationery"},"name":"Staples","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/McPaper":{"tags":{"name":"McPaper","shop":"stationery"},"name":"McPaper","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/Office Depot":{"tags":{"name":"Office Depot","shop":"stationery"},"name":"Office Depot","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/Канцтовары":{"tags":{"name":"Канцтовары","shop":"stationery"},"name":"Канцтовары","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/car/Skoda":{"tags":{"name":"Skoda","shop":"car"},"name":"Skoda","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/BMW":{"tags":{"name":"BMW","shop":"car"},"name":"BMW","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Citroen":{"tags":{"name":"Citroen","shop":"car"},"name":"Citroen","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Renault":{"tags":{"name":"Renault","shop":"car"},"name":"Renault","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Mercedes-Benz":{"tags":{"name":"Mercedes-Benz","shop":"car"},"name":"Mercedes-Benz","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Volvo":{"tags":{"name":"Volvo","shop":"car"},"name":"Volvo","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Ford":{"tags":{"name":"Ford","shop":"car"},"name":"Ford","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Volkswagen":{"tags":{"name":"Volkswagen","shop":"car"},"name":"Volkswagen","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Mazda":{"tags":{"name":"Mazda","shop":"car"},"name":"Mazda","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Mitsubishi":{"tags":{"name":"Mitsubishi","shop":"car"},"name":"Mitsubishi","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Fiat":{"tags":{"name":"Fiat","shop":"car"},"name":"Fiat","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Автозапчасти":{"tags":{"name":"Автозапчасти","shop":"car"},"name":"Автозапчасти","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Opel":{"tags":{"name":"Opel","shop":"car"},"name":"Opel","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Audi":{"tags":{"name":"Audi","shop":"car"},"name":"Audi","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Toyota":{"tags":{"name":"Toyota","shop":"car"},"name":"Toyota","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Nissan":{"tags":{"name":"Nissan","shop":"car"},"name":"Nissan","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Suzuki":{"tags":{"name":"Suzuki","shop":"car"},"name":"Suzuki","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Honda":{"tags":{"name":"Honda","shop":"car"},"name":"Honda","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Peugeot":{"tags":{"name":"Peugeot","shop":"car"},"name":"Peugeot","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Hyundai":{"tags":{"name":"Hyundai","shop":"car"},"name":"Hyundai","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Subaru":{"tags":{"name":"Subaru","shop":"car"},"name":"Subaru","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Chevrolet":{"tags":{"name":"Chevrolet","shop":"car"},"name":"Chevrolet","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Автомагазин":{"tags":{"name":"Автомагазин","shop":"car"},"name":"Автомагазин","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/clothes/Matalan":{"tags":{"name":"Matalan","shop":"clothes"},"name":"Matalan","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/KiK":{"tags":{"name":"KiK","shop":"clothes"},"name":"KiK","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/H&M":{"tags":{"name":"H&M","shop":"clothes"},"name":"H&M","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Urban Outfitters":{"tags":{"name":"Urban Outfitters","shop":"clothes"},"name":"Urban Outfitters","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Vögele":{"tags":{"name":"Vögele","shop":"clothes"},"name":"Vögele","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Zeeman":{"tags":{"name":"Zeeman","shop":"clothes"},"name":"Zeeman","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Takko":{"tags":{"name":"Takko","shop":"clothes"},"name":"Takko","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/C&A":{"tags":{"name":"C&A","shop":"clothes"},"name":"C&A","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Zara":{"tags":{"name":"Zara","shop":"clothes"},"name":"Zara","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Vero Moda":{"tags":{"name":"Vero Moda","shop":"clothes"},"name":"Vero Moda","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/NKD":{"tags":{"name":"NKD","shop":"clothes"},"name":"NKD","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ernsting's family":{"tags":{"name":"Ernsting's family","shop":"clothes"},"name":"Ernsting's family","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Winners":{"tags":{"name":"Winners","shop":"clothes"},"name":"Winners","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/River Island":{"tags":{"name":"River Island","shop":"clothes"},"name":"River Island","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Next":{"tags":{"name":"Next","shop":"clothes"},"name":"Next","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Gap":{"tags":{"name":"Gap","shop":"clothes"},"name":"Gap","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Adidas":{"tags":{"name":"Adidas","shop":"clothes"},"name":"Adidas","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Mr Price":{"tags":{"name":"Mr Price","shop":"clothes"},"name":"Mr Price","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Pep":{"tags":{"name":"Pep","shop":"clothes"},"name":"Pep","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Edgars":{"tags":{"name":"Edgars","shop":"clothes"},"name":"Edgars","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ackermans":{"tags":{"name":"Ackermans","shop":"clothes"},"name":"Ackermans","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Truworths":{"tags":{"name":"Truworths","shop":"clothes"},"name":"Truworths","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ross":{"tags":{"name":"Ross","shop":"clothes"},"name":"Ross","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Burton":{"tags":{"name":"Burton","shop":"clothes"},"name":"Burton","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Dorothy Perkins":{"tags":{"name":"Dorothy Perkins","shop":"clothes"},"name":"Dorothy Perkins","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Lindex":{"tags":{"name":"Lindex","shop":"clothes"},"name":"Lindex","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/s.Oliver":{"tags":{"name":"s.Oliver","shop":"clothes"},"name":"s.Oliver","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Cecil":{"tags":{"name":"Cecil","shop":"clothes"},"name":"Cecil","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Dress Barn":{"tags":{"name":"Dress Barn","shop":"clothes"},"name":"Dress Barn","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Old Navy":{"tags":{"name":"Old Navy","shop":"clothes"},"name":"Old Navy","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jack & Jones":{"tags":{"name":"Jack & Jones","shop":"clothes"},"name":"Jack & Jones","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Pimkie":{"tags":{"name":"Pimkie","shop":"clothes"},"name":"Pimkie","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Esprit":{"tags":{"name":"Esprit","shop":"clothes"},"name":"Esprit","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Primark":{"tags":{"name":"Primark","shop":"clothes"},"name":"Primark","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Bonita":{"tags":{"name":"Bonita","shop":"clothes"},"name":"Bonita","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Mexx":{"tags":{"name":"Mexx","shop":"clothes"},"name":"Mexx","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Gerry Weber":{"tags":{"name":"Gerry Weber","shop":"clothes"},"name":"Gerry Weber","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Tally Weijl":{"tags":{"name":"Tally Weijl","shop":"clothes"},"name":"Tally Weijl","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Mango":{"tags":{"name":"Mango","shop":"clothes"},"name":"Mango","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/TK Maxx":{"tags":{"name":"TK Maxx","shop":"clothes"},"name":"TK Maxx","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Benetton":{"tags":{"name":"Benetton","shop":"clothes"},"name":"Benetton","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ulla Popken":{"tags":{"name":"Ulla Popken","shop":"clothes"},"name":"Ulla Popken","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/AWG":{"tags":{"name":"AWG","shop":"clothes"},"name":"AWG","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Tommy Hilfiger":{"tags":{"name":"Tommy Hilfiger","shop":"clothes"},"name":"Tommy Hilfiger","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/New Yorker":{"tags":{"name":"New Yorker","shop":"clothes"},"name":"New Yorker","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Orsay":{"tags":{"name":"Orsay","shop":"clothes"},"name":"Orsay","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jeans Fritz":{"tags":{"name":"Jeans Fritz","shop":"clothes"},"name":"Jeans Fritz","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Charles Vögele":{"tags":{"name":"Charles Vögele","shop":"clothes"},"name":"Charles Vögele","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/New Look":{"tags":{"name":"New Look","shop":"clothes"},"name":"New Look","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Lacoste":{"tags":{"name":"Lacoste","shop":"clothes"},"name":"Lacoste","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Etam":{"tags":{"name":"Etam","shop":"clothes"},"name":"Etam","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Kiabi":{"tags":{"name":"Kiabi","shop":"clothes"},"name":"Kiabi","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jack Wolfskin":{"tags":{"name":"Jack Wolfskin","shop":"clothes"},"name":"Jack Wolfskin","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/American Apparel":{"tags":{"name":"American Apparel","shop":"clothes"},"name":"American Apparel","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Men's Wearhouse":{"tags":{"name":"Men's Wearhouse","shop":"clothes"},"name":"Men's Wearhouse","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Intimissimi":{"tags":{"name":"Intimissimi","shop":"clothes"},"name":"Intimissimi","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/United Colors of Benetton":{"tags":{"name":"United Colors of Benetton","shop":"clothes"},"name":"United Colors of Benetton","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jules":{"tags":{"name":"Jules","shop":"clothes"},"name":"Jules","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Second Hand":{"tags":{"name":"Second Hand","shop":"clothes"},"name":"Second Hand","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/AOKI":{"tags":{"name":"AOKI","shop":"clothes"},"name":"AOKI","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Calzedonia":{"tags":{"name":"Calzedonia","shop":"clothes"},"name":"Calzedonia","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/洋服の青山":{"tags":{"name":"洋服の青山","shop":"clothes"},"name":"洋服の青山","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Levi's":{"tags":{"name":"Levi's","shop":"clothes"},"name":"Levi's","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Celio":{"tags":{"name":"Celio","shop":"clothes"},"name":"Celio","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/TJ Maxx":{"tags":{"name":"TJ Maxx","shop":"clothes"},"name":"TJ Maxx","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Promod":{"tags":{"name":"Promod","shop":"clothes"},"name":"Promod","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Street One":{"tags":{"name":"Street One","shop":"clothes"},"name":"Street One","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/ユニクロ":{"tags":{"name":"ユニクロ","shop":"clothes"},"name":"ユニクロ","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Banana Republic":{"tags":{"name":"Banana Republic","shop":"clothes"},"name":"Banana Republic","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Одежда":{"tags":{"name":"Одежда","shop":"clothes"},"name":"Одежда","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Marshalls":{"tags":{"name":"Marshalls","shop":"clothes"},"name":"Marshalls","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/La Halle":{"tags":{"name":"La Halle","shop":"clothes"},"name":"La Halle","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Peacocks":{"tags":{"name":"Peacocks","shop":"clothes"},"name":"Peacocks","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/しまむら":{"tags":{"name":"しまむら","shop":"clothes"},"name":"しまむら","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/books/Bruna":{"tags":{"name":"Bruna","shop":"books"},"name":"Bruna","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Waterstones":{"tags":{"name":"Waterstones","shop":"books"},"name":"Waterstones","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Libro":{"tags":{"name":"Libro","shop":"books"},"name":"Libro","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Barnes & Noble":{"tags":{"name":"Barnes & Noble","shop":"books"},"name":"Barnes & Noble","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Weltbild":{"tags":{"name":"Weltbild","shop":"books"},"name":"Weltbild","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Thalia":{"tags":{"name":"Thalia","shop":"books"},"name":"Thalia","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Книги":{"tags":{"name":"Книги","shop":"books"},"name":"Книги","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/department_store/Debenhams":{"tags":{"name":"Debenhams","shop":"department_store"},"name":"Debenhams","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Karstadt":{"tags":{"name":"Karstadt","shop":"department_store"},"name":"Karstadt","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Kmart":{"tags":{"name":"Kmart","shop":"department_store"},"name":"Kmart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Target":{"tags":{"name":"Target","shop":"department_store"},"name":"Target","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Galeria Kaufhof":{"tags":{"name":"Galeria Kaufhof","shop":"department_store"},"name":"Galeria Kaufhof","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Marks & Spencer":{"tags":{"name":"Marks & Spencer","shop":"department_store"},"name":"Marks & Spencer","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Big W":{"tags":{"name":"Big W","shop":"department_store"},"name":"Big W","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Woolworth":{"tags":{"name":"Woolworth","shop":"department_store"},"name":"Woolworth","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Универмаг":{"tags":{"name":"Универмаг","shop":"department_store"},"name":"Универмаг","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Sears":{"tags":{"name":"Sears","shop":"department_store"},"name":"Sears","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Kohl's":{"tags":{"name":"Kohl's","shop":"department_store"},"name":"Kohl's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Macy's":{"tags":{"name":"Macy's","shop":"department_store"},"name":"Macy's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/JCPenney":{"tags":{"name":"JCPenney","shop":"department_store"},"name":"JCPenney","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/alcohol/Alko":{"tags":{"name":"Alko","shop":"alcohol"},"name":"Alko","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/The Beer Store":{"tags":{"name":"The Beer Store","shop":"alcohol"},"name":"The Beer Store","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Systembolaget":{"tags":{"name":"Systembolaget","shop":"alcohol"},"name":"Systembolaget","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/LCBO":{"tags":{"name":"LCBO","shop":"alcohol"},"name":"LCBO","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Ароматный мир":{"tags":{"name":"Ароматный мир","shop":"alcohol"},"name":"Ароматный мир","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Bargain Booze":{"tags":{"name":"Bargain Booze","shop":"alcohol"},"name":"Bargain Booze","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Nicolas":{"tags":{"name":"Nicolas","shop":"alcohol"},"name":"Nicolas","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/BWS":{"tags":{"name":"BWS","shop":"alcohol"},"name":"BWS","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Botilleria":{"tags":{"name":"Botilleria","shop":"alcohol"},"name":"Botilleria","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/SAQ":{"tags":{"name":"SAQ","shop":"alcohol"},"name":"SAQ","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Gall & Gall":{"tags":{"name":"Gall & Gall","shop":"alcohol"},"name":"Gall & Gall","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Живое пиво":{"tags":{"name":"Живое пиво","shop":"alcohol"},"name":"Живое пиво","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/bakery/Kamps":{"tags":{"name":"Kamps","shop":"bakery"},"name":"Kamps","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Banette":{"tags":{"name":"Banette","shop":"bakery"},"name":"Banette","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Bäckerei Schmidt":{"tags":{"name":"Bäckerei Schmidt","shop":"bakery"},"name":"Bäckerei Schmidt","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Anker":{"tags":{"name":"Anker","shop":"bakery"},"name":"Anker","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Hofpfisterei":{"tags":{"name":"Hofpfisterei","shop":"bakery"},"name":"Hofpfisterei","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Greggs":{"tags":{"name":"Greggs","shop":"bakery"},"name":"Greggs","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Oebel":{"tags":{"name":"Oebel","shop":"bakery"},"name":"Oebel","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Boulangerie":{"tags":{"name":"Boulangerie","shop":"bakery"},"name":"Boulangerie","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Stadtbäckerei":{"tags":{"name":"Stadtbäckerei","shop":"bakery"},"name":"Stadtbäckerei","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Steinecke":{"tags":{"name":"Steinecke","shop":"bakery"},"name":"Steinecke","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Ihle":{"tags":{"name":"Ihle","shop":"bakery"},"name":"Ihle","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Goldilocks":{"tags":{"name":"Goldilocks","shop":"bakery"},"name":"Goldilocks","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Dat Backhus":{"tags":{"name":"Dat Backhus","shop":"bakery"},"name":"Dat Backhus","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/K&U":{"tags":{"name":"K&U","shop":"bakery"},"name":"K&U","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Der Beck":{"tags":{"name":"Der Beck","shop":"bakery"},"name":"Der Beck","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Thürmann":{"tags":{"name":"Thürmann","shop":"bakery"},"name":"Thürmann","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Backwerk":{"tags":{"name":"Backwerk","shop":"bakery"},"name":"Backwerk","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Schäfer's":{"tags":{"name":"Schäfer's","shop":"bakery"},"name":"Schäfer's","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Panaderia":{"tags":{"name":"Panaderia","shop":"bakery"},"name":"Panaderia","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Goeken backen":{"tags":{"name":"Goeken backen","shop":"bakery"},"name":"Goeken backen","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Stadtbäckerei Junge":{"tags":{"name":"Stadtbäckerei Junge","shop":"bakery"},"name":"Stadtbäckerei Junge","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Boulangerie Patisserie":{"tags":{"name":"Boulangerie Patisserie","shop":"bakery"},"name":"Boulangerie Patisserie","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Paul":{"tags":{"name":"Paul","shop":"bakery"},"name":"Paul","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Хлеб":{"tags":{"name":"Хлеб","shop":"bakery"},"name":"Хлеб","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Пекарня":{"tags":{"name":"Пекарня","shop":"bakery"},"name":"Пекарня","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Кулиничи":{"tags":{"name":"Кулиничи","shop":"bakery"},"name":"Кулиничи","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Sports Direct":{"tags":{"name":"Sports Direct","shop":"sports"},"name":"Sports Direct","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Decathlon":{"tags":{"name":"Decathlon","shop":"sports"},"name":"Decathlon","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Intersport":{"tags":{"name":"Intersport","shop":"sports"},"name":"Intersport","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Sports Authority":{"tags":{"name":"Sports Authority","shop":"sports"},"name":"Sports Authority","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Спортмастер":{"tags":{"name":"Спортмастер","shop":"sports"},"name":"Спортмастер","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Sport 2000":{"tags":{"name":"Sport 2000","shop":"sports"},"name":"Sport 2000","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Dick's Sporting Goods":{"tags":{"name":"Dick's Sporting Goods","shop":"sports"},"name":"Dick's Sporting Goods","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Tedi":{"tags":{"name":"Tedi","shop":"variety_store"},"name":"Tedi","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Dollarama":{"tags":{"name":"Dollarama","shop":"variety_store"},"name":"Dollarama","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Family Dollar":{"tags":{"name":"Family Dollar","shop":"variety_store"},"name":"Family Dollar","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Dollar Tree":{"tags":{"name":"Dollar Tree","shop":"variety_store"},"name":"Dollar Tree","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Fressnapf":{"tags":{"name":"Fressnapf","shop":"pet"},"name":"Fressnapf","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/PetSmart":{"tags":{"name":"PetSmart","shop":"pet"},"name":"PetSmart","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Das Futterhaus":{"tags":{"name":"Das Futterhaus","shop":"pet"},"name":"Das Futterhaus","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Pets at Home":{"tags":{"name":"Pets at Home","shop":"pet"},"name":"Pets at Home","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Petco":{"tags":{"name":"Petco","shop":"pet"},"name":"Petco","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Зоомагазин":{"tags":{"name":"Зоомагазин","shop":"pet"},"name":"Зоомагазин","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Deichmann":{"tags":{"name":"Deichmann","shop":"shoes"},"name":"Deichmann","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Reno":{"tags":{"name":"Reno","shop":"shoes"},"name":"Reno","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Ecco":{"tags":{"name":"Ecco","shop":"shoes"},"name":"Ecco","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Clarks":{"tags":{"name":"Clarks","shop":"shoes"},"name":"Clarks","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/La Halle aux Chaussures":{"tags":{"name":"La Halle aux Chaussures","shop":"shoes"},"name":"La Halle aux Chaussures","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Brantano":{"tags":{"name":"Brantano","shop":"shoes"},"name":"Brantano","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Geox":{"tags":{"name":"Geox","shop":"shoes"},"name":"Geox","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Salamander":{"tags":{"name":"Salamander","shop":"shoes"},"name":"Salamander","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Обувь":{"tags":{"name":"Обувь","shop":"shoes"},"name":"Обувь","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Payless Shoe Source":{"tags":{"name":"Payless Shoe Source","shop":"shoes"},"name":"Payless Shoe Source","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Famous Footwear":{"tags":{"name":"Famous Footwear","shop":"shoes"},"name":"Famous Footwear","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Quick Schuh":{"tags":{"name":"Quick Schuh","shop":"shoes"},"name":"Quick Schuh","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Shoe Zone":{"tags":{"name":"Shoe Zone","shop":"shoes"},"name":"Shoe Zone","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Foot Locker":{"tags":{"name":"Foot Locker","shop":"shoes"},"name":"Foot Locker","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Bata":{"tags":{"name":"Bata","shop":"shoes"},"name":"Bata","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/ЦентрОбувь":{"tags":{"name":"ЦентрОбувь","shop":"shoes"},"name":"ЦентрОбувь","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/La Grande Récré":{"tags":{"name":"La Grande Récré","shop":"toys"},"name":"La Grande Récré","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Toys R Us":{"tags":{"name":"Toys R Us","shop":"toys"},"name":"Toys R Us","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Intertoys":{"tags":{"name":"Intertoys","shop":"toys"},"name":"Intertoys","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Детский мир":{"tags":{"name":"Детский мир","shop":"toys"},"name":"Детский мир","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Игрушки":{"tags":{"name":"Игрушки","shop":"toys"},"name":"Игрушки","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/travel_agency/Flight Centre":{"tags":{"name":"Flight Centre","shop":"travel_agency"},"name":"Flight Centre","icon":"suitcase","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/travel_agency/Thomas Cook":{"tags":{"name":"Thomas Cook","shop":"travel_agency"},"name":"Thomas Cook","icon":"suitcase","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/jewelry/Bijou Brigitte":{"tags":{"name":"Bijou Brigitte","shop":"jewelry"},"name":"Bijou Brigitte","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/jewelry/Christ":{"tags":{"name":"Christ","shop":"jewelry"},"name":"Christ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/jewelry/Swarovski":{"tags":{"name":"Swarovski","shop":"jewelry"},"name":"Swarovski","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Fielmann":{"tags":{"name":"Fielmann","shop":"optician"},"name":"Fielmann","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Apollo Optik":{"tags":{"name":"Apollo Optik","shop":"optician"},"name":"Apollo Optik","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Vision Express":{"tags":{"name":"Vision Express","shop":"optician"},"name":"Vision Express","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Оптика":{"tags":{"name":"Оптика","shop":"optician"},"name":"Оптика","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Optic 2000":{"tags":{"name":"Optic 2000","shop":"optician"},"name":"Optic 2000","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Alain Afflelou":{"tags":{"name":"Alain Afflelou","shop":"optician"},"name":"Alain Afflelou","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Specsavers":{"tags":{"name":"Specsavers","shop":"optician"},"name":"Specsavers","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Krys":{"tags":{"name":"Krys","shop":"optician"},"name":"Krys","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Atol":{"tags":{"name":"Atol","shop":"optician"},"name":"Atol","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/video/Blockbuster":{"tags":{"name":"Blockbuster","shop":"video"},"name":"Blockbuster","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/video/World of Video":{"tags":{"name":"World of Video","shop":"video"},"name":"World of Video","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Билайн":{"tags":{"name":"Билайн","shop":"mobile_phone"},"name":"Билайн","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/ソフトバンクショップ (SoftBank shop)":{"tags":{"name":"ソフトバンクショップ (SoftBank shop)","shop":"mobile_phone"},"name":"ソフトバンクショップ (SoftBank shop)","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Vodafone":{"tags":{"name":"Vodafone","shop":"mobile_phone"},"name":"Vodafone","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/O2":{"tags":{"name":"O2","shop":"mobile_phone"},"name":"O2","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Carphone Warehouse":{"tags":{"name":"Carphone Warehouse","shop":"mobile_phone"},"name":"Carphone Warehouse","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Orange":{"tags":{"name":"Orange","shop":"mobile_phone"},"name":"Orange","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Verizon Wireless":{"tags":{"name":"Verizon Wireless","shop":"mobile_phone"},"name":"Verizon Wireless","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Sprint":{"tags":{"name":"Sprint","shop":"mobile_phone"},"name":"Sprint","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/T-Mobile":{"tags":{"name":"T-Mobile","shop":"mobile_phone"},"name":"T-Mobile","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/МТС":{"tags":{"name":"МТС","shop":"mobile_phone"},"name":"МТС","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Евросеть":{"tags":{"name":"Евросеть","shop":"mobile_phone"},"name":"Евросеть","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Bell":{"tags":{"name":"Bell","shop":"mobile_phone"},"name":"Bell","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/The Phone House":{"tags":{"name":"The Phone House","shop":"mobile_phone"},"name":"The Phone House","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/SFR":{"tags":{"name":"SFR","shop":"mobile_phone"},"name":"SFR","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Связной":{"tags":{"name":"Связной","shop":"mobile_phone"},"name":"Связной","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Мегафон":{"tags":{"name":"Мегафон","shop":"mobile_phone"},"name":"Мегафон","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/AT&T":{"tags":{"name":"AT&T","shop":"mobile_phone"},"name":"AT&T","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/ドコモショップ (docomo shop)":{"tags":{"name":"ドコモショップ (docomo shop)","shop":"mobile_phone"},"name":"ドコモショップ (docomo shop)","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/au":{"tags":{"name":"au","shop":"mobile_phone"},"name":"au","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Movistar":{"tags":{"name":"Movistar","shop":"mobile_phone"},"name":"Movistar","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Bitė":{"tags":{"name":"Bitė","shop":"mobile_phone"},"name":"Bitė","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/computer/PC World":{"tags":{"name":"PC World","shop":"computer"},"name":"PC World","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/computer/DNS":{"tags":{"name":"DNS","shop":"computer"},"name":"DNS","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Klier":{"tags":{"name":"Klier","shop":"hairdresser"},"name":"Klier","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Supercuts":{"tags":{"name":"Supercuts","shop":"hairdresser"},"name":"Supercuts","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Hairkiller":{"tags":{"name":"Hairkiller","shop":"hairdresser"},"name":"Hairkiller","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Great Clips":{"tags":{"name":"Great Clips","shop":"hairdresser"},"name":"Great Clips","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Парикмахерская":{"tags":{"name":"Парикмахерская","shop":"hairdresser"},"name":"Парикмахерская","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Стиль":{"tags":{"name":"Стиль","shop":"hairdresser"},"name":"Стиль","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Franck Provost":{"tags":{"name":"Franck Provost","shop":"hairdresser"},"name":"Franck Provost","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Салон красоты":{"tags":{"name":"Салон красоты","shop":"hairdresser"},"name":"Салон красоты","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hardware/1000 мелочей":{"tags":{"name":"1000 мелочей","shop":"hardware"},"name":"1000 мелочей","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hardware/Хозтовары":{"tags":{"name":"Хозтовары","shop":"hardware"},"name":"Хозтовары","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/motorcycle/Yamaha":{"tags":{"name":"Yamaha","shop":"motorcycle"},"name":"Yamaha","icon":"scooter","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true}};
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 Ramp"},"lamp_type":{"key":"lamp_type","type":"combo","label":"Type"},"landuse":{"key":"landuse","type":"typeCombo","label":"Type"},"lanes":{"key":"lanes","type":"number","label":"Lanes","placeholder":"1, 2, 3..."},"layer":{"key":"layer","type":"combo","label":"Layer"},"leaf_cycle_singular":{"key":"leaf_cycle","type":"combo","label":"Leaf Cycle","strings":{"options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous"}}},"leaf_cycle":{"key":"leaf_cycle","type":"combo","label":"Leaf Cycle","strings":{"options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous","mixed":"Mixed"}}},"leaf_type_singular":{"key":"leaf_type","type":"combo","label":"Leaf Type","strings":{"options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","leafless":"Leafless"}}},"leaf_type":{"key":"leaf_type","type":"combo","label":"Leaf Type","strings":{"options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","mixed":"Mixed","leafless":"Leafless"}}},"leisure":{"key":"leisure","type":"typeCombo","label":"Type"},"length":{"key":"length","type":"number","label":"Length (Meters)"},"level":{"key":"level","type":"combo","label":"Level","universal":true},"levels":{"key":"building:levels","type":"number","label":"Levels","placeholder":"2, 4, 6..."},"lit":{"key":"lit","type":"check","label":"Lit"},"location":{"key":"location","type":"combo","label":"Location"},"man_made":{"key":"man_made","type":"typeCombo","label":"Type"},"map_size":{"key":"map_size","type":"typeCombo","label":"Coverage"},"map_type":{"key":"map_type","type":"typeCombo","label":"Type"},"maxheight":{"key":"maxheight","type":"combo","label":"Max Height","placeholder":"4, 4.5, 5, 14'0\", 14'6\", 15'0\"","snake_case":false},"maxspeed":{"key":"maxspeed","type":"maxspeed","label":"Speed Limit","placeholder":"40, 50, 60..."},"maxstay":{"key":"maxstay","type":"combo","label":"Max Stay","options":["15 min","30 min","45 min","1 hr","1.5 hr","2 hr","2.5 hr","3 hr","4 hr","1 day","2 day"],"snake_case":false},"mtb/scale":{"key":"mtb:scale","type":"combo","label":"Mountain Biking Difficulty","placeholder":"0, 1, 2, 3...","strings":{"options":{"0":"0: Solid gravel/packed earth, no obstacles, wide curves","1":"1: Some loose surface, small obstacles, wide curves","2":"2: Much loose surface, large obstacles, easy hairpins","3":"3: Slippery surface, large obstacles, tight hairpins","4":"4: Loose surface or boulders, dangerous hairpins","5":"5: Maximum difficulty, boulder fields, landslides","6":"6: Not rideable except by the very best mountain bikers"}}},"mtb/scale/imba":{"key":"mtb:scale:imba","type":"combo","label":"IMBA Trail Difficulty","placeholder":"Easy, Medium, Difficult...","strings":{"options":{"0":"Easiest (white circle)","1":"Easy (green circle)","2":"Medium (blue square)","3":"Difficult (black diamond)","4":"Extremely Difficult (double black diamond)"}}},"mtb/scale/uphill":{"key":"mtb:scale:uphill","type":"combo","label":"Mountain Biking Uphill Difficulty","placeholder":"0, 1, 2, 3...","strings":{"options":{"0":"0: Avg. incline <10%, gravel/packed earth, no obstacles","1":"1: Avg. incline <15%, gravel/packed earth, few small objects","2":"2: Avg. incline <20%, stable surface, fistsize rocks/roots","3":"3: Avg. incline <25%, variable surface, fistsize rocks/branches","4":"4: Avg. incline <30%, poor condition, big rocks/branches","5":"5: Very steep, bike generally needs to be pushed or carried"}}},"name":{"key":"name","type":"localized","label":"Name","placeholder":"Common name (if any)"},"natural":{"key":"natural","type":"typeCombo","label":"Natural"},"network_bicycle":{"key":"network","type":"combo","label":"Network Type","placeholder":"Local, Regional, National, International","strings":{"options":{"lcn":"Local","rcn":"Regional","ncn":"National","icn":"International"}}},"network_foot":{"key":"network","type":"combo","label":"Network Type","placeholder":"Local, Regional, National, International","strings":{"options":{"lwn":"Local","rwn":"Regional","nwn":"National","iwn":"International"}}},"network_horse":{"key":"network","type":"combo","label":"Network Type","placeholder":"Local, Regional, National, International","strings":{"options":{"lhn":"Local","rhn":"Regional","nhn":"National","ihn":"International"}}},"network_road":{"key":"network","type":"networkCombo","label":"Network"},"network":{"key":"network","type":"text","label":"Network"},"note":{"key":"note","type":"textarea","universal":true,"icon":"note","label":"Note"},"office":{"key":"office","type":"typeCombo","label":"Type"},"oneway_yes":{"key":"oneway","type":"onewayCheck","label":"One Way","strings":{"options":{"undefined":"Assumed to be Yes","yes":"Yes","no":"No"}}},"oneway":{"key":"oneway","type":"onewayCheck","label":"One Way","strings":{"options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}}},"opening_hours":{"key":"opening_hours","type":"combo","label":"Hours"},"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.8.0";
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)";
19838 }
19839
19840 function translateY(y) {
19841   return "translate(0," + y + ")";
19842 }
19843
19844 function center(scale) {
19845   var offset = scale.bandwidth() / 2;
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, y = orient === left || orient === right ? (x = "x", "y") : (x = "y", "x"),
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         .attr(y + "1", 0.5)
19893         .attr(y + "2", 0.5));
19894
19895     text = text.merge(tickEnter.append("text")
19896         .attr("fill", "#000")
19897         .attr(x, k * spacing)
19898         .attr(y, 0.5)
19899         .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
19900
19901     if (context !== selection) {
19902       path = path.transition(context);
19903       tick = tick.transition(context);
19904       line = line.transition(context);
19905       text = text.transition(context);
19906
19907       tickExit = tickExit.transition(context)
19908           .attr("opacity", epsilon)
19909           .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); });
19910
19911       tickEnter
19912           .attr("opacity", epsilon)
19913           .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); });
19914     }
19915
19916     tickExit.remove();
19917
19918     path
19919         .attr("d", orient === left || orient == right
19920             ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter
19921             : "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter);
19922
19923     tick
19924         .attr("opacity", 1)
19925         .attr("transform", function(d) { return transform(position(d)); });
19926
19927     line
19928         .attr(x + "2", k * tickSizeInner);
19929
19930     text
19931         .attr(x, k * spacing)
19932         .text(format);
19933
19934     selection.filter(entering)
19935         .attr("fill", "none")
19936         .attr("font-size", 10)
19937         .attr("font-family", "sans-serif")
19938         .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
19939
19940     selection
19941         .each(function() { this.__axis = position; });
19942   }
19943
19944   axis.scale = function(_) {
19945     return arguments.length ? (scale = _, axis) : scale;
19946   };
19947
19948   axis.ticks = function() {
19949     return tickArguments = slice$1.call(arguments), axis;
19950   };
19951
19952   axis.tickArguments = function(_) {
19953     return arguments.length ? (tickArguments = _ == null ? [] : slice$1.call(_), axis) : tickArguments.slice();
19954   };
19955
19956   axis.tickValues = function(_) {
19957     return arguments.length ? (tickValues = _ == null ? null : slice$1.call(_), axis) : tickValues && tickValues.slice();
19958   };
19959
19960   axis.tickFormat = function(_) {
19961     return arguments.length ? (tickFormat = _, axis) : tickFormat;
19962   };
19963
19964   axis.tickSize = function(_) {
19965     return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
19966   };
19967
19968   axis.tickSizeInner = function(_) {
19969     return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
19970   };
19971
19972   axis.tickSizeOuter = function(_) {
19973     return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
19974   };
19975
19976   axis.tickPadding = function(_) {
19977     return arguments.length ? (tickPadding = +_, axis) : tickPadding;
19978   };
19979
19980   return axis;
19981 }
19982
19983 function axisTop(scale) {
19984   return axis(top, scale);
19985 }
19986
19987 function axisRight(scale) {
19988   return axis(right, scale);
19989 }
19990
19991 function axisBottom(scale) {
19992   return axis(bottom, scale);
19993 }
19994
19995 function axisLeft(scale) {
19996   return axis(left, scale);
19997 }
19998
19999 var noop = {value: function() {}};
20000
20001 function dispatch() {
20002   for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
20003     if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
20004     _[t] = [];
20005   }
20006   return new Dispatch(_);
20007 }
20008
20009 function Dispatch(_) {
20010   this._ = _;
20011 }
20012
20013 function parseTypenames(typenames, types) {
20014   return typenames.trim().split(/^|\s+/).map(function(t) {
20015     var name = "", i = t.indexOf(".");
20016     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20017     if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
20018     return {type: t, name: name};
20019   });
20020 }
20021
20022 Dispatch.prototype = dispatch.prototype = {
20023   constructor: Dispatch,
20024   on: function(typename, callback) {
20025     var _ = this._,
20026         T = parseTypenames(typename + "", _),
20027         t,
20028         i = -1,
20029         n = T.length;
20030
20031     // If no callback was specified, return the callback of the given type and name.
20032     if (arguments.length < 2) {
20033       while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
20034       return;
20035     }
20036
20037     // If a type was specified, set the callback for the given type and name.
20038     // Otherwise, if a null callback was specified, remove callbacks of the given name.
20039     if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
20040     while (++i < n) {
20041       if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
20042       else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
20043     }
20044
20045     return this;
20046   },
20047   copy: function() {
20048     var copy = {}, _ = this._;
20049     for (var t in _) copy[t] = _[t].slice();
20050     return new Dispatch(copy);
20051   },
20052   call: function(type, that) {
20053     if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
20054     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20055     for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20056   },
20057   apply: function(type, that, args) {
20058     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20059     for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20060   }
20061 };
20062
20063 function get(type, name) {
20064   for (var i = 0, n = type.length, c; i < n; ++i) {
20065     if ((c = type[i]).name === name) {
20066       return c.value;
20067     }
20068   }
20069 }
20070
20071 function set(type, name, callback) {
20072   for (var i = 0, n = type.length; i < n; ++i) {
20073     if (type[i].name === name) {
20074       type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
20075       break;
20076     }
20077   }
20078   if (callback != null) type.push({name: name, value: callback});
20079   return type;
20080 }
20081
20082 var xhtml = "http://www.w3.org/1999/xhtml";
20083
20084 var namespaces = {
20085   svg: "http://www.w3.org/2000/svg",
20086   xhtml: xhtml,
20087   xlink: "http://www.w3.org/1999/xlink",
20088   xml: "http://www.w3.org/XML/1998/namespace",
20089   xmlns: "http://www.w3.org/2000/xmlns/"
20090 };
20091
20092 var namespace = function(name) {
20093   var prefix = name += "", i = prefix.indexOf(":");
20094   if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
20095   return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
20096 };
20097
20098 function creatorInherit(name) {
20099   return function() {
20100     var document = this.ownerDocument,
20101         uri = this.namespaceURI;
20102     return uri === xhtml && document.documentElement.namespaceURI === xhtml
20103         ? document.createElement(name)
20104         : document.createElementNS(uri, name);
20105   };
20106 }
20107
20108 function creatorFixed(fullname) {
20109   return function() {
20110     return this.ownerDocument.createElementNS(fullname.space, fullname.local);
20111   };
20112 }
20113
20114 var creator = function(name) {
20115   var fullname = namespace(name);
20116   return (fullname.local
20117       ? creatorFixed
20118       : creatorInherit)(fullname);
20119 };
20120
20121 var nextId = 0;
20122
20123 function local$1() {
20124   return new Local;
20125 }
20126
20127 function Local() {
20128   this._ = "@" + (++nextId).toString(36);
20129 }
20130
20131 Local.prototype = local$1.prototype = {
20132   constructor: Local,
20133   get: function(node) {
20134     var id = this._;
20135     while (!(id in node)) if (!(node = node.parentNode)) return;
20136     return node[id];
20137   },
20138   set: function(node, value) {
20139     return node[this._] = value;
20140   },
20141   remove: function(node) {
20142     return this._ in node && delete node[this._];
20143   },
20144   toString: function() {
20145     return this._;
20146   }
20147 };
20148
20149 var matcher = function(selector) {
20150   return function() {
20151     return this.matches(selector);
20152   };
20153 };
20154
20155 if (typeof document !== "undefined") {
20156   var element = document.documentElement;
20157   if (!element.matches) {
20158     var vendorMatches = element.webkitMatchesSelector
20159         || element.msMatchesSelector
20160         || element.mozMatchesSelector
20161         || element.oMatchesSelector;
20162     matcher = function(selector) {
20163       return function() {
20164         return vendorMatches.call(this, selector);
20165       };
20166     };
20167   }
20168 }
20169
20170 var matcher$1 = matcher;
20171
20172 var filterEvents = {};
20173
20174 var event = null;
20175
20176 if (typeof document !== "undefined") {
20177   var element$1 = document.documentElement;
20178   if (!("onmouseenter" in element$1)) {
20179     filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
20180   }
20181 }
20182
20183 function filterContextListener(listener, index, group) {
20184   listener = contextListener(listener, index, group);
20185   return function(event) {
20186     var related = event.relatedTarget;
20187     if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
20188       listener.call(this, event);
20189     }
20190   };
20191 }
20192
20193 function contextListener(listener, index, group) {
20194   return function(event1) {
20195     var event0 = event; // Events can be reentrant (e.g., focus).
20196     event = event1;
20197     try {
20198       listener.call(this, this.__data__, index, group);
20199     } finally {
20200       event = event0;
20201     }
20202   };
20203 }
20204
20205 function parseTypenames$1(typenames) {
20206   return typenames.trim().split(/^|\s+/).map(function(t) {
20207     var name = "", i = t.indexOf(".");
20208     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20209     return {type: t, name: name};
20210   });
20211 }
20212
20213 function onRemove(typename) {
20214   return function() {
20215     var on = this.__on;
20216     if (!on) return;
20217     for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
20218       if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
20219         this.removeEventListener(o.type, o.listener, o.capture);
20220       } else {
20221         on[++i] = o;
20222       }
20223     }
20224     if (++i) on.length = i;
20225     else delete this.__on;
20226   };
20227 }
20228
20229 function onAdd(typename, value, capture) {
20230   var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
20231   return function(d, i, group) {
20232     var on = this.__on, o, listener = wrap(value, i, group);
20233     if (on) for (var j = 0, m = on.length; j < m; ++j) {
20234       if ((o = on[j]).type === typename.type && o.name === typename.name) {
20235         this.removeEventListener(o.type, o.listener, o.capture);
20236         this.addEventListener(o.type, o.listener = listener, o.capture = capture);
20237         o.value = value;
20238         return;
20239       }
20240     }
20241     this.addEventListener(typename.type, listener, capture);
20242     o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
20243     if (!on) this.__on = [o];
20244     else on.push(o);
20245   };
20246 }
20247
20248 var selection_on = function(typename, value, capture) {
20249   var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t;
20250
20251   if (arguments.length < 2) {
20252     var on = this.node().__on;
20253     if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
20254       for (i = 0, o = on[j]; i < n; ++i) {
20255         if ((t = typenames[i]).type === o.type && t.name === o.name) {
20256           return o.value;
20257         }
20258       }
20259     }
20260     return;
20261   }
20262
20263   on = value ? onAdd : onRemove;
20264   if (capture == null) capture = false;
20265   for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
20266   return this;
20267 };
20268
20269 function customEvent(event1, listener, that, args) {
20270   var event0 = event;
20271   event1.sourceEvent = event;
20272   event = event1;
20273   try {
20274     return listener.apply(that, args);
20275   } finally {
20276     event = event0;
20277   }
20278 }
20279
20280 var sourceEvent = function() {
20281   var current = event, source;
20282   while (source = current.sourceEvent) current = source;
20283   return current;
20284 };
20285
20286 var point = function(node, event) {
20287   var svg = node.ownerSVGElement || node;
20288
20289   if (svg.createSVGPoint) {
20290     var point = svg.createSVGPoint();
20291     point.x = event.clientX, point.y = event.clientY;
20292     point = point.matrixTransform(node.getScreenCTM().inverse());
20293     return [point.x, point.y];
20294   }
20295
20296   var rect = node.getBoundingClientRect();
20297   return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
20298 };
20299
20300 var mouse = function(node) {
20301   var event = sourceEvent();
20302   if (event.changedTouches) event = event.changedTouches[0];
20303   return point(node, event);
20304 };
20305
20306 function none() {}
20307
20308 var selector = function(selector) {
20309   return selector == null ? none : function() {
20310     return this.querySelector(selector);
20311   };
20312 };
20313
20314 var selection_select = function(select) {
20315   if (typeof select !== "function") select = selector(select);
20316
20317   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20318     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
20319       if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
20320         if ("__data__" in node) subnode.__data__ = node.__data__;
20321         subgroup[i] = subnode;
20322       }
20323     }
20324   }
20325
20326   return new Selection(subgroups, this._parents);
20327 };
20328
20329 function empty$1() {
20330   return [];
20331 }
20332
20333 var selectorAll = function(selector) {
20334   return selector == null ? empty$1 : function() {
20335     return this.querySelectorAll(selector);
20336   };
20337 };
20338
20339 var selection_selectAll = function(select) {
20340   if (typeof select !== "function") select = selectorAll(select);
20341
20342   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
20343     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
20344       if (node = group[i]) {
20345         subgroups.push(select.call(node, node.__data__, i, group));
20346         parents.push(node);
20347       }
20348     }
20349   }
20350
20351   return new Selection(subgroups, parents);
20352 };
20353
20354 var selection_filter = function(match) {
20355   if (typeof match !== "function") match = matcher$1(match);
20356
20357   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20358     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
20359       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
20360         subgroup.push(node);
20361       }
20362     }
20363   }
20364
20365   return new Selection(subgroups, this._parents);
20366 };
20367
20368 var sparse = function(update) {
20369   return new Array(update.length);
20370 };
20371
20372 var selection_enter = function() {
20373   return new Selection(this._enter || this._groups.map(sparse), this._parents);
20374 };
20375
20376 function EnterNode(parent, datum) {
20377   this.ownerDocument = parent.ownerDocument;
20378   this.namespaceURI = parent.namespaceURI;
20379   this._next = null;
20380   this._parent = parent;
20381   this.__data__ = datum;
20382 }
20383
20384 EnterNode.prototype = {
20385   constructor: EnterNode,
20386   appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
20387   insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
20388   querySelector: function(selector) { return this._parent.querySelector(selector); },
20389   querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
20390 };
20391
20392 var constant$1 = function(x) {
20393   return function() {
20394     return x;
20395   };
20396 };
20397
20398 var keyPrefix = "$"; // Protect against keys like “__proto__”.
20399
20400 function bindIndex(parent, group, enter, update, exit, data) {
20401   var i = 0,
20402       node,
20403       groupLength = group.length,
20404       dataLength = data.length;
20405
20406   // Put any non-null nodes that fit into update.
20407   // Put any null nodes into enter.
20408   // Put any remaining data into enter.
20409   for (; i < dataLength; ++i) {
20410     if (node = group[i]) {
20411       node.__data__ = data[i];
20412       update[i] = node;
20413     } else {
20414       enter[i] = new EnterNode(parent, data[i]);
20415     }
20416   }
20417
20418   // Put any non-null nodes that don’t fit into exit.
20419   for (; i < groupLength; ++i) {
20420     if (node = group[i]) {
20421       exit[i] = node;
20422     }
20423   }
20424 }
20425
20426 function bindKey(parent, group, enter, update, exit, data, key) {
20427   var i,
20428       node,
20429       nodeByKeyValue = {},
20430       groupLength = group.length,
20431       dataLength = data.length,
20432       keyValues = new Array(groupLength),
20433       keyValue;
20434
20435   // Compute the key for each node.
20436   // If multiple nodes have the same key, the duplicates are added to exit.
20437   for (i = 0; i < groupLength; ++i) {
20438     if (node = group[i]) {
20439       keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
20440       if (keyValue in nodeByKeyValue) {
20441         exit[i] = node;
20442       } else {
20443         nodeByKeyValue[keyValue] = node;
20444       }
20445     }
20446   }
20447
20448   // Compute the key for each datum.
20449   // If there a node associated with this key, join and add it to update.
20450   // If there is not (or the key is a duplicate), add it to enter.
20451   for (i = 0; i < dataLength; ++i) {
20452     keyValue = keyPrefix + key.call(parent, data[i], i, data);
20453     if (node = nodeByKeyValue[keyValue]) {
20454       update[i] = node;
20455       node.__data__ = data[i];
20456       nodeByKeyValue[keyValue] = null;
20457     } else {
20458       enter[i] = new EnterNode(parent, data[i]);
20459     }
20460   }
20461
20462   // Add any remaining nodes that were not bound to data to exit.
20463   for (i = 0; i < groupLength; ++i) {
20464     if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
20465       exit[i] = node;
20466     }
20467   }
20468 }
20469
20470 var selection_data = function(value, key) {
20471   if (!value) {
20472     data = new Array(this.size()), j = -1;
20473     this.each(function(d) { data[++j] = d; });
20474     return data;
20475   }
20476
20477   var bind = key ? bindKey : bindIndex,
20478       parents = this._parents,
20479       groups = this._groups;
20480
20481   if (typeof value !== "function") value = constant$1(value);
20482
20483   for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
20484     var parent = parents[j],
20485         group = groups[j],
20486         groupLength = group.length,
20487         data = value.call(parent, parent && parent.__data__, j, parents),
20488         dataLength = data.length,
20489         enterGroup = enter[j] = new Array(dataLength),
20490         updateGroup = update[j] = new Array(dataLength),
20491         exitGroup = exit[j] = new Array(groupLength);
20492
20493     bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
20494
20495     // Now connect the enter nodes to their following update node, such that
20496     // appendChild can insert the materialized enter node before this node,
20497     // rather than at the end of the parent node.
20498     for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
20499       if (previous = enterGroup[i0]) {
20500         if (i0 >= i1) i1 = i0 + 1;
20501         while (!(next = updateGroup[i1]) && ++i1 < dataLength);
20502         previous._next = next || null;
20503       }
20504     }
20505   }
20506
20507   update = new Selection(update, parents);
20508   update._enter = enter;
20509   update._exit = exit;
20510   return update;
20511 };
20512
20513 var selection_exit = function() {
20514   return new Selection(this._exit || this._groups.map(sparse), this._parents);
20515 };
20516
20517 var selection_merge = function(selection) {
20518
20519   for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
20520     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
20521       if (node = group0[i] || group1[i]) {
20522         merge[i] = node;
20523       }
20524     }
20525   }
20526
20527   for (; j < m0; ++j) {
20528     merges[j] = groups0[j];
20529   }
20530
20531   return new Selection(merges, this._parents);
20532 };
20533
20534 var selection_order = function() {
20535
20536   for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
20537     for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
20538       if (node = group[i]) {
20539         if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
20540         next = node;
20541       }
20542     }
20543   }
20544
20545   return this;
20546 };
20547
20548 var selection_sort = function(compare) {
20549   if (!compare) compare = ascending$1;
20550
20551   function compareNode(a, b) {
20552     return a && b ? compare(a.__data__, b.__data__) : !a - !b;
20553   }
20554
20555   for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
20556     for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
20557       if (node = group[i]) {
20558         sortgroup[i] = node;
20559       }
20560     }
20561     sortgroup.sort(compareNode);
20562   }
20563
20564   return new Selection(sortgroups, this._parents).order();
20565 };
20566
20567 function ascending$1(a, b) {
20568   return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
20569 }
20570
20571 var selection_call = function() {
20572   var callback = arguments[0];
20573   arguments[0] = this;
20574   callback.apply(null, arguments);
20575   return this;
20576 };
20577
20578 var selection_nodes = function() {
20579   var nodes = new Array(this.size()), i = -1;
20580   this.each(function() { nodes[++i] = this; });
20581   return nodes;
20582 };
20583
20584 var selection_node = function() {
20585
20586   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20587     for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
20588       var node = group[i];
20589       if (node) return node;
20590     }
20591   }
20592
20593   return null;
20594 };
20595
20596 var selection_size = function() {
20597   var size = 0;
20598   this.each(function() { ++size; });
20599   return size;
20600 };
20601
20602 var selection_empty = function() {
20603   return !this.node();
20604 };
20605
20606 var selection_each = function(callback) {
20607
20608   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20609     for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
20610       if (node = group[i]) callback.call(node, node.__data__, i, group);
20611     }
20612   }
20613
20614   return this;
20615 };
20616
20617 function attrRemove(name) {
20618   return function() {
20619     this.removeAttribute(name);
20620   };
20621 }
20622
20623 function attrRemoveNS(fullname) {
20624   return function() {
20625     this.removeAttributeNS(fullname.space, fullname.local);
20626   };
20627 }
20628
20629 function attrConstant(name, value) {
20630   return function() {
20631     this.setAttribute(name, value);
20632   };
20633 }
20634
20635 function attrConstantNS(fullname, value) {
20636   return function() {
20637     this.setAttributeNS(fullname.space, fullname.local, value);
20638   };
20639 }
20640
20641 function attrFunction(name, value) {
20642   return function() {
20643     var v = value.apply(this, arguments);
20644     if (v == null) this.removeAttribute(name);
20645     else this.setAttribute(name, v);
20646   };
20647 }
20648
20649 function attrFunctionNS(fullname, value) {
20650   return function() {
20651     var v = value.apply(this, arguments);
20652     if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
20653     else this.setAttributeNS(fullname.space, fullname.local, v);
20654   };
20655 }
20656
20657 var selection_attr = function(name, value) {
20658   var fullname = namespace(name);
20659
20660   if (arguments.length < 2) {
20661     var node = this.node();
20662     return fullname.local
20663         ? node.getAttributeNS(fullname.space, fullname.local)
20664         : node.getAttribute(fullname);
20665   }
20666
20667   return this.each((value == null
20668       ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
20669       ? (fullname.local ? attrFunctionNS : attrFunction)
20670       : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
20671 };
20672
20673 var window$1 = function(node) {
20674   return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
20675       || (node.document && node) // node is a Window
20676       || node.defaultView; // node is a Document
20677 };
20678
20679 function styleRemove(name) {
20680   return function() {
20681     this.style.removeProperty(name);
20682   };
20683 }
20684
20685 function styleConstant(name, value, priority) {
20686   return function() {
20687     this.style.setProperty(name, value, priority);
20688   };
20689 }
20690
20691 function styleFunction(name, value, priority) {
20692   return function() {
20693     var v = value.apply(this, arguments);
20694     if (v == null) this.style.removeProperty(name);
20695     else this.style.setProperty(name, v, priority);
20696   };
20697 }
20698
20699 var selection_style = function(name, value, priority) {
20700   var node;
20701   return arguments.length > 1
20702       ? this.each((value == null
20703             ? styleRemove : typeof value === "function"
20704             ? styleFunction
20705             : styleConstant)(name, value, priority == null ? "" : priority))
20706       : window$1(node = this.node())
20707           .getComputedStyle(node, null)
20708           .getPropertyValue(name);
20709 };
20710
20711 function propertyRemove(name) {
20712   return function() {
20713     delete this[name];
20714   };
20715 }
20716
20717 function propertyConstant(name, value) {
20718   return function() {
20719     this[name] = value;
20720   };
20721 }
20722
20723 function propertyFunction(name, value) {
20724   return function() {
20725     var v = value.apply(this, arguments);
20726     if (v == null) delete this[name];
20727     else this[name] = v;
20728   };
20729 }
20730
20731 var selection_property = function(name, value) {
20732   return arguments.length > 1
20733       ? this.each((value == null
20734           ? propertyRemove : typeof value === "function"
20735           ? propertyFunction
20736           : propertyConstant)(name, value))
20737       : this.node()[name];
20738 };
20739
20740 function classArray(string) {
20741   return string.trim().split(/^|\s+/);
20742 }
20743
20744 function classList(node) {
20745   return node.classList || new ClassList(node);
20746 }
20747
20748 function ClassList(node) {
20749   this._node = node;
20750   this._names = classArray(node.getAttribute("class") || "");
20751 }
20752
20753 ClassList.prototype = {
20754   add: function(name) {
20755     var i = this._names.indexOf(name);
20756     if (i < 0) {
20757       this._names.push(name);
20758       this._node.setAttribute("class", this._names.join(" "));
20759     }
20760   },
20761   remove: function(name) {
20762     var i = this._names.indexOf(name);
20763     if (i >= 0) {
20764       this._names.splice(i, 1);
20765       this._node.setAttribute("class", this._names.join(" "));
20766     }
20767   },
20768   contains: function(name) {
20769     return this._names.indexOf(name) >= 0;
20770   }
20771 };
20772
20773 function classedAdd(node, names) {
20774   var list = classList(node), i = -1, n = names.length;
20775   while (++i < n) list.add(names[i]);
20776 }
20777
20778 function classedRemove(node, names) {
20779   var list = classList(node), i = -1, n = names.length;
20780   while (++i < n) list.remove(names[i]);
20781 }
20782
20783 function classedTrue(names) {
20784   return function() {
20785     classedAdd(this, names);
20786   };
20787 }
20788
20789 function classedFalse(names) {
20790   return function() {
20791     classedRemove(this, names);
20792   };
20793 }
20794
20795 function classedFunction(names, value) {
20796   return function() {
20797     (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
20798   };
20799 }
20800
20801 var selection_classed = function(name, value) {
20802   var names = classArray(name + "");
20803
20804   if (arguments.length < 2) {
20805     var list = classList(this.node()), i = -1, n = names.length;
20806     while (++i < n) if (!list.contains(names[i])) return false;
20807     return true;
20808   }
20809
20810   return this.each((typeof value === "function"
20811       ? classedFunction : value
20812       ? classedTrue
20813       : classedFalse)(names, value));
20814 };
20815
20816 function textRemove() {
20817   this.textContent = "";
20818 }
20819
20820 function textConstant(value) {
20821   return function() {
20822     this.textContent = value;
20823   };
20824 }
20825
20826 function textFunction(value) {
20827   return function() {
20828     var v = value.apply(this, arguments);
20829     this.textContent = v == null ? "" : v;
20830   };
20831 }
20832
20833 var selection_text = function(value) {
20834   return arguments.length
20835       ? this.each(value == null
20836           ? textRemove : (typeof value === "function"
20837           ? textFunction
20838           : textConstant)(value))
20839       : this.node().textContent;
20840 };
20841
20842 function htmlRemove() {
20843   this.innerHTML = "";
20844 }
20845
20846 function htmlConstant(value) {
20847   return function() {
20848     this.innerHTML = value;
20849   };
20850 }
20851
20852 function htmlFunction(value) {
20853   return function() {
20854     var v = value.apply(this, arguments);
20855     this.innerHTML = v == null ? "" : v;
20856   };
20857 }
20858
20859 var selection_html = function(value) {
20860   return arguments.length
20861       ? this.each(value == null
20862           ? htmlRemove : (typeof value === "function"
20863           ? htmlFunction
20864           : htmlConstant)(value))
20865       : this.node().innerHTML;
20866 };
20867
20868 function raise() {
20869   if (this.nextSibling) this.parentNode.appendChild(this);
20870 }
20871
20872 var selection_raise = function() {
20873   return this.each(raise);
20874 };
20875
20876 function lower() {
20877   if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
20878 }
20879
20880 var selection_lower = function() {
20881   return this.each(lower);
20882 };
20883
20884 var selection_append = function(name) {
20885   var create = typeof name === "function" ? name : creator(name);
20886   return this.select(function() {
20887     return this.appendChild(create.apply(this, arguments));
20888   });
20889 };
20890
20891 function constantNull() {
20892   return null;
20893 }
20894
20895 var selection_insert = function(name, before) {
20896   var create = typeof name === "function" ? name : creator(name),
20897       select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
20898   return this.select(function() {
20899     return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
20900   });
20901 };
20902
20903 function remove() {
20904   var parent = this.parentNode;
20905   if (parent) parent.removeChild(this);
20906 }
20907
20908 var selection_remove = function() {
20909   return this.each(remove);
20910 };
20911
20912 var selection_datum = function(value) {
20913   return arguments.length
20914       ? this.property("__data__", value)
20915       : this.node().__data__;
20916 };
20917
20918 function dispatchEvent(node, type, params) {
20919   var window = window$1(node),
20920       event = window.CustomEvent;
20921
20922   if (event) {
20923     event = new event(type, params);
20924   } else {
20925     event = window.document.createEvent("Event");
20926     if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
20927     else event.initEvent(type, false, false);
20928   }
20929
20930   node.dispatchEvent(event);
20931 }
20932
20933 function dispatchConstant(type, params) {
20934   return function() {
20935     return dispatchEvent(this, type, params);
20936   };
20937 }
20938
20939 function dispatchFunction(type, params) {
20940   return function() {
20941     return dispatchEvent(this, type, params.apply(this, arguments));
20942   };
20943 }
20944
20945 var selection_dispatch = function(type, params) {
20946   return this.each((typeof params === "function"
20947       ? dispatchFunction
20948       : dispatchConstant)(type, params));
20949 };
20950
20951 var root = [null];
20952
20953 function Selection(groups, parents) {
20954   this._groups = groups;
20955   this._parents = parents;
20956 }
20957
20958 function selection() {
20959   return new Selection([[document.documentElement]], root);
20960 }
20961
20962 Selection.prototype = selection.prototype = {
20963   constructor: Selection,
20964   select: selection_select,
20965   selectAll: selection_selectAll,
20966   filter: selection_filter,
20967   data: selection_data,
20968   enter: selection_enter,
20969   exit: selection_exit,
20970   merge: selection_merge,
20971   order: selection_order,
20972   sort: selection_sort,
20973   call: selection_call,
20974   nodes: selection_nodes,
20975   node: selection_node,
20976   size: selection_size,
20977   empty: selection_empty,
20978   each: selection_each,
20979   attr: selection_attr,
20980   style: selection_style,
20981   property: selection_property,
20982   classed: selection_classed,
20983   text: selection_text,
20984   html: selection_html,
20985   raise: selection_raise,
20986   lower: selection_lower,
20987   append: selection_append,
20988   insert: selection_insert,
20989   remove: selection_remove,
20990   datum: selection_datum,
20991   on: selection_on,
20992   dispatch: selection_dispatch
20993 };
20994
20995 var select = function(selector) {
20996   return typeof selector === "string"
20997       ? new Selection([[document.querySelector(selector)]], [document.documentElement])
20998       : new Selection([[selector]], root);
20999 };
21000
21001 var selectAll = function(selector) {
21002   return typeof selector === "string"
21003       ? new Selection([document.querySelectorAll(selector)], [document.documentElement])
21004       : new Selection([selector == null ? [] : selector], root);
21005 };
21006
21007 var touch = function(node, touches, identifier) {
21008   if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches;
21009
21010   for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) {
21011     if ((touch = touches[i]).identifier === identifier) {
21012       return point(node, touch);
21013     }
21014   }
21015
21016   return null;
21017 };
21018
21019 var touches = function(node, touches) {
21020   if (touches == null) touches = sourceEvent().touches;
21021
21022   for (var i = 0, n = touches ? touches.length : 0, points = new Array(n); i < n; ++i) {
21023     points[i] = point(node, touches[i]);
21024   }
21025
21026   return points;
21027 };
21028
21029 function nopropagation() {
21030   event.stopImmediatePropagation();
21031 }
21032
21033 var noevent = function() {
21034   event.preventDefault();
21035   event.stopImmediatePropagation();
21036 };
21037
21038 var dragDisable = function(view) {
21039   var root = view.document.documentElement,
21040       selection$$1 = select(view).on("dragstart.drag", noevent, true);
21041   if ("onselectstart" in root) {
21042     selection$$1.on("selectstart.drag", noevent, true);
21043   } else {
21044     root.__noselect = root.style.MozUserSelect;
21045     root.style.MozUserSelect = "none";
21046   }
21047 };
21048
21049 function yesdrag(view, noclick) {
21050   var root = view.document.documentElement,
21051       selection$$1 = select(view).on("dragstart.drag", null);
21052   if (noclick) {
21053     selection$$1.on("click.drag", noevent, true);
21054     setTimeout(function() { selection$$1.on("click.drag", null); }, 0);
21055   }
21056   if ("onselectstart" in root) {
21057     selection$$1.on("selectstart.drag", null);
21058   } else {
21059     root.style.MozUserSelect = root.__noselect;
21060     delete root.__noselect;
21061   }
21062 }
21063
21064 var constant$2 = function(x) {
21065   return function() {
21066     return x;
21067   };
21068 };
21069
21070 function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) {
21071   this.target = target;
21072   this.type = type;
21073   this.subject = subject;
21074   this.identifier = id;
21075   this.active = active;
21076   this.x = x;
21077   this.y = y;
21078   this.dx = dx;
21079   this.dy = dy;
21080   this._ = dispatch;
21081 }
21082
21083 DragEvent.prototype.on = function() {
21084   var value = this._.on.apply(this._, arguments);
21085   return value === this._ ? this : value;
21086 };
21087
21088 // Ignore right-click, since that should open the context menu.
21089 function defaultFilter$1() {
21090   return !event.button;
21091 }
21092
21093 function defaultContainer() {
21094   return this.parentNode;
21095 }
21096
21097 function defaultSubject(d) {
21098   return d == null ? {x: event.x, y: event.y} : d;
21099 }
21100
21101 var drag = function() {
21102   var filter = defaultFilter$1,
21103       container = defaultContainer,
21104       subject = defaultSubject,
21105       gestures = {},
21106       listeners = dispatch("start", "drag", "end"),
21107       active = 0,
21108       mousemoving,
21109       touchending;
21110
21111   function drag(selection$$1) {
21112     selection$$1
21113         .on("mousedown.drag", mousedowned)
21114         .on("touchstart.drag", touchstarted)
21115         .on("touchmove.drag", touchmoved)
21116         .on("touchend.drag touchcancel.drag", touchended)
21117         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
21118   }
21119
21120   function mousedowned() {
21121     if (touchending || !filter.apply(this, arguments)) return;
21122     var gesture = beforestart("mouse", container.apply(this, arguments), mouse, this, arguments);
21123     if (!gesture) return;
21124     select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
21125     dragDisable(event.view);
21126     nopropagation();
21127     mousemoving = false;
21128     gesture("start");
21129   }
21130
21131   function mousemoved() {
21132     noevent();
21133     mousemoving = true;
21134     gestures.mouse("drag");
21135   }
21136
21137   function mouseupped() {
21138     select(event.view).on("mousemove.drag mouseup.drag", null);
21139     yesdrag(event.view, mousemoving);
21140     noevent();
21141     gestures.mouse("end");
21142   }
21143
21144   function touchstarted() {
21145     if (!filter.apply(this, arguments)) return;
21146     var touches$$1 = event.changedTouches,
21147         c = container.apply(this, arguments),
21148         n = touches$$1.length, i, gesture;
21149
21150     for (i = 0; i < n; ++i) {
21151       if (gesture = beforestart(touches$$1[i].identifier, c, touch, this, arguments)) {
21152         nopropagation();
21153         gesture("start");
21154       }
21155     }
21156   }
21157
21158   function touchmoved() {
21159     var touches$$1 = event.changedTouches,
21160         n = touches$$1.length, i, gesture;
21161
21162     for (i = 0; i < n; ++i) {
21163       if (gesture = gestures[touches$$1[i].identifier]) {
21164         noevent();
21165         gesture("drag");
21166       }
21167     }
21168   }
21169
21170   function touchended() {
21171     var touches$$1 = event.changedTouches,
21172         n = touches$$1.length, i, gesture;
21173
21174     if (touchending) clearTimeout(touchending);
21175     touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
21176     for (i = 0; i < n; ++i) {
21177       if (gesture = gestures[touches$$1[i].identifier]) {
21178         nopropagation();
21179         gesture("end");
21180       }
21181     }
21182   }
21183
21184   function beforestart(id, container, point, that, args) {
21185     var p = point(container, id), s, dx, dy,
21186         sublisteners = listeners.copy();
21187
21188     if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() {
21189       if ((event.subject = s = subject.apply(that, args)) == null) return false;
21190       dx = s.x - p[0] || 0;
21191       dy = s.y - p[1] || 0;
21192       return true;
21193     })) return;
21194
21195     return function gesture(type) {
21196       var p0 = p, n;
21197       switch (type) {
21198         case "start": gestures[id] = gesture, n = active++; break;
21199         case "end": delete gestures[id], --active; // nobreak
21200         case "drag": p = point(container, id), n = active; break;
21201       }
21202       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]);
21203     };
21204   }
21205
21206   drag.filter = function(_) {
21207     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter;
21208   };
21209
21210   drag.container = function(_) {
21211     return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container;
21212   };
21213
21214   drag.subject = function(_) {
21215     return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject;
21216   };
21217
21218   drag.on = function() {
21219     var value = listeners.on.apply(listeners, arguments);
21220     return value === listeners ? drag : value;
21221   };
21222
21223   return drag;
21224 };
21225
21226 var define = function(constructor, factory, prototype) {
21227   constructor.prototype = factory.prototype = prototype;
21228   prototype.constructor = constructor;
21229 };
21230
21231 function extend(parent, definition) {
21232   var prototype = Object.create(parent.prototype);
21233   for (var key in definition) prototype[key] = definition[key];
21234   return prototype;
21235 }
21236
21237 function Color() {}
21238
21239 var darker = 0.7;
21240 var brighter = 1 / darker;
21241
21242 var reI = "\\s*([+-]?\\d+)\\s*";
21243 var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*";
21244 var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
21245 var reHex3 = /^#([0-9a-f]{3})$/;
21246 var reHex6 = /^#([0-9a-f]{6})$/;
21247 var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$");
21248 var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$");
21249 var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$");
21250 var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$");
21251 var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$");
21252 var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
21253
21254 var named = {
21255   aliceblue: 0xf0f8ff,
21256   antiquewhite: 0xfaebd7,
21257   aqua: 0x00ffff,
21258   aquamarine: 0x7fffd4,
21259   azure: 0xf0ffff,
21260   beige: 0xf5f5dc,
21261   bisque: 0xffe4c4,
21262   black: 0x000000,
21263   blanchedalmond: 0xffebcd,
21264   blue: 0x0000ff,
21265   blueviolet: 0x8a2be2,
21266   brown: 0xa52a2a,
21267   burlywood: 0xdeb887,
21268   cadetblue: 0x5f9ea0,
21269   chartreuse: 0x7fff00,
21270   chocolate: 0xd2691e,
21271   coral: 0xff7f50,
21272   cornflowerblue: 0x6495ed,
21273   cornsilk: 0xfff8dc,
21274   crimson: 0xdc143c,
21275   cyan: 0x00ffff,
21276   darkblue: 0x00008b,
21277   darkcyan: 0x008b8b,
21278   darkgoldenrod: 0xb8860b,
21279   darkgray: 0xa9a9a9,
21280   darkgreen: 0x006400,
21281   darkgrey: 0xa9a9a9,
21282   darkkhaki: 0xbdb76b,
21283   darkmagenta: 0x8b008b,
21284   darkolivegreen: 0x556b2f,
21285   darkorange: 0xff8c00,
21286   darkorchid: 0x9932cc,
21287   darkred: 0x8b0000,
21288   darksalmon: 0xe9967a,
21289   darkseagreen: 0x8fbc8f,
21290   darkslateblue: 0x483d8b,
21291   darkslategray: 0x2f4f4f,
21292   darkslategrey: 0x2f4f4f,
21293   darkturquoise: 0x00ced1,
21294   darkviolet: 0x9400d3,
21295   deeppink: 0xff1493,
21296   deepskyblue: 0x00bfff,
21297   dimgray: 0x696969,
21298   dimgrey: 0x696969,
21299   dodgerblue: 0x1e90ff,
21300   firebrick: 0xb22222,
21301   floralwhite: 0xfffaf0,
21302   forestgreen: 0x228b22,
21303   fuchsia: 0xff00ff,
21304   gainsboro: 0xdcdcdc,
21305   ghostwhite: 0xf8f8ff,
21306   gold: 0xffd700,
21307   goldenrod: 0xdaa520,
21308   gray: 0x808080,
21309   green: 0x008000,
21310   greenyellow: 0xadff2f,
21311   grey: 0x808080,
21312   honeydew: 0xf0fff0,
21313   hotpink: 0xff69b4,
21314   indianred: 0xcd5c5c,
21315   indigo: 0x4b0082,
21316   ivory: 0xfffff0,
21317   khaki: 0xf0e68c,
21318   lavender: 0xe6e6fa,
21319   lavenderblush: 0xfff0f5,
21320   lawngreen: 0x7cfc00,
21321   lemonchiffon: 0xfffacd,
21322   lightblue: 0xadd8e6,
21323   lightcoral: 0xf08080,
21324   lightcyan: 0xe0ffff,
21325   lightgoldenrodyellow: 0xfafad2,
21326   lightgray: 0xd3d3d3,
21327   lightgreen: 0x90ee90,
21328   lightgrey: 0xd3d3d3,
21329   lightpink: 0xffb6c1,
21330   lightsalmon: 0xffa07a,
21331   lightseagreen: 0x20b2aa,
21332   lightskyblue: 0x87cefa,
21333   lightslategray: 0x778899,
21334   lightslategrey: 0x778899,
21335   lightsteelblue: 0xb0c4de,
21336   lightyellow: 0xffffe0,
21337   lime: 0x00ff00,
21338   limegreen: 0x32cd32,
21339   linen: 0xfaf0e6,
21340   magenta: 0xff00ff,
21341   maroon: 0x800000,
21342   mediumaquamarine: 0x66cdaa,
21343   mediumblue: 0x0000cd,
21344   mediumorchid: 0xba55d3,
21345   mediumpurple: 0x9370db,
21346   mediumseagreen: 0x3cb371,
21347   mediumslateblue: 0x7b68ee,
21348   mediumspringgreen: 0x00fa9a,
21349   mediumturquoise: 0x48d1cc,
21350   mediumvioletred: 0xc71585,
21351   midnightblue: 0x191970,
21352   mintcream: 0xf5fffa,
21353   mistyrose: 0xffe4e1,
21354   moccasin: 0xffe4b5,
21355   navajowhite: 0xffdead,
21356   navy: 0x000080,
21357   oldlace: 0xfdf5e6,
21358   olive: 0x808000,
21359   olivedrab: 0x6b8e23,
21360   orange: 0xffa500,
21361   orangered: 0xff4500,
21362   orchid: 0xda70d6,
21363   palegoldenrod: 0xeee8aa,
21364   palegreen: 0x98fb98,
21365   paleturquoise: 0xafeeee,
21366   palevioletred: 0xdb7093,
21367   papayawhip: 0xffefd5,
21368   peachpuff: 0xffdab9,
21369   peru: 0xcd853f,
21370   pink: 0xffc0cb,
21371   plum: 0xdda0dd,
21372   powderblue: 0xb0e0e6,
21373   purple: 0x800080,
21374   rebeccapurple: 0x663399,
21375   red: 0xff0000,
21376   rosybrown: 0xbc8f8f,
21377   royalblue: 0x4169e1,
21378   saddlebrown: 0x8b4513,
21379   salmon: 0xfa8072,
21380   sandybrown: 0xf4a460,
21381   seagreen: 0x2e8b57,
21382   seashell: 0xfff5ee,
21383   sienna: 0xa0522d,
21384   silver: 0xc0c0c0,
21385   skyblue: 0x87ceeb,
21386   slateblue: 0x6a5acd,
21387   slategray: 0x708090,
21388   slategrey: 0x708090,
21389   snow: 0xfffafa,
21390   springgreen: 0x00ff7f,
21391   steelblue: 0x4682b4,
21392   tan: 0xd2b48c,
21393   teal: 0x008080,
21394   thistle: 0xd8bfd8,
21395   tomato: 0xff6347,
21396   turquoise: 0x40e0d0,
21397   violet: 0xee82ee,
21398   wheat: 0xf5deb3,
21399   white: 0xffffff,
21400   whitesmoke: 0xf5f5f5,
21401   yellow: 0xffff00,
21402   yellowgreen: 0x9acd32
21403 };
21404
21405 define(Color, color, {
21406   displayable: function() {
21407     return this.rgb().displayable();
21408   },
21409   toString: function() {
21410     return this.rgb() + "";
21411   }
21412 });
21413
21414 function color(format) {
21415   var m;
21416   format = (format + "").trim().toLowerCase();
21417   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
21418       : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
21419       : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
21420       : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
21421       : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
21422       : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
21423       : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
21424       : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
21425       : named.hasOwnProperty(format) ? rgbn(named[format])
21426       : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
21427       : null;
21428 }
21429
21430 function rgbn(n) {
21431   return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
21432 }
21433
21434 function rgba(r, g, b, a) {
21435   if (a <= 0) r = g = b = NaN;
21436   return new Rgb(r, g, b, a);
21437 }
21438
21439 function rgbConvert(o) {
21440   if (!(o instanceof Color)) o = color(o);
21441   if (!o) return new Rgb;
21442   o = o.rgb();
21443   return new Rgb(o.r, o.g, o.b, o.opacity);
21444 }
21445
21446 function rgb(r, g, b, opacity) {
21447   return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
21448 }
21449
21450 function Rgb(r, g, b, opacity) {
21451   this.r = +r;
21452   this.g = +g;
21453   this.b = +b;
21454   this.opacity = +opacity;
21455 }
21456
21457 define(Rgb, rgb, extend(Color, {
21458   brighter: function(k) {
21459     k = k == null ? brighter : Math.pow(brighter, k);
21460     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21461   },
21462   darker: function(k) {
21463     k = k == null ? darker : Math.pow(darker, k);
21464     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21465   },
21466   rgb: function() {
21467     return this;
21468   },
21469   displayable: function() {
21470     return (0 <= this.r && this.r <= 255)
21471         && (0 <= this.g && this.g <= 255)
21472         && (0 <= this.b && this.b <= 255)
21473         && (0 <= this.opacity && this.opacity <= 1);
21474   },
21475   toString: function() {
21476     var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
21477     return (a === 1 ? "rgb(" : "rgba(")
21478         + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
21479         + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
21480         + Math.max(0, Math.min(255, Math.round(this.b) || 0))
21481         + (a === 1 ? ")" : ", " + a + ")");
21482   }
21483 }));
21484
21485 function hsla(h, s, l, a) {
21486   if (a <= 0) h = s = l = NaN;
21487   else if (l <= 0 || l >= 1) h = s = NaN;
21488   else if (s <= 0) h = NaN;
21489   return new Hsl(h, s, l, a);
21490 }
21491
21492 function hslConvert(o) {
21493   if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
21494   if (!(o instanceof Color)) o = color(o);
21495   if (!o) return new Hsl;
21496   if (o instanceof Hsl) return o;
21497   o = o.rgb();
21498   var r = o.r / 255,
21499       g = o.g / 255,
21500       b = o.b / 255,
21501       min = Math.min(r, g, b),
21502       max = Math.max(r, g, b),
21503       h = NaN,
21504       s = max - min,
21505       l = (max + min) / 2;
21506   if (s) {
21507     if (r === max) h = (g - b) / s + (g < b) * 6;
21508     else if (g === max) h = (b - r) / s + 2;
21509     else h = (r - g) / s + 4;
21510     s /= l < 0.5 ? max + min : 2 - max - min;
21511     h *= 60;
21512   } else {
21513     s = l > 0 && l < 1 ? 0 : h;
21514   }
21515   return new Hsl(h, s, l, o.opacity);
21516 }
21517
21518 function hsl(h, s, l, opacity) {
21519   return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
21520 }
21521
21522 function Hsl(h, s, l, opacity) {
21523   this.h = +h;
21524   this.s = +s;
21525   this.l = +l;
21526   this.opacity = +opacity;
21527 }
21528
21529 define(Hsl, hsl, extend(Color, {
21530   brighter: function(k) {
21531     k = k == null ? brighter : Math.pow(brighter, k);
21532     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21533   },
21534   darker: function(k) {
21535     k = k == null ? darker : Math.pow(darker, k);
21536     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21537   },
21538   rgb: function() {
21539     var h = this.h % 360 + (this.h < 0) * 360,
21540         s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
21541         l = this.l,
21542         m2 = l + (l < 0.5 ? l : 1 - l) * s,
21543         m1 = 2 * l - m2;
21544     return new Rgb(
21545       hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
21546       hsl2rgb(h, m1, m2),
21547       hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
21548       this.opacity
21549     );
21550   },
21551   displayable: function() {
21552     return (0 <= this.s && this.s <= 1 || isNaN(this.s))
21553         && (0 <= this.l && this.l <= 1)
21554         && (0 <= this.opacity && this.opacity <= 1);
21555   }
21556 }));
21557
21558 /* From FvD 13.37, CSS Color Module Level 3 */
21559 function hsl2rgb(h, m1, m2) {
21560   return (h < 60 ? m1 + (m2 - m1) * h / 60
21561       : h < 180 ? m2
21562       : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
21563       : m1) * 255;
21564 }
21565
21566 var deg2rad = Math.PI / 180;
21567 var rad2deg = 180 / Math.PI;
21568
21569 var Kn = 18;
21570 var Xn = 0.950470;
21571 var Yn = 1;
21572 var Zn = 1.088830;
21573 var t0 = 4 / 29;
21574 var t1 = 6 / 29;
21575 var t2 = 3 * t1 * t1;
21576 var t3 = t1 * t1 * t1;
21577
21578 function labConvert(o) {
21579   if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
21580   if (o instanceof Hcl) {
21581     var h = o.h * deg2rad;
21582     return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
21583   }
21584   if (!(o instanceof Rgb)) o = rgbConvert(o);
21585   var b = rgb2xyz(o.r),
21586       a = rgb2xyz(o.g),
21587       l = rgb2xyz(o.b),
21588       x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
21589       y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
21590       z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
21591   return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
21592 }
21593
21594 function lab(l, a, b, opacity) {
21595   return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
21596 }
21597
21598 function Lab(l, a, b, opacity) {
21599   this.l = +l;
21600   this.a = +a;
21601   this.b = +b;
21602   this.opacity = +opacity;
21603 }
21604
21605 define(Lab, lab, extend(Color, {
21606   brighter: function(k) {
21607     return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21608   },
21609   darker: function(k) {
21610     return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21611   },
21612   rgb: function() {
21613     var y = (this.l + 16) / 116,
21614         x = isNaN(this.a) ? y : y + this.a / 500,
21615         z = isNaN(this.b) ? y : y - this.b / 200;
21616     y = Yn * lab2xyz(y);
21617     x = Xn * lab2xyz(x);
21618     z = Zn * lab2xyz(z);
21619     return new Rgb(
21620       xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
21621       xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
21622       xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
21623       this.opacity
21624     );
21625   }
21626 }));
21627
21628 function xyz2lab(t) {
21629   return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
21630 }
21631
21632 function lab2xyz(t) {
21633   return t > t1 ? t * t * t : t2 * (t - t0);
21634 }
21635
21636 function xyz2rgb(x) {
21637   return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
21638 }
21639
21640 function rgb2xyz(x) {
21641   return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
21642 }
21643
21644 function hclConvert(o) {
21645   if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
21646   if (!(o instanceof Lab)) o = labConvert(o);
21647   var h = Math.atan2(o.b, o.a) * rad2deg;
21648   return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
21649 }
21650
21651 function hcl(h, c, l, opacity) {
21652   return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
21653 }
21654
21655 function Hcl(h, c, l, opacity) {
21656   this.h = +h;
21657   this.c = +c;
21658   this.l = +l;
21659   this.opacity = +opacity;
21660 }
21661
21662 define(Hcl, hcl, extend(Color, {
21663   brighter: function(k) {
21664     return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
21665   },
21666   darker: function(k) {
21667     return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
21668   },
21669   rgb: function() {
21670     return labConvert(this).rgb();
21671   }
21672 }));
21673
21674 var A = -0.14861;
21675 var B = +1.78277;
21676 var C = -0.29227;
21677 var D = -0.90649;
21678 var E = +1.97294;
21679 var ED = E * D;
21680 var EB = E * B;
21681 var BC_DA = B * C - D * A;
21682
21683 function cubehelixConvert(o) {
21684   if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
21685   if (!(o instanceof Rgb)) o = rgbConvert(o);
21686   var r = o.r / 255,
21687       g = o.g / 255,
21688       b = o.b / 255,
21689       l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
21690       bl = b - l,
21691       k = (E * (g - l) - C * bl) / D,
21692       s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
21693       h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
21694   return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
21695 }
21696
21697 function cubehelix(h, s, l, opacity) {
21698   return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
21699 }
21700
21701 function Cubehelix(h, s, l, opacity) {
21702   this.h = +h;
21703   this.s = +s;
21704   this.l = +l;
21705   this.opacity = +opacity;
21706 }
21707
21708 define(Cubehelix, cubehelix, extend(Color, {
21709   brighter: function(k) {
21710     k = k == null ? brighter : Math.pow(brighter, k);
21711     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21712   },
21713   darker: function(k) {
21714     k = k == null ? darker : Math.pow(darker, k);
21715     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21716   },
21717   rgb: function() {
21718     var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
21719         l = +this.l,
21720         a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
21721         cosh = Math.cos(h),
21722         sinh = Math.sin(h);
21723     return new Rgb(
21724       255 * (l + a * (A * cosh + B * sinh)),
21725       255 * (l + a * (C * cosh + D * sinh)),
21726       255 * (l + a * (E * cosh)),
21727       this.opacity
21728     );
21729   }
21730 }));
21731
21732 function basis(t1, v0, v1, v2, v3) {
21733   var t2 = t1 * t1, t3 = t2 * t1;
21734   return ((1 - 3 * t1 + 3 * t2 - t3) * v0
21735       + (4 - 6 * t2 + 3 * t3) * v1
21736       + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
21737       + t3 * v3) / 6;
21738 }
21739
21740 var basis$1 = function(values) {
21741   var n = values.length - 1;
21742   return function(t) {
21743     var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
21744         v1 = values[i],
21745         v2 = values[i + 1],
21746         v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
21747         v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
21748     return basis((t - i / n) * n, v0, v1, v2, v3);
21749   };
21750 };
21751
21752 var basisClosed = function(values) {
21753   var n = values.length;
21754   return function(t) {
21755     var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
21756         v0 = values[(i + n - 1) % n],
21757         v1 = values[i % n],
21758         v2 = values[(i + 1) % n],
21759         v3 = values[(i + 2) % n];
21760     return basis((t - i / n) * n, v0, v1, v2, v3);
21761   };
21762 };
21763
21764 var constant$3 = function(x) {
21765   return function() {
21766     return x;
21767   };
21768 };
21769
21770 function linear(a, d) {
21771   return function(t) {
21772     return a + t * d;
21773   };
21774 }
21775
21776 function exponential(a, b, y) {
21777   return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
21778     return Math.pow(a + t * b, y);
21779   };
21780 }
21781
21782 function hue(a, b) {
21783   var d = b - a;
21784   return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$3(isNaN(a) ? b : a);
21785 }
21786
21787 function gamma(y) {
21788   return (y = +y) === 1 ? nogamma : function(a, b) {
21789     return b - a ? exponential(a, b, y) : constant$3(isNaN(a) ? b : a);
21790   };
21791 }
21792
21793 function nogamma(a, b) {
21794   var d = b - a;
21795   return d ? linear(a, d) : constant$3(isNaN(a) ? b : a);
21796 }
21797
21798 var interpolateRgb = ((function rgbGamma(y) {
21799   var color$$1 = gamma(y);
21800
21801   function rgb$$1(start, end) {
21802     var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r),
21803         g = color$$1(start.g, end.g),
21804         b = color$$1(start.b, end.b),
21805         opacity = nogamma(start.opacity, end.opacity);
21806     return function(t) {
21807       start.r = r(t);
21808       start.g = g(t);
21809       start.b = b(t);
21810       start.opacity = opacity(t);
21811       return start + "";
21812     };
21813   }
21814
21815   rgb$$1.gamma = rgbGamma;
21816
21817   return rgb$$1;
21818 }))(1);
21819
21820 function rgbSpline(spline) {
21821   return function(colors) {
21822     var n = colors.length,
21823         r = new Array(n),
21824         g = new Array(n),
21825         b = new Array(n),
21826         i, color$$1;
21827     for (i = 0; i < n; ++i) {
21828       color$$1 = rgb(colors[i]);
21829       r[i] = color$$1.r || 0;
21830       g[i] = color$$1.g || 0;
21831       b[i] = color$$1.b || 0;
21832     }
21833     r = spline(r);
21834     g = spline(g);
21835     b = spline(b);
21836     color$$1.opacity = 1;
21837     return function(t) {
21838       color$$1.r = r(t);
21839       color$$1.g = g(t);
21840       color$$1.b = b(t);
21841       return color$$1 + "";
21842     };
21843   };
21844 }
21845
21846 var rgbBasis = rgbSpline(basis$1);
21847 var rgbBasisClosed = rgbSpline(basisClosed);
21848
21849 var array$1 = function(a, b) {
21850   var nb = b ? b.length : 0,
21851       na = a ? Math.min(nb, a.length) : 0,
21852       x = new Array(nb),
21853       c = new Array(nb),
21854       i;
21855
21856   for (i = 0; i < na; ++i) x[i] = interpolateValue(a[i], b[i]);
21857   for (; i < nb; ++i) c[i] = b[i];
21858
21859   return function(t) {
21860     for (i = 0; i < na; ++i) c[i] = x[i](t);
21861     return c;
21862   };
21863 };
21864
21865 var date = function(a, b) {
21866   var d = new Date;
21867   return a = +a, b -= a, function(t) {
21868     return d.setTime(a + b * t), d;
21869   };
21870 };
21871
21872 var reinterpolate = function(a, b) {
21873   return a = +a, b -= a, function(t) {
21874     return a + b * t;
21875   };
21876 };
21877
21878 var object = function(a, b) {
21879   var i = {},
21880       c = {},
21881       k;
21882
21883   if (a === null || typeof a !== "object") a = {};
21884   if (b === null || typeof b !== "object") b = {};
21885
21886   for (k in b) {
21887     if (k in a) {
21888       i[k] = interpolateValue(a[k], b[k]);
21889     } else {
21890       c[k] = b[k];
21891     }
21892   }
21893
21894   return function(t) {
21895     for (k in i) c[k] = i[k](t);
21896     return c;
21897   };
21898 };
21899
21900 var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
21901 var reB = new RegExp(reA.source, "g");
21902
21903 function zero(b) {
21904   return function() {
21905     return b;
21906   };
21907 }
21908
21909 function one(b) {
21910   return function(t) {
21911     return b(t) + "";
21912   };
21913 }
21914
21915 var interpolateString = function(a, b) {
21916   var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
21917       am, // current match in a
21918       bm, // current match in b
21919       bs, // string preceding current number in b, if any
21920       i = -1, // index in s
21921       s = [], // string constants and placeholders
21922       q = []; // number interpolators
21923
21924   // Coerce inputs to strings.
21925   a = a + "", b = b + "";
21926
21927   // Interpolate pairs of numbers in a & b.
21928   while ((am = reA.exec(a))
21929       && (bm = reB.exec(b))) {
21930     if ((bs = bm.index) > bi) { // a string precedes the next number in b
21931       bs = b.slice(bi, bs);
21932       if (s[i]) s[i] += bs; // coalesce with previous string
21933       else s[++i] = bs;
21934     }
21935     if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
21936       if (s[i]) s[i] += bm; // coalesce with previous string
21937       else s[++i] = bm;
21938     } else { // interpolate non-matching numbers
21939       s[++i] = null;
21940       q.push({i: i, x: reinterpolate(am, bm)});
21941     }
21942     bi = reB.lastIndex;
21943   }
21944
21945   // Add remains of b.
21946   if (bi < b.length) {
21947     bs = b.slice(bi);
21948     if (s[i]) s[i] += bs; // coalesce with previous string
21949     else s[++i] = bs;
21950   }
21951
21952   // Special optimization for only a single match.
21953   // Otherwise, interpolate each of the numbers and rejoin the string.
21954   return s.length < 2 ? (q[0]
21955       ? one(q[0].x)
21956       : zero(b))
21957       : (b = q.length, function(t) {
21958           for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
21959           return s.join("");
21960         });
21961 };
21962
21963 var interpolateValue = function(a, b) {
21964   var t = typeof b, c;
21965   return b == null || t === "boolean" ? constant$3(b)
21966       : (t === "number" ? reinterpolate
21967       : t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString)
21968       : b instanceof color ? interpolateRgb
21969       : b instanceof Date ? date
21970       : Array.isArray(b) ? array$1
21971       : isNaN(b) ? object
21972       : reinterpolate)(a, b);
21973 };
21974
21975 var interpolateRound = function(a, b) {
21976   return a = +a, b -= a, function(t) {
21977     return Math.round(a + b * t);
21978   };
21979 };
21980
21981 var degrees = 180 / Math.PI;
21982
21983 var identity$2 = {
21984   translateX: 0,
21985   translateY: 0,
21986   rotate: 0,
21987   skewX: 0,
21988   scaleX: 1,
21989   scaleY: 1
21990 };
21991
21992 var decompose = function(a, b, c, d, e, f) {
21993   var scaleX, scaleY, skewX;
21994   if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
21995   if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
21996   if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
21997   if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
21998   return {
21999     translateX: e,
22000     translateY: f,
22001     rotate: Math.atan2(b, a) * degrees,
22002     skewX: Math.atan(skewX) * degrees,
22003     scaleX: scaleX,
22004     scaleY: scaleY
22005   };
22006 };
22007
22008 var cssNode;
22009 var cssRoot;
22010 var cssView;
22011 var svgNode;
22012
22013 function parseCss(value) {
22014   if (value === "none") return identity$2;
22015   if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
22016   cssNode.style.transform = value;
22017   value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
22018   cssRoot.removeChild(cssNode);
22019   value = value.slice(7, -1).split(",");
22020   return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
22021 }
22022
22023 function parseSvg(value) {
22024   if (value == null) return identity$2;
22025   if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
22026   svgNode.setAttribute("transform", value);
22027   if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2;
22028   value = value.matrix;
22029   return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
22030 }
22031
22032 function interpolateTransform(parse, pxComma, pxParen, degParen) {
22033
22034   function pop(s) {
22035     return s.length ? s.pop() + " " : "";
22036   }
22037
22038   function translate(xa, ya, xb, yb, s, q) {
22039     if (xa !== xb || ya !== yb) {
22040       var i = s.push("translate(", null, pxComma, null, pxParen);
22041       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22042     } else if (xb || yb) {
22043       s.push("translate(" + xb + pxComma + yb + pxParen);
22044     }
22045   }
22046
22047   function rotate(a, b, s, q) {
22048     if (a !== b) {
22049       if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
22050       q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: reinterpolate(a, b)});
22051     } else if (b) {
22052       s.push(pop(s) + "rotate(" + b + degParen);
22053     }
22054   }
22055
22056   function skewX(a, b, s, q) {
22057     if (a !== b) {
22058       q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: reinterpolate(a, b)});
22059     } else if (b) {
22060       s.push(pop(s) + "skewX(" + b + degParen);
22061     }
22062   }
22063
22064   function scale(xa, ya, xb, yb, s, q) {
22065     if (xa !== xb || ya !== yb) {
22066       var i = s.push(pop(s) + "scale(", null, ",", null, ")");
22067       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22068     } else if (xb !== 1 || yb !== 1) {
22069       s.push(pop(s) + "scale(" + xb + "," + yb + ")");
22070     }
22071   }
22072
22073   return function(a, b) {
22074     var s = [], // string constants and placeholders
22075         q = []; // number interpolators
22076     a = parse(a), b = parse(b);
22077     translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
22078     rotate(a.rotate, b.rotate, s, q);
22079     skewX(a.skewX, b.skewX, s, q);
22080     scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
22081     a = b = null; // gc
22082     return function(t) {
22083       var i = -1, n = q.length, o;
22084       while (++i < n) s[(o = q[i]).i] = o.x(t);
22085       return s.join("");
22086     };
22087   };
22088 }
22089
22090 var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
22091 var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
22092
22093 var rho = Math.SQRT2;
22094 var rho2 = 2;
22095 var rho4 = 4;
22096 var epsilon2 = 1e-12;
22097
22098 function cosh(x) {
22099   return ((x = Math.exp(x)) + 1 / x) / 2;
22100 }
22101
22102 function sinh(x) {
22103   return ((x = Math.exp(x)) - 1 / x) / 2;
22104 }
22105
22106 function tanh(x) {
22107   return ((x = Math.exp(2 * x)) - 1) / (x + 1);
22108 }
22109
22110 // p0 = [ux0, uy0, w0]
22111 // p1 = [ux1, uy1, w1]
22112 var interpolateZoom = function(p0, p1) {
22113   var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
22114       ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
22115       dx = ux1 - ux0,
22116       dy = uy1 - uy0,
22117       d2 = dx * dx + dy * dy,
22118       i,
22119       S;
22120
22121   // Special case for u0 ≅ u1.
22122   if (d2 < epsilon2) {
22123     S = Math.log(w1 / w0) / rho;
22124     i = function(t) {
22125       return [
22126         ux0 + t * dx,
22127         uy0 + t * dy,
22128         w0 * Math.exp(rho * t * S)
22129       ];
22130     };
22131   }
22132
22133   // General case.
22134   else {
22135     var d1 = Math.sqrt(d2),
22136         b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
22137         b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
22138         r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
22139         r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
22140     S = (r1 - r0) / rho;
22141     i = function(t) {
22142       var s = t * S,
22143           coshr0 = cosh(r0),
22144           u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
22145       return [
22146         ux0 + u * dx,
22147         uy0 + u * dy,
22148         w0 * coshr0 / cosh(rho * s + r0)
22149       ];
22150     };
22151   }
22152
22153   i.duration = S * 1000;
22154
22155   return i;
22156 };
22157
22158 function hsl$1(hue$$1) {
22159   return function(start, end) {
22160     var h = hue$$1((start = hsl(start)).h, (end = hsl(end)).h),
22161         s = nogamma(start.s, end.s),
22162         l = nogamma(start.l, end.l),
22163         opacity = nogamma(start.opacity, end.opacity);
22164     return function(t) {
22165       start.h = h(t);
22166       start.s = s(t);
22167       start.l = l(t);
22168       start.opacity = opacity(t);
22169       return start + "";
22170     };
22171   }
22172 }
22173
22174 var hsl$2 = hsl$1(hue);
22175 var hslLong = hsl$1(nogamma);
22176
22177 function lab$1(start, end) {
22178   var l = nogamma((start = lab(start)).l, (end = lab(end)).l),
22179       a = nogamma(start.a, end.a),
22180       b = nogamma(start.b, end.b),
22181       opacity = nogamma(start.opacity, end.opacity);
22182   return function(t) {
22183     start.l = l(t);
22184     start.a = a(t);
22185     start.b = b(t);
22186     start.opacity = opacity(t);
22187     return start + "";
22188   };
22189 }
22190
22191 function hcl$1(hue$$1) {
22192   return function(start, end) {
22193     var h = hue$$1((start = hcl(start)).h, (end = hcl(end)).h),
22194         c = nogamma(start.c, end.c),
22195         l = nogamma(start.l, end.l),
22196         opacity = nogamma(start.opacity, end.opacity);
22197     return function(t) {
22198       start.h = h(t);
22199       start.c = c(t);
22200       start.l = l(t);
22201       start.opacity = opacity(t);
22202       return start + "";
22203     };
22204   }
22205 }
22206
22207 var hcl$2 = hcl$1(hue);
22208 var hclLong = hcl$1(nogamma);
22209
22210 function cubehelix$1(hue$$1) {
22211   return (function cubehelixGamma(y) {
22212     y = +y;
22213
22214     function cubehelix$$1(start, end) {
22215       var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h),
22216           s = nogamma(start.s, end.s),
22217           l = nogamma(start.l, end.l),
22218           opacity = nogamma(start.opacity, end.opacity);
22219       return function(t) {
22220         start.h = h(t);
22221         start.s = s(t);
22222         start.l = l(Math.pow(t, y));
22223         start.opacity = opacity(t);
22224         return start + "";
22225       };
22226     }
22227
22228     cubehelix$$1.gamma = cubehelixGamma;
22229
22230     return cubehelix$$1;
22231   })(1);
22232 }
22233
22234 var cubehelix$2 = cubehelix$1(hue);
22235 var cubehelixLong = cubehelix$1(nogamma);
22236
22237 var quantize = function(interpolator, n) {
22238   var samples = new Array(n);
22239   for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
22240   return samples;
22241 };
22242
22243 var frame = 0;
22244 var timeout = 0;
22245 var interval = 0;
22246 var pokeDelay = 1000;
22247 var taskHead;
22248 var taskTail;
22249 var clockLast = 0;
22250 var clockNow = 0;
22251 var clockSkew = 0;
22252 var clock = typeof performance === "object" && performance.now ? performance : Date;
22253 var setFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : function(f) { setTimeout(f, 17); };
22254
22255 function now() {
22256   return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
22257 }
22258
22259 function clearNow() {
22260   clockNow = 0;
22261 }
22262
22263 function Timer() {
22264   this._call =
22265   this._time =
22266   this._next = null;
22267 }
22268
22269 Timer.prototype = timer.prototype = {
22270   constructor: Timer,
22271   restart: function(callback, delay, time) {
22272     if (typeof callback !== "function") throw new TypeError("callback is not a function");
22273     time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
22274     if (!this._next && taskTail !== this) {
22275       if (taskTail) taskTail._next = this;
22276       else taskHead = this;
22277       taskTail = this;
22278     }
22279     this._call = callback;
22280     this._time = time;
22281     sleep();
22282   },
22283   stop: function() {
22284     if (this._call) {
22285       this._call = null;
22286       this._time = Infinity;
22287       sleep();
22288     }
22289   }
22290 };
22291
22292 function timer(callback, delay, time) {
22293   var t = new Timer;
22294   t.restart(callback, delay, time);
22295   return t;
22296 }
22297
22298 function timerFlush() {
22299   now(); // Get the current time, if not already set.
22300   ++frame; // Pretend we’ve set an alarm, if we haven’t already.
22301   var t = taskHead, e;
22302   while (t) {
22303     if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
22304     t = t._next;
22305   }
22306   --frame;
22307 }
22308
22309 function wake() {
22310   clockNow = (clockLast = clock.now()) + clockSkew;
22311   frame = timeout = 0;
22312   try {
22313     timerFlush();
22314   } finally {
22315     frame = 0;
22316     nap();
22317     clockNow = 0;
22318   }
22319 }
22320
22321 function poke() {
22322   var now = clock.now(), delay = now - clockLast;
22323   if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
22324 }
22325
22326 function nap() {
22327   var t0, t1 = taskHead, t2, time = Infinity;
22328   while (t1) {
22329     if (t1._call) {
22330       if (time > t1._time) time = t1._time;
22331       t0 = t1, t1 = t1._next;
22332     } else {
22333       t2 = t1._next, t1._next = null;
22334       t1 = t0 ? t0._next = t2 : taskHead = t2;
22335     }
22336   }
22337   taskTail = t0;
22338   sleep(time);
22339 }
22340
22341 function sleep(time) {
22342   if (frame) return; // Soonest alarm already set, or will be.
22343   if (timeout) timeout = clearTimeout(timeout);
22344   var delay = time - clockNow;
22345   if (delay > 24) {
22346     if (time < Infinity) timeout = setTimeout(wake, delay);
22347     if (interval) interval = clearInterval(interval);
22348   } else {
22349     if (!interval) clockLast = clockNow, interval = setInterval(poke, pokeDelay);
22350     frame = 1, setFrame(wake);
22351   }
22352 }
22353
22354 var timeout$1 = function(callback, delay, time) {
22355   var t = new Timer;
22356   delay = delay == null ? 0 : +delay;
22357   t.restart(function(elapsed) {
22358     t.stop();
22359     callback(elapsed + delay);
22360   }, delay, time);
22361   return t;
22362 };
22363
22364 var interval$1 = function(callback, delay, time) {
22365   var t = new Timer, total = delay;
22366   if (delay == null) return t.restart(callback, delay, time), t;
22367   delay = +delay, time = time == null ? now() : +time;
22368   t.restart(function tick(elapsed) {
22369     elapsed += total;
22370     t.restart(tick, total += delay, time);
22371     callback(elapsed);
22372   }, delay, time);
22373   return t;
22374 };
22375
22376 var emptyOn = dispatch("start", "end", "interrupt");
22377 var emptyTween = [];
22378
22379 var CREATED = 0;
22380 var SCHEDULED = 1;
22381 var STARTING = 2;
22382 var STARTED = 3;
22383 var RUNNING = 4;
22384 var ENDING = 5;
22385 var ENDED = 6;
22386
22387 var schedule = function(node, name, id, index, group, timing) {
22388   var schedules = node.__transition;
22389   if (!schedules) node.__transition = {};
22390   else if (id in schedules) return;
22391   create(node, id, {
22392     name: name,
22393     index: index, // For context during callback.
22394     group: group, // For context during callback.
22395     on: emptyOn,
22396     tween: emptyTween,
22397     time: timing.time,
22398     delay: timing.delay,
22399     duration: timing.duration,
22400     ease: timing.ease,
22401     timer: null,
22402     state: CREATED
22403   });
22404 };
22405
22406 function init(node, id) {
22407   var schedule = node.__transition;
22408   if (!schedule || !(schedule = schedule[id]) || schedule.state > CREATED) throw new Error("too late");
22409   return schedule;
22410 }
22411
22412 function set$1(node, id) {
22413   var schedule = node.__transition;
22414   if (!schedule || !(schedule = schedule[id]) || schedule.state > STARTING) throw new Error("too late");
22415   return schedule;
22416 }
22417
22418 function get$1(node, id) {
22419   var schedule = node.__transition;
22420   if (!schedule || !(schedule = schedule[id])) throw new Error("too late");
22421   return schedule;
22422 }
22423
22424 function create(node, id, self) {
22425   var schedules = node.__transition,
22426       tween;
22427
22428   // Initialize the self timer when the transition is created.
22429   // Note the actual delay is not known until the first callback!
22430   schedules[id] = self;
22431   self.timer = timer(schedule, 0, self.time);
22432
22433   function schedule(elapsed) {
22434     self.state = SCHEDULED;
22435     self.timer.restart(start, self.delay, self.time);
22436
22437     // If the elapsed delay is less than our first sleep, start immediately.
22438     if (self.delay <= elapsed) start(elapsed - self.delay);
22439   }
22440
22441   function start(elapsed) {
22442     var i, j, n, o;
22443
22444     // If the state is not SCHEDULED, then we previously errored on start.
22445     if (self.state !== SCHEDULED) return stop();
22446
22447     for (i in schedules) {
22448       o = schedules[i];
22449       if (o.name !== self.name) continue;
22450
22451       // While this element already has a starting transition during this frame,
22452       // defer starting an interrupting transition until that transition has a
22453       // chance to tick (and possibly end); see d3/d3-transition#54!
22454       if (o.state === STARTED) return timeout$1(start);
22455
22456       // Interrupt the active transition, if any.
22457       // Dispatch the interrupt event.
22458       if (o.state === RUNNING) {
22459         o.state = ENDED;
22460         o.timer.stop();
22461         o.on.call("interrupt", node, node.__data__, o.index, o.group);
22462         delete schedules[i];
22463       }
22464
22465       // Cancel any pre-empted transitions. No interrupt event is dispatched
22466       // because the cancelled transitions never started. Note that this also
22467       // removes this transition from the pending list!
22468       else if (+i < id) {
22469         o.state = ENDED;
22470         o.timer.stop();
22471         delete schedules[i];
22472       }
22473     }
22474
22475     // Defer the first tick to end of the current frame; see d3/d3#1576.
22476     // Note the transition may be canceled after start and before the first tick!
22477     // Note this must be scheduled before the start event; see d3/d3-transition#16!
22478     // Assuming this is successful, subsequent callbacks go straight to tick.
22479     timeout$1(function() {
22480       if (self.state === STARTED) {
22481         self.state = RUNNING;
22482         self.timer.restart(tick, self.delay, self.time);
22483         tick(elapsed);
22484       }
22485     });
22486
22487     // Dispatch the start event.
22488     // Note this must be done before the tween are initialized.
22489     self.state = STARTING;
22490     self.on.call("start", node, node.__data__, self.index, self.group);
22491     if (self.state !== STARTING) return; // interrupted
22492     self.state = STARTED;
22493
22494     // Initialize the tween, deleting null tween.
22495     tween = new Array(n = self.tween.length);
22496     for (i = 0, j = -1; i < n; ++i) {
22497       if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
22498         tween[++j] = o;
22499       }
22500     }
22501     tween.length = j + 1;
22502   }
22503
22504   function tick(elapsed) {
22505     var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
22506         i = -1,
22507         n = tween.length;
22508
22509     while (++i < n) {
22510       tween[i].call(null, t);
22511     }
22512
22513     // Dispatch the end event.
22514     if (self.state === ENDING) {
22515       self.on.call("end", node, node.__data__, self.index, self.group);
22516       stop();
22517     }
22518   }
22519
22520   function stop() {
22521     self.state = ENDED;
22522     self.timer.stop();
22523     delete schedules[id];
22524     for (var i in schedules) return; // eslint-disable-line no-unused-vars
22525     delete node.__transition;
22526   }
22527 }
22528
22529 var interrupt = function(node, name) {
22530   var schedules = node.__transition,
22531       schedule,
22532       active,
22533       empty = true,
22534       i;
22535
22536   if (!schedules) return;
22537
22538   name = name == null ? null : name + "";
22539
22540   for (i in schedules) {
22541     if ((schedule = schedules[i]).name !== name) { empty = false; continue; }
22542     active = schedule.state > STARTING && schedule.state < ENDING;
22543     schedule.state = ENDED;
22544     schedule.timer.stop();
22545     if (active) schedule.on.call("interrupt", node, node.__data__, schedule.index, schedule.group);
22546     delete schedules[i];
22547   }
22548
22549   if (empty) delete node.__transition;
22550 };
22551
22552 var selection_interrupt = function(name) {
22553   return this.each(function() {
22554     interrupt(this, name);
22555   });
22556 };
22557
22558 function tweenRemove(id, name) {
22559   var tween0, tween1;
22560   return function() {
22561     var schedule = set$1(this, id),
22562         tween = schedule.tween;
22563
22564     // If this node shared tween with the previous node,
22565     // just assign the updated shared tween and we’re done!
22566     // Otherwise, copy-on-write.
22567     if (tween !== tween0) {
22568       tween1 = tween0 = tween;
22569       for (var i = 0, n = tween1.length; i < n; ++i) {
22570         if (tween1[i].name === name) {
22571           tween1 = tween1.slice();
22572           tween1.splice(i, 1);
22573           break;
22574         }
22575       }
22576     }
22577
22578     schedule.tween = tween1;
22579   };
22580 }
22581
22582 function tweenFunction(id, name, value) {
22583   var tween0, tween1;
22584   if (typeof value !== "function") throw new Error;
22585   return function() {
22586     var schedule = set$1(this, id),
22587         tween = schedule.tween;
22588
22589     // If this node shared tween with the previous node,
22590     // just assign the updated shared tween and we’re done!
22591     // Otherwise, copy-on-write.
22592     if (tween !== tween0) {
22593       tween1 = (tween0 = tween).slice();
22594       for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {
22595         if (tween1[i].name === name) {
22596           tween1[i] = t;
22597           break;
22598         }
22599       }
22600       if (i === n) tween1.push(t);
22601     }
22602
22603     schedule.tween = tween1;
22604   };
22605 }
22606
22607 var transition_tween = function(name, value) {
22608   var id = this._id;
22609
22610   name += "";
22611
22612   if (arguments.length < 2) {
22613     var tween = get$1(this.node(), id).tween;
22614     for (var i = 0, n = tween.length, t; i < n; ++i) {
22615       if ((t = tween[i]).name === name) {
22616         return t.value;
22617       }
22618     }
22619     return null;
22620   }
22621
22622   return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
22623 };
22624
22625 function tweenValue(transition, name, value) {
22626   var id = transition._id;
22627
22628   transition.each(function() {
22629     var schedule = set$1(this, id);
22630     (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
22631   });
22632
22633   return function(node) {
22634     return get$1(node, id).value[name];
22635   };
22636 }
22637
22638 var interpolate$$1 = function(a, b) {
22639   var c;
22640   return (typeof b === "number" ? reinterpolate
22641       : b instanceof color ? interpolateRgb
22642       : (c = color(b)) ? (b = c, interpolateRgb)
22643       : interpolateString)(a, b);
22644 };
22645
22646 function attrRemove$1(name) {
22647   return function() {
22648     this.removeAttribute(name);
22649   };
22650 }
22651
22652 function attrRemoveNS$1(fullname) {
22653   return function() {
22654     this.removeAttributeNS(fullname.space, fullname.local);
22655   };
22656 }
22657
22658 function attrConstant$1(name, interpolate$$1, value1) {
22659   var value00,
22660       interpolate0;
22661   return function() {
22662     var value0 = this.getAttribute(name);
22663     return value0 === value1 ? null
22664         : value0 === value00 ? interpolate0
22665         : interpolate0 = interpolate$$1(value00 = value0, value1);
22666   };
22667 }
22668
22669 function attrConstantNS$1(fullname, interpolate$$1, value1) {
22670   var value00,
22671       interpolate0;
22672   return function() {
22673     var value0 = this.getAttributeNS(fullname.space, fullname.local);
22674     return value0 === value1 ? null
22675         : value0 === value00 ? interpolate0
22676         : interpolate0 = interpolate$$1(value00 = value0, value1);
22677   };
22678 }
22679
22680 function attrFunction$1(name, interpolate$$1, value) {
22681   var value00,
22682       value10,
22683       interpolate0;
22684   return function() {
22685     var value0, value1 = value(this);
22686     if (value1 == null) return void this.removeAttribute(name);
22687     value0 = this.getAttribute(name);
22688     return value0 === value1 ? null
22689         : value0 === value00 && value1 === value10 ? interpolate0
22690         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22691   };
22692 }
22693
22694 function attrFunctionNS$1(fullname, interpolate$$1, value) {
22695   var value00,
22696       value10,
22697       interpolate0;
22698   return function() {
22699     var value0, value1 = value(this);
22700     if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
22701     value0 = this.getAttributeNS(fullname.space, fullname.local);
22702     return value0 === value1 ? null
22703         : value0 === value00 && value1 === value10 ? interpolate0
22704         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22705   };
22706 }
22707
22708 var transition_attr = function(name, value) {
22709   var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate$$1;
22710   return this.attrTween(name, typeof value === "function"
22711       ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value))
22712       : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname)
22713       : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value + ""));
22714 };
22715
22716 function attrTweenNS(fullname, value) {
22717   function tween() {
22718     var node = this, i = value.apply(node, arguments);
22719     return i && function(t) {
22720       node.setAttributeNS(fullname.space, fullname.local, i(t));
22721     };
22722   }
22723   tween._value = value;
22724   return tween;
22725 }
22726
22727 function attrTween(name, value) {
22728   function tween() {
22729     var node = this, i = value.apply(node, arguments);
22730     return i && function(t) {
22731       node.setAttribute(name, i(t));
22732     };
22733   }
22734   tween._value = value;
22735   return tween;
22736 }
22737
22738 var transition_attrTween = function(name, value) {
22739   var key = "attr." + name;
22740   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
22741   if (value == null) return this.tween(key, null);
22742   if (typeof value !== "function") throw new Error;
22743   var fullname = namespace(name);
22744   return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
22745 };
22746
22747 function delayFunction(id, value) {
22748   return function() {
22749     init(this, id).delay = +value.apply(this, arguments);
22750   };
22751 }
22752
22753 function delayConstant(id, value) {
22754   return value = +value, function() {
22755     init(this, id).delay = value;
22756   };
22757 }
22758
22759 var transition_delay = function(value) {
22760   var id = this._id;
22761
22762   return arguments.length
22763       ? this.each((typeof value === "function"
22764           ? delayFunction
22765           : delayConstant)(id, value))
22766       : get$1(this.node(), id).delay;
22767 };
22768
22769 function durationFunction(id, value) {
22770   return function() {
22771     set$1(this, id).duration = +value.apply(this, arguments);
22772   };
22773 }
22774
22775 function durationConstant(id, value) {
22776   return value = +value, function() {
22777     set$1(this, id).duration = value;
22778   };
22779 }
22780
22781 var transition_duration = function(value) {
22782   var id = this._id;
22783
22784   return arguments.length
22785       ? this.each((typeof value === "function"
22786           ? durationFunction
22787           : durationConstant)(id, value))
22788       : get$1(this.node(), id).duration;
22789 };
22790
22791 function easeConstant(id, value) {
22792   if (typeof value !== "function") throw new Error;
22793   return function() {
22794     set$1(this, id).ease = value;
22795   };
22796 }
22797
22798 var transition_ease = function(value) {
22799   var id = this._id;
22800
22801   return arguments.length
22802       ? this.each(easeConstant(id, value))
22803       : get$1(this.node(), id).ease;
22804 };
22805
22806 var transition_filter = function(match) {
22807   if (typeof match !== "function") match = matcher$1(match);
22808
22809   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22810     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
22811       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
22812         subgroup.push(node);
22813       }
22814     }
22815   }
22816
22817   return new Transition(subgroups, this._parents, this._name, this._id);
22818 };
22819
22820 var transition_merge = function(transition) {
22821   if (transition._id !== this._id) throw new Error;
22822
22823   for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
22824     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
22825       if (node = group0[i] || group1[i]) {
22826         merge[i] = node;
22827       }
22828     }
22829   }
22830
22831   for (; j < m0; ++j) {
22832     merges[j] = groups0[j];
22833   }
22834
22835   return new Transition(merges, this._parents, this._name, this._id);
22836 };
22837
22838 function start(name) {
22839   return (name + "").trim().split(/^|\s+/).every(function(t) {
22840     var i = t.indexOf(".");
22841     if (i >= 0) t = t.slice(0, i);
22842     return !t || t === "start";
22843   });
22844 }
22845
22846 function onFunction(id, name, listener) {
22847   var on0, on1, sit = start(name) ? init : set$1;
22848   return function() {
22849     var schedule = sit(this, id),
22850         on = schedule.on;
22851
22852     // If this node shared a dispatch with the previous node,
22853     // just assign the updated shared dispatch and we’re done!
22854     // Otherwise, copy-on-write.
22855     if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
22856
22857     schedule.on = on1;
22858   };
22859 }
22860
22861 var transition_on = function(name, listener) {
22862   var id = this._id;
22863
22864   return arguments.length < 2
22865       ? get$1(this.node(), id).on.on(name)
22866       : this.each(onFunction(id, name, listener));
22867 };
22868
22869 function removeFunction(id) {
22870   return function() {
22871     var parent = this.parentNode;
22872     for (var i in this.__transition) if (+i !== id) return;
22873     if (parent) parent.removeChild(this);
22874   };
22875 }
22876
22877 var transition_remove = function() {
22878   return this.on("end.remove", removeFunction(this._id));
22879 };
22880
22881 var transition_select = function(select$$1) {
22882   var name = this._name,
22883       id = this._id;
22884
22885   if (typeof select$$1 !== "function") select$$1 = selector(select$$1);
22886
22887   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22888     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
22889       if ((node = group[i]) && (subnode = select$$1.call(node, node.__data__, i, group))) {
22890         if ("__data__" in node) subnode.__data__ = node.__data__;
22891         subgroup[i] = subnode;
22892         schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
22893       }
22894     }
22895   }
22896
22897   return new Transition(subgroups, this._parents, name, id);
22898 };
22899
22900 var transition_selectAll = function(select$$1) {
22901   var name = this._name,
22902       id = this._id;
22903
22904   if (typeof select$$1 !== "function") select$$1 = selectorAll(select$$1);
22905
22906   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
22907     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
22908       if (node = group[i]) {
22909         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) {
22910           if (child = children[k]) {
22911             schedule(child, name, id, k, children, inherit);
22912           }
22913         }
22914         subgroups.push(children);
22915         parents.push(node);
22916       }
22917     }
22918   }
22919
22920   return new Transition(subgroups, parents, name, id);
22921 };
22922
22923 var Selection$1 = selection.prototype.constructor;
22924
22925 var transition_selection = function() {
22926   return new Selection$1(this._groups, this._parents);
22927 };
22928
22929 function styleRemove$1(name, interpolate$$2) {
22930   var value00,
22931       value10,
22932       interpolate0;
22933   return function() {
22934     var style = window$1(this).getComputedStyle(this, null),
22935         value0 = style.getPropertyValue(name),
22936         value1 = (this.style.removeProperty(name), style.getPropertyValue(name));
22937     return value0 === value1 ? null
22938         : value0 === value00 && value1 === value10 ? interpolate0
22939         : interpolate0 = interpolate$$2(value00 = value0, value10 = value1);
22940   };
22941 }
22942
22943 function styleRemoveEnd(name) {
22944   return function() {
22945     this.style.removeProperty(name);
22946   };
22947 }
22948
22949 function styleConstant$1(name, interpolate$$2, value1) {
22950   var value00,
22951       interpolate0;
22952   return function() {
22953     var value0 = window$1(this).getComputedStyle(this, null).getPropertyValue(name);
22954     return value0 === value1 ? null
22955         : value0 === value00 ? interpolate0
22956         : interpolate0 = interpolate$$2(value00 = value0, value1);
22957   };
22958 }
22959
22960 function styleFunction$1(name, interpolate$$2, value) {
22961   var value00,
22962       value10,
22963       interpolate0;
22964   return function() {
22965     var style = window$1(this).getComputedStyle(this, null),
22966         value0 = style.getPropertyValue(name),
22967         value1 = value(this);
22968     if (value1 == null) value1 = (this.style.removeProperty(name), style.getPropertyValue(name));
22969     return value0 === value1 ? null
22970         : value0 === value00 && value1 === value10 ? interpolate0
22971         : interpolate0 = interpolate$$2(value00 = value0, value10 = value1);
22972   };
22973 }
22974
22975 var transition_style = function(name, value, priority) {
22976   var i = (name += "") === "transform" ? interpolateTransformCss : interpolate$$1;
22977   return value == null ? this
22978           .styleTween(name, styleRemove$1(name, i))
22979           .on("end.style." + name, styleRemoveEnd(name))
22980       : this.styleTween(name, typeof value === "function"
22981           ? styleFunction$1(name, i, tweenValue(this, "style." + name, value))
22982           : styleConstant$1(name, i, value + ""), priority);
22983 };
22984
22985 function styleTween(name, value, priority) {
22986   function tween() {
22987     var node = this, i = value.apply(node, arguments);
22988     return i && function(t) {
22989       node.style.setProperty(name, i(t), priority);
22990     };
22991   }
22992   tween._value = value;
22993   return tween;
22994 }
22995
22996 var transition_styleTween = function(name, value, priority) {
22997   var key = "style." + (name += "");
22998   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
22999   if (value == null) return this.tween(key, null);
23000   if (typeof value !== "function") throw new Error;
23001   return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
23002 };
23003
23004 function textConstant$1(value) {
23005   return function() {
23006     this.textContent = value;
23007   };
23008 }
23009
23010 function textFunction$1(value) {
23011   return function() {
23012     var value1 = value(this);
23013     this.textContent = value1 == null ? "" : value1;
23014   };
23015 }
23016
23017 var transition_text = function(value) {
23018   return this.tween("text", typeof value === "function"
23019       ? textFunction$1(tweenValue(this, "text", value))
23020       : textConstant$1(value == null ? "" : value + ""));
23021 };
23022
23023 var transition_transition = function() {
23024   var name = this._name,
23025       id0 = this._id,
23026       id1 = newId();
23027
23028   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23029     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23030       if (node = group[i]) {
23031         var inherit = get$1(node, id0);
23032         schedule(node, name, id1, i, group, {
23033           time: inherit.time + inherit.delay + inherit.duration,
23034           delay: 0,
23035           duration: inherit.duration,
23036           ease: inherit.ease
23037         });
23038       }
23039     }
23040   }
23041
23042   return new Transition(groups, this._parents, name, id1);
23043 };
23044
23045 var id = 0;
23046
23047 function Transition(groups, parents, name, id) {
23048   this._groups = groups;
23049   this._parents = parents;
23050   this._name = name;
23051   this._id = id;
23052 }
23053
23054 function transition(name) {
23055   return selection().transition(name);
23056 }
23057
23058 function newId() {
23059   return ++id;
23060 }
23061
23062 var selection_prototype = selection.prototype;
23063
23064 Transition.prototype = transition.prototype = {
23065   constructor: Transition,
23066   select: transition_select,
23067   selectAll: transition_selectAll,
23068   filter: transition_filter,
23069   merge: transition_merge,
23070   selection: transition_selection,
23071   transition: transition_transition,
23072   call: selection_prototype.call,
23073   nodes: selection_prototype.nodes,
23074   node: selection_prototype.node,
23075   size: selection_prototype.size,
23076   empty: selection_prototype.empty,
23077   each: selection_prototype.each,
23078   on: transition_on,
23079   attr: transition_attr,
23080   attrTween: transition_attrTween,
23081   style: transition_style,
23082   styleTween: transition_styleTween,
23083   text: transition_text,
23084   remove: transition_remove,
23085   tween: transition_tween,
23086   delay: transition_delay,
23087   duration: transition_duration,
23088   ease: transition_ease
23089 };
23090
23091 function linear$1(t) {
23092   return +t;
23093 }
23094
23095 function quadIn(t) {
23096   return t * t;
23097 }
23098
23099 function quadOut(t) {
23100   return t * (2 - t);
23101 }
23102
23103 function quadInOut(t) {
23104   return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
23105 }
23106
23107 function cubicIn(t) {
23108   return t * t * t;
23109 }
23110
23111 function cubicOut(t) {
23112   return --t * t * t + 1;
23113 }
23114
23115 function cubicInOut(t) {
23116   return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
23117 }
23118
23119 var exponent = 3;
23120
23121 var polyIn = (function custom(e) {
23122   e = +e;
23123
23124   function polyIn(t) {
23125     return Math.pow(t, e);
23126   }
23127
23128   polyIn.exponent = custom;
23129
23130   return polyIn;
23131 })(exponent);
23132
23133 var polyOut = (function custom(e) {
23134   e = +e;
23135
23136   function polyOut(t) {
23137     return 1 - Math.pow(1 - t, e);
23138   }
23139
23140   polyOut.exponent = custom;
23141
23142   return polyOut;
23143 })(exponent);
23144
23145 var polyInOut = (function custom(e) {
23146   e = +e;
23147
23148   function polyInOut(t) {
23149     return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
23150   }
23151
23152   polyInOut.exponent = custom;
23153
23154   return polyInOut;
23155 })(exponent);
23156
23157 var pi = Math.PI;
23158 var halfPi = pi / 2;
23159
23160 function sinIn(t) {
23161   return 1 - Math.cos(t * halfPi);
23162 }
23163
23164 function sinOut(t) {
23165   return Math.sin(t * halfPi);
23166 }
23167
23168 function sinInOut(t) {
23169   return (1 - Math.cos(pi * t)) / 2;
23170 }
23171
23172 function expIn(t) {
23173   return Math.pow(2, 10 * t - 10);
23174 }
23175
23176 function expOut(t) {
23177   return 1 - Math.pow(2, -10 * t);
23178 }
23179
23180 function expInOut(t) {
23181   return ((t *= 2) <= 1 ? Math.pow(2, 10 * t - 10) : 2 - Math.pow(2, 10 - 10 * t)) / 2;
23182 }
23183
23184 function circleIn(t) {
23185   return 1 - Math.sqrt(1 - t * t);
23186 }
23187
23188 function circleOut(t) {
23189   return Math.sqrt(1 - --t * t);
23190 }
23191
23192 function circleInOut(t) {
23193   return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
23194 }
23195
23196 var b1 = 4 / 11;
23197 var b2 = 6 / 11;
23198 var b3 = 8 / 11;
23199 var b4 = 3 / 4;
23200 var b5 = 9 / 11;
23201 var b6 = 10 / 11;
23202 var b7 = 15 / 16;
23203 var b8 = 21 / 22;
23204 var b9 = 63 / 64;
23205 var b0 = 1 / b1 / b1;
23206
23207 function bounceIn(t) {
23208   return 1 - bounceOut(1 - t);
23209 }
23210
23211 function bounceOut(t) {
23212   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;
23213 }
23214
23215 function bounceInOut(t) {
23216   return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
23217 }
23218
23219 var overshoot = 1.70158;
23220
23221 var backIn = (function custom(s) {
23222   s = +s;
23223
23224   function backIn(t) {
23225     return t * t * ((s + 1) * t - s);
23226   }
23227
23228   backIn.overshoot = custom;
23229
23230   return backIn;
23231 })(overshoot);
23232
23233 var backOut = (function custom(s) {
23234   s = +s;
23235
23236   function backOut(t) {
23237     return --t * t * ((s + 1) * t + s) + 1;
23238   }
23239
23240   backOut.overshoot = custom;
23241
23242   return backOut;
23243 })(overshoot);
23244
23245 var backInOut = (function custom(s) {
23246   s = +s;
23247
23248   function backInOut(t) {
23249     return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
23250   }
23251
23252   backInOut.overshoot = custom;
23253
23254   return backInOut;
23255 })(overshoot);
23256
23257 var tau = 2 * Math.PI;
23258 var amplitude = 1;
23259 var period = 0.3;
23260
23261 var elasticIn = (function custom(a, p) {
23262   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23263
23264   function elasticIn(t) {
23265     return a * Math.pow(2, 10 * --t) * Math.sin((s - t) / p);
23266   }
23267
23268   elasticIn.amplitude = function(a) { return custom(a, p * tau); };
23269   elasticIn.period = function(p) { return custom(a, p); };
23270
23271   return elasticIn;
23272 })(amplitude, period);
23273
23274 var elasticOut = (function custom(a, p) {
23275   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23276
23277   function elasticOut(t) {
23278     return 1 - a * Math.pow(2, -10 * (t = +t)) * Math.sin((t + s) / p);
23279   }
23280
23281   elasticOut.amplitude = function(a) { return custom(a, p * tau); };
23282   elasticOut.period = function(p) { return custom(a, p); };
23283
23284   return elasticOut;
23285 })(amplitude, period);
23286
23287 var elasticInOut = (function custom(a, p) {
23288   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23289
23290   function elasticInOut(t) {
23291     return ((t = t * 2 - 1) < 0
23292         ? a * Math.pow(2, 10 * t) * Math.sin((s - t) / p)
23293         : 2 - a * Math.pow(2, -10 * t) * Math.sin((s + t) / p)) / 2;
23294   }
23295
23296   elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
23297   elasticInOut.period = function(p) { return custom(a, p); };
23298
23299   return elasticInOut;
23300 })(amplitude, period);
23301
23302 var defaultTiming = {
23303   time: null, // Set on use.
23304   delay: 0,
23305   duration: 250,
23306   ease: cubicInOut
23307 };
23308
23309 function inherit(node, id) {
23310   var timing;
23311   while (!(timing = node.__transition) || !(timing = timing[id])) {
23312     if (!(node = node.parentNode)) {
23313       return defaultTiming.time = now(), defaultTiming;
23314     }
23315   }
23316   return timing;
23317 }
23318
23319 var selection_transition = function(name) {
23320   var id,
23321       timing;
23322
23323   if (name instanceof Transition) {
23324     id = name._id, name = name._name;
23325   } else {
23326     id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
23327   }
23328
23329   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23330     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23331       if (node = group[i]) {
23332         schedule(node, name, id, i, group, timing || inherit(node, id));
23333       }
23334     }
23335   }
23336
23337   return new Transition(groups, this._parents, name, id);
23338 };
23339
23340 selection.prototype.interrupt = selection_interrupt;
23341 selection.prototype.transition = selection_transition;
23342
23343 var root$1 = [null];
23344
23345 var active = function(node, name) {
23346   var schedules = node.__transition,
23347       schedule,
23348       i;
23349
23350   if (schedules) {
23351     name = name == null ? null : name + "";
23352     for (i in schedules) {
23353       if ((schedule = schedules[i]).state > SCHEDULED && schedule.name === name) {
23354         return new Transition([[node]], root$1, name, +i);
23355       }
23356     }
23357   }
23358
23359   return null;
23360 };
23361
23362 var constant$4 = function(x) {
23363   return function() {
23364     return x;
23365   };
23366 };
23367
23368 var BrushEvent = function(target, type, selection) {
23369   this.target = target;
23370   this.type = type;
23371   this.selection = selection;
23372 };
23373
23374 function nopropagation$1() {
23375   event.stopImmediatePropagation();
23376 }
23377
23378 var noevent$1 = function() {
23379   event.preventDefault();
23380   event.stopImmediatePropagation();
23381 };
23382
23383 var MODE_DRAG = {name: "drag"};
23384 var MODE_SPACE = {name: "space"};
23385 var MODE_HANDLE = {name: "handle"};
23386 var MODE_CENTER = {name: "center"};
23387
23388 var X = {
23389   name: "x",
23390   handles: ["e", "w"].map(type$2),
23391   input: function(x, e) { return x && [[x[0], e[0][1]], [x[1], e[1][1]]]; },
23392   output: function(xy) { return xy && [xy[0][0], xy[1][0]]; }
23393 };
23394
23395 var Y = {
23396   name: "y",
23397   handles: ["n", "s"].map(type$2),
23398   input: function(y, e) { return y && [[e[0][0], y[0]], [e[1][0], y[1]]]; },
23399   output: function(xy) { return xy && [xy[0][1], xy[1][1]]; }
23400 };
23401
23402 var XY = {
23403   name: "xy",
23404   handles: ["n", "e", "s", "w", "nw", "ne", "se", "sw"].map(type$2),
23405   input: function(xy) { return xy; },
23406   output: function(xy) { return xy; }
23407 };
23408
23409 var cursors = {
23410   overlay: "crosshair",
23411   selection: "move",
23412   n: "ns-resize",
23413   e: "ew-resize",
23414   s: "ns-resize",
23415   w: "ew-resize",
23416   nw: "nwse-resize",
23417   ne: "nesw-resize",
23418   se: "nwse-resize",
23419   sw: "nesw-resize"
23420 };
23421
23422 var flipX = {
23423   e: "w",
23424   w: "e",
23425   nw: "ne",
23426   ne: "nw",
23427   se: "sw",
23428   sw: "se"
23429 };
23430
23431 var flipY = {
23432   n: "s",
23433   s: "n",
23434   nw: "sw",
23435   ne: "se",
23436   se: "ne",
23437   sw: "nw"
23438 };
23439
23440 var signsX = {
23441   overlay: +1,
23442   selection: +1,
23443   n: null,
23444   e: +1,
23445   s: null,
23446   w: -1,
23447   nw: -1,
23448   ne: +1,
23449   se: +1,
23450   sw: -1
23451 };
23452
23453 var signsY = {
23454   overlay: +1,
23455   selection: +1,
23456   n: -1,
23457   e: null,
23458   s: +1,
23459   w: null,
23460   nw: -1,
23461   ne: -1,
23462   se: +1,
23463   sw: +1
23464 };
23465
23466 function type$2(t) {
23467   return {type: t};
23468 }
23469
23470 // Ignore right-click, since that should open the context menu.
23471 function defaultFilter() {
23472   return !event.button;
23473 }
23474
23475 function defaultExtent() {
23476   var svg = this.ownerSVGElement || this;
23477   return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]];
23478 }
23479
23480 // Like d3.local, but with the name “__brush” rather than auto-generated.
23481 function local$$1(node) {
23482   while (!node.__brush) if (!(node = node.parentNode)) return;
23483   return node.__brush;
23484 }
23485
23486 function empty(extent) {
23487   return extent[0][0] === extent[1][0]
23488       || extent[0][1] === extent[1][1];
23489 }
23490
23491 function brushSelection(node) {
23492   var state = node.__brush;
23493   return state ? state.dim.output(state.selection) : null;
23494 }
23495
23496 function brushX() {
23497   return brush$1(X);
23498 }
23499
23500 function brushY() {
23501   return brush$1(Y);
23502 }
23503
23504 var brush = function() {
23505   return brush$1(XY);
23506 };
23507
23508 function brush$1(dim) {
23509   var extent = defaultExtent,
23510       filter = defaultFilter,
23511       listeners = dispatch(brush, "start", "brush", "end"),
23512       handleSize = 6,
23513       touchending;
23514
23515   function brush(group) {
23516     var overlay = group
23517         .property("__brush", initialize)
23518       .selectAll(".overlay")
23519       .data([type$2("overlay")]);
23520
23521     overlay.enter().append("rect")
23522         .attr("class", "overlay")
23523         .attr("pointer-events", "all")
23524         .attr("cursor", cursors.overlay)
23525       .merge(overlay)
23526         .each(function() {
23527           var extent = local$$1(this).extent;
23528           select(this)
23529               .attr("x", extent[0][0])
23530               .attr("y", extent[0][1])
23531               .attr("width", extent[1][0] - extent[0][0])
23532               .attr("height", extent[1][1] - extent[0][1]);
23533         });
23534
23535     group.selectAll(".selection")
23536       .data([type$2("selection")])
23537       .enter().append("rect")
23538         .attr("class", "selection")
23539         .attr("cursor", cursors.selection)
23540         .attr("fill", "#777")
23541         .attr("fill-opacity", 0.3)
23542         .attr("stroke", "#fff")
23543         .attr("shape-rendering", "crispEdges");
23544
23545     var handle = group.selectAll(".handle")
23546       .data(dim.handles, function(d) { return d.type; });
23547
23548     handle.exit().remove();
23549
23550     handle.enter().append("rect")
23551         .attr("class", function(d) { return "handle handle--" + d.type; })
23552         .attr("cursor", function(d) { return cursors[d.type]; });
23553
23554     group
23555         .each(redraw)
23556         .attr("fill", "none")
23557         .attr("pointer-events", "all")
23558         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
23559         .on("mousedown.brush touchstart.brush", started);
23560   }
23561
23562   brush.move = function(group, selection$$1) {
23563     if (group.selection) {
23564       group
23565           .on("start.brush", function() { emitter(this, arguments).beforestart().start(); })
23566           .on("interrupt.brush end.brush", function() { emitter(this, arguments).end(); })
23567           .tween("brush", function() {
23568             var that = this,
23569                 state = that.__brush,
23570                 emit = emitter(that, arguments),
23571                 selection0 = state.selection,
23572                 selection1 = dim.input(typeof selection$$1 === "function" ? selection$$1.apply(this, arguments) : selection$$1, state.extent),
23573                 i = interpolateValue(selection0, selection1);
23574
23575             function tween(t) {
23576               state.selection = t === 1 && empty(selection1) ? null : i(t);
23577               redraw.call(that);
23578               emit.brush();
23579             }
23580
23581             return selection0 && selection1 ? tween : tween(1);
23582           });
23583     } else {
23584       group
23585           .each(function() {
23586             var that = this,
23587                 args = arguments,
23588                 state = that.__brush,
23589                 selection1 = dim.input(typeof selection$$1 === "function" ? selection$$1.apply(that, args) : selection$$1, state.extent),
23590                 emit = emitter(that, args).beforestart();
23591
23592             interrupt(that);
23593             state.selection = selection1 == null || empty(selection1) ? null : selection1;
23594             redraw.call(that);
23595             emit.start().brush().end();
23596           });
23597     }
23598   };
23599
23600   function redraw() {
23601     var group = select(this),
23602         selection$$1 = local$$1(this).selection;
23603
23604     if (selection$$1) {
23605       group.selectAll(".selection")
23606           .style("display", null)
23607           .attr("x", selection$$1[0][0])
23608           .attr("y", selection$$1[0][1])
23609           .attr("width", selection$$1[1][0] - selection$$1[0][0])
23610           .attr("height", selection$$1[1][1] - selection$$1[0][1]);
23611
23612       group.selectAll(".handle")
23613           .style("display", null)
23614           .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection$$1[1][0] - handleSize / 2 : selection$$1[0][0] - handleSize / 2; })
23615           .attr("y", function(d) { return d.type[0] === "s" ? selection$$1[1][1] - handleSize / 2 : selection$$1[0][1] - handleSize / 2; })
23616           .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection$$1[1][0] - selection$$1[0][0] + handleSize : handleSize; })
23617           .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection$$1[1][1] - selection$$1[0][1] + handleSize : handleSize; });
23618     }
23619
23620     else {
23621       group.selectAll(".selection,.handle")
23622           .style("display", "none")
23623           .attr("x", null)
23624           .attr("y", null)
23625           .attr("width", null)
23626           .attr("height", null);
23627     }
23628   }
23629
23630   function emitter(that, args) {
23631     return that.__brush.emitter || new Emitter(that, args);
23632   }
23633
23634   function Emitter(that, args) {
23635     this.that = that;
23636     this.args = args;
23637     this.state = that.__brush;
23638     this.active = 0;
23639   }
23640
23641   Emitter.prototype = {
23642     beforestart: function() {
23643       if (++this.active === 1) this.state.emitter = this, this.starting = true;
23644       return this;
23645     },
23646     start: function() {
23647       if (this.starting) this.starting = false, this.emit("start");
23648       return this;
23649     },
23650     brush: function() {
23651       this.emit("brush");
23652       return this;
23653     },
23654     end: function() {
23655       if (--this.active === 0) delete this.state.emitter, this.emit("end");
23656       return this;
23657     },
23658     emit: function(type) {
23659       customEvent(new BrushEvent(brush, type, dim.output(this.state.selection)), listeners.apply, listeners, [type, this.that, this.args]);
23660     }
23661   };
23662
23663   function started() {
23664     if (event.touches) { if (event.changedTouches.length < event.touches.length) return noevent$1(); }
23665     else if (touchending) return;
23666     if (!filter.apply(this, arguments)) return;
23667
23668     var that = this,
23669         type = event.target.__data__.type,
23670         mode = (event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (event.altKey ? MODE_CENTER : MODE_HANDLE),
23671         signX = dim === Y ? null : signsX[type],
23672         signY = dim === X ? null : signsY[type],
23673         state = local$$1(that),
23674         extent = state.extent,
23675         selection$$1 = state.selection,
23676         W = extent[0][0], w0, w1,
23677         N = extent[0][1], n0, n1,
23678         E = extent[1][0], e0, e1,
23679         S = extent[1][1], s0, s1,
23680         dx,
23681         dy,
23682         moving,
23683         shifting = signX && signY && event.shiftKey,
23684         lockX,
23685         lockY,
23686         point0 = mouse(that),
23687         point = point0,
23688         emit = emitter(that, arguments).beforestart();
23689
23690     if (type === "overlay") {
23691       state.selection = selection$$1 = [
23692         [w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]],
23693         [e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0]
23694       ];
23695     } else {
23696       w0 = selection$$1[0][0];
23697       n0 = selection$$1[0][1];
23698       e0 = selection$$1[1][0];
23699       s0 = selection$$1[1][1];
23700     }
23701
23702     w1 = w0;
23703     n1 = n0;
23704     e1 = e0;
23705     s1 = s0;
23706
23707     var group = select(that)
23708         .attr("pointer-events", "none");
23709
23710     var overlay = group.selectAll(".overlay")
23711         .attr("cursor", cursors[type]);
23712
23713     if (event.touches) {
23714       group
23715           .on("touchmove.brush", moved, true)
23716           .on("touchend.brush touchcancel.brush", ended, true);
23717     } else {
23718       var view = select(event.view)
23719           .on("keydown.brush", keydowned, true)
23720           .on("keyup.brush", keyupped, true)
23721           .on("mousemove.brush", moved, true)
23722           .on("mouseup.brush", ended, true);
23723
23724       dragDisable(event.view);
23725     }
23726
23727     nopropagation$1();
23728     interrupt(that);
23729     redraw.call(that);
23730     emit.start();
23731
23732     function moved() {
23733       var point1 = mouse(that);
23734       if (shifting && !lockX && !lockY) {
23735         if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true;
23736         else lockX = true;
23737       }
23738       point = point1;
23739       moving = true;
23740       noevent$1();
23741       move();
23742     }
23743
23744     function move() {
23745       var t;
23746
23747       dx = point[0] - point0[0];
23748       dy = point[1] - point0[1];
23749
23750       switch (mode) {
23751         case MODE_SPACE:
23752         case MODE_DRAG: {
23753           if (signX) dx = Math.max(W - w0, Math.min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
23754           if (signY) dy = Math.max(N - n0, Math.min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
23755           break;
23756         }
23757         case MODE_HANDLE: {
23758           if (signX < 0) dx = Math.max(W - w0, Math.min(E - w0, dx)), w1 = w0 + dx, e1 = e0;
23759           else if (signX > 0) dx = Math.max(W - e0, Math.min(E - e0, dx)), w1 = w0, e1 = e0 + dx;
23760           if (signY < 0) dy = Math.max(N - n0, Math.min(S - n0, dy)), n1 = n0 + dy, s1 = s0;
23761           else if (signY > 0) dy = Math.max(N - s0, Math.min(S - s0, dy)), n1 = n0, s1 = s0 + dy;
23762           break;
23763         }
23764         case MODE_CENTER: {
23765           if (signX) w1 = Math.max(W, Math.min(E, w0 - dx * signX)), e1 = Math.max(W, Math.min(E, e0 + dx * signX));
23766           if (signY) n1 = Math.max(N, Math.min(S, n0 - dy * signY)), s1 = Math.max(N, Math.min(S, s0 + dy * signY));
23767           break;
23768         }
23769       }
23770
23771       if (e1 < w1) {
23772         signX *= -1;
23773         t = w0, w0 = e0, e0 = t;
23774         t = w1, w1 = e1, e1 = t;
23775         if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]);
23776       }
23777
23778       if (s1 < n1) {
23779         signY *= -1;
23780         t = n0, n0 = s0, s0 = t;
23781         t = n1, n1 = s1, s1 = t;
23782         if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]);
23783       }
23784
23785       if (state.selection) selection$$1 = state.selection; // May be set by brush.move!
23786       if (lockX) w1 = selection$$1[0][0], e1 = selection$$1[1][0];
23787       if (lockY) n1 = selection$$1[0][1], s1 = selection$$1[1][1];
23788
23789       if (selection$$1[0][0] !== w1
23790           || selection$$1[0][1] !== n1
23791           || selection$$1[1][0] !== e1
23792           || selection$$1[1][1] !== s1) {
23793         state.selection = [[w1, n1], [e1, s1]];
23794         redraw.call(that);
23795         emit.brush();
23796       }
23797     }
23798
23799     function ended() {
23800       nopropagation$1();
23801       if (event.touches) {
23802         if (event.touches.length) return;
23803         if (touchending) clearTimeout(touchending);
23804         touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
23805         group.on("touchmove.brush touchend.brush touchcancel.brush", null);
23806       } else {
23807         yesdrag(event.view, moving);
23808         view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null);
23809       }
23810       group.attr("pointer-events", "all");
23811       overlay.attr("cursor", cursors.overlay);
23812       if (state.selection) selection$$1 = state.selection; // May be set by brush.move (on start)!
23813       if (empty(selection$$1)) state.selection = null, redraw.call(that);
23814       emit.end();
23815     }
23816
23817     function keydowned() {
23818       switch (event.keyCode) {
23819         case 16: { // SHIFT
23820           shifting = signX && signY;
23821           break;
23822         }
23823         case 18: { // ALT
23824           if (mode === MODE_HANDLE) {
23825             if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23826             if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23827             mode = MODE_CENTER;
23828             move();
23829           }
23830           break;
23831         }
23832         case 32: { // SPACE; takes priority over ALT
23833           if (mode === MODE_HANDLE || mode === MODE_CENTER) {
23834             if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx;
23835             if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy;
23836             mode = MODE_SPACE;
23837             overlay.attr("cursor", cursors.selection);
23838             move();
23839           }
23840           break;
23841         }
23842         default: return;
23843       }
23844       noevent$1();
23845     }
23846
23847     function keyupped() {
23848       switch (event.keyCode) {
23849         case 16: { // SHIFT
23850           if (shifting) {
23851             lockX = lockY = shifting = false;
23852             move();
23853           }
23854           break;
23855         }
23856         case 18: { // ALT
23857           if (mode === MODE_CENTER) {
23858             if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23859             if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23860             mode = MODE_HANDLE;
23861             move();
23862           }
23863           break;
23864         }
23865         case 32: { // SPACE
23866           if (mode === MODE_SPACE) {
23867             if (event.altKey) {
23868               if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23869               if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23870               mode = MODE_CENTER;
23871             } else {
23872               if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23873               if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23874               mode = MODE_HANDLE;
23875             }
23876             overlay.attr("cursor", cursors[type]);
23877             move();
23878           }
23879           break;
23880         }
23881         default: return;
23882       }
23883       noevent$1();
23884     }
23885   }
23886
23887   function initialize() {
23888     var state = this.__brush || {selection: null};
23889     state.extent = extent.apply(this, arguments);
23890     state.dim = dim;
23891     return state;
23892   }
23893
23894   brush.extent = function(_) {
23895     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$4([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), brush) : extent;
23896   };
23897
23898   brush.filter = function(_) {
23899     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$4(!!_), brush) : filter;
23900   };
23901
23902   brush.handleSize = function(_) {
23903     return arguments.length ? (handleSize = +_, brush) : handleSize;
23904   };
23905
23906   brush.on = function() {
23907     var value = listeners.on.apply(listeners, arguments);
23908     return value === listeners ? brush : value;
23909   };
23910
23911   return brush;
23912 }
23913
23914 var cos = Math.cos;
23915 var sin = Math.sin;
23916 var pi$1 = Math.PI;
23917 var halfPi$1 = pi$1 / 2;
23918 var tau$1 = pi$1 * 2;
23919 var max$1 = Math.max;
23920
23921 function compareValue(compare) {
23922   return function(a, b) {
23923     return compare(
23924       a.source.value + a.target.value,
23925       b.source.value + b.target.value
23926     );
23927   };
23928 }
23929
23930 var chord = function() {
23931   var padAngle = 0,
23932       sortGroups = null,
23933       sortSubgroups = null,
23934       sortChords = null;
23935
23936   function chord(matrix) {
23937     var n = matrix.length,
23938         groupSums = [],
23939         groupIndex = sequence(n),
23940         subgroupIndex = [],
23941         chords = [],
23942         groups = chords.groups = new Array(n),
23943         subgroups = new Array(n * n),
23944         k,
23945         x,
23946         x0,
23947         dx,
23948         i,
23949         j;
23950
23951     // Compute the sum.
23952     k = 0, i = -1; while (++i < n) {
23953       x = 0, j = -1; while (++j < n) {
23954         x += matrix[i][j];
23955       }
23956       groupSums.push(x);
23957       subgroupIndex.push(sequence(n));
23958       k += x;
23959     }
23960
23961     // Sort groups…
23962     if (sortGroups) groupIndex.sort(function(a, b) {
23963       return sortGroups(groupSums[a], groupSums[b]);
23964     });
23965
23966     // Sort subgroups…
23967     if (sortSubgroups) subgroupIndex.forEach(function(d, i) {
23968       d.sort(function(a, b) {
23969         return sortSubgroups(matrix[i][a], matrix[i][b]);
23970       });
23971     });
23972
23973     // Convert the sum to scaling factor for [0, 2pi].
23974     // TODO Allow start and end angle to be specified?
23975     // TODO Allow padding to be specified as percentage?
23976     k = max$1(0, tau$1 - padAngle * n) / k;
23977     dx = k ? padAngle : tau$1 / n;
23978
23979     // Compute the start and end angle for each group and subgroup.
23980     // Note: Opera has a bug reordering object literal properties!
23981     x = 0, i = -1; while (++i < n) {
23982       x0 = x, j = -1; while (++j < n) {
23983         var di = groupIndex[i],
23984             dj = subgroupIndex[di][j],
23985             v = matrix[di][dj],
23986             a0 = x,
23987             a1 = x += v * k;
23988         subgroups[dj * n + di] = {
23989           index: di,
23990           subindex: dj,
23991           startAngle: a0,
23992           endAngle: a1,
23993           value: v
23994         };
23995       }
23996       groups[di] = {
23997         index: di,
23998         startAngle: x0,
23999         endAngle: x,
24000         value: groupSums[di]
24001       };
24002       x += dx;
24003     }
24004
24005     // Generate chords for each (non-empty) subgroup-subgroup link.
24006     i = -1; while (++i < n) {
24007       j = i - 1; while (++j < n) {
24008         var source = subgroups[j * n + i],
24009             target = subgroups[i * n + j];
24010         if (source.value || target.value) {
24011           chords.push(source.value < target.value
24012               ? {source: target, target: source}
24013               : {source: source, target: target});
24014         }
24015       }
24016     }
24017
24018     return sortChords ? chords.sort(sortChords) : chords;
24019   }
24020
24021   chord.padAngle = function(_) {
24022     return arguments.length ? (padAngle = max$1(0, _), chord) : padAngle;
24023   };
24024
24025   chord.sortGroups = function(_) {
24026     return arguments.length ? (sortGroups = _, chord) : sortGroups;
24027   };
24028
24029   chord.sortSubgroups = function(_) {
24030     return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups;
24031   };
24032
24033   chord.sortChords = function(_) {
24034     return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._;
24035   };
24036
24037   return chord;
24038 };
24039
24040 var slice$2 = Array.prototype.slice;
24041
24042 var constant$5 = function(x) {
24043   return function() {
24044     return x;
24045   };
24046 };
24047
24048 var pi$2 = Math.PI;
24049 var tau$2 = 2 * pi$2;
24050 var epsilon$1 = 1e-6;
24051 var tauEpsilon = tau$2 - epsilon$1;
24052
24053 function Path() {
24054   this._x0 = this._y0 = // start of current subpath
24055   this._x1 = this._y1 = null; // end of current subpath
24056   this._ = "";
24057 }
24058
24059 function path() {
24060   return new Path;
24061 }
24062
24063 Path.prototype = path.prototype = {
24064   constructor: Path,
24065   moveTo: function(x, y) {
24066     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y);
24067   },
24068   closePath: function() {
24069     if (this._x1 !== null) {
24070       this._x1 = this._x0, this._y1 = this._y0;
24071       this._ += "Z";
24072     }
24073   },
24074   lineTo: function(x, y) {
24075     this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y);
24076   },
24077   quadraticCurveTo: function(x1, y1, x, y) {
24078     this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24079   },
24080   bezierCurveTo: function(x1, y1, x2, y2, x, y) {
24081     this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24082   },
24083   arcTo: function(x1, y1, x2, y2, r) {
24084     x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
24085     var x0 = this._x1,
24086         y0 = this._y1,
24087         x21 = x2 - x1,
24088         y21 = y2 - y1,
24089         x01 = x0 - x1,
24090         y01 = y0 - y1,
24091         l01_2 = x01 * x01 + y01 * y01;
24092
24093     // Is the radius negative? Error.
24094     if (r < 0) throw new Error("negative radius: " + r);
24095
24096     // Is this path empty? Move to (x1,y1).
24097     if (this._x1 === null) {
24098       this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1);
24099     }
24100
24101     // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
24102     else if (!(l01_2 > epsilon$1)) {}
24103
24104     // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
24105     // Equivalently, is (x1,y1) coincident with (x2,y2)?
24106     // Or, is the radius zero? Line to (x1,y1).
24107     else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$1) || !r) {
24108       this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1);
24109     }
24110
24111     // Otherwise, draw an arc!
24112     else {
24113       var x20 = x2 - x0,
24114           y20 = y2 - y0,
24115           l21_2 = x21 * x21 + y21 * y21,
24116           l20_2 = x20 * x20 + y20 * y20,
24117           l21 = Math.sqrt(l21_2),
24118           l01 = Math.sqrt(l01_2),
24119           l = r * Math.tan((pi$2 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),
24120           t01 = l / l01,
24121           t21 = l / l21;
24122
24123       // If the start tangent is not coincident with (x0,y0), line to.
24124       if (Math.abs(t01 - 1) > epsilon$1) {
24125         this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01);
24126       }
24127
24128       this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21);
24129     }
24130   },
24131   arc: function(x, y, r, a0, a1, ccw) {
24132     x = +x, y = +y, r = +r;
24133     var dx = r * Math.cos(a0),
24134         dy = r * Math.sin(a0),
24135         x0 = x + dx,
24136         y0 = y + dy,
24137         cw = 1 ^ ccw,
24138         da = ccw ? a0 - a1 : a1 - a0;
24139
24140     // Is the radius negative? Error.
24141     if (r < 0) throw new Error("negative radius: " + r);
24142
24143     // Is this path empty? Move to (x0,y0).
24144     if (this._x1 === null) {
24145       this._ += "M" + x0 + "," + y0;
24146     }
24147
24148     // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
24149     else if (Math.abs(this._x1 - x0) > epsilon$1 || Math.abs(this._y1 - y0) > epsilon$1) {
24150       this._ += "L" + x0 + "," + y0;
24151     }
24152
24153     // Is this arc empty? We’re done.
24154     if (!r) return;
24155
24156     // Does the angle go the wrong way? Flip the direction.
24157     if (da < 0) da = da % tau$2 + tau$2;
24158
24159     // Is this a complete circle? Draw two arcs to complete the circle.
24160     if (da > tauEpsilon) {
24161       this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0);
24162     }
24163
24164     // Is this arc non-empty? Draw an arc!
24165     else if (da > epsilon$1) {
24166       this._ += "A" + r + "," + r + ",0," + (+(da >= pi$2)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1));
24167     }
24168   },
24169   rect: function(x, y, w, h) {
24170     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z";
24171   },
24172   toString: function() {
24173     return this._;
24174   }
24175 };
24176
24177 function defaultSource(d) {
24178   return d.source;
24179 }
24180
24181 function defaultTarget(d) {
24182   return d.target;
24183 }
24184
24185 function defaultRadius(d) {
24186   return d.radius;
24187 }
24188
24189 function defaultStartAngle(d) {
24190   return d.startAngle;
24191 }
24192
24193 function defaultEndAngle(d) {
24194   return d.endAngle;
24195 }
24196
24197 var ribbon = function() {
24198   var source = defaultSource,
24199       target = defaultTarget,
24200       radius = defaultRadius,
24201       startAngle = defaultStartAngle,
24202       endAngle = defaultEndAngle,
24203       context = null;
24204
24205   function ribbon() {
24206     var buffer,
24207         argv = slice$2.call(arguments),
24208         s = source.apply(this, argv),
24209         t = target.apply(this, argv),
24210         sr = +radius.apply(this, (argv[0] = s, argv)),
24211         sa0 = startAngle.apply(this, argv) - halfPi$1,
24212         sa1 = endAngle.apply(this, argv) - halfPi$1,
24213         sx0 = sr * cos(sa0),
24214         sy0 = sr * sin(sa0),
24215         tr = +radius.apply(this, (argv[0] = t, argv)),
24216         ta0 = startAngle.apply(this, argv) - halfPi$1,
24217         ta1 = endAngle.apply(this, argv) - halfPi$1;
24218
24219     if (!context) context = buffer = path();
24220
24221     context.moveTo(sx0, sy0);
24222     context.arc(0, 0, sr, sa0, sa1);
24223     if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr?
24224       context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
24225       context.arc(0, 0, tr, ta0, ta1);
24226     }
24227     context.quadraticCurveTo(0, 0, sx0, sy0);
24228     context.closePath();
24229
24230     if (buffer) return context = null, buffer + "" || null;
24231   }
24232
24233   ribbon.radius = function(_) {
24234     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$5(+_), ribbon) : radius;
24235   };
24236
24237   ribbon.startAngle = function(_) {
24238     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : startAngle;
24239   };
24240
24241   ribbon.endAngle = function(_) {
24242     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : endAngle;
24243   };
24244
24245   ribbon.source = function(_) {
24246     return arguments.length ? (source = _, ribbon) : source;
24247   };
24248
24249   ribbon.target = function(_) {
24250     return arguments.length ? (target = _, ribbon) : target;
24251   };
24252
24253   ribbon.context = function(_) {
24254     return arguments.length ? ((context = _ == null ? null : _), ribbon) : context;
24255   };
24256
24257   return ribbon;
24258 };
24259
24260 var prefix = "$";
24261
24262 function Map() {}
24263
24264 Map.prototype = map$1.prototype = {
24265   constructor: Map,
24266   has: function(key) {
24267     return (prefix + key) in this;
24268   },
24269   get: function(key) {
24270     return this[prefix + key];
24271   },
24272   set: function(key, value) {
24273     this[prefix + key] = value;
24274     return this;
24275   },
24276   remove: function(key) {
24277     var property = prefix + key;
24278     return property in this && delete this[property];
24279   },
24280   clear: function() {
24281     for (var property in this) if (property[0] === prefix) delete this[property];
24282   },
24283   keys: function() {
24284     var keys = [];
24285     for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
24286     return keys;
24287   },
24288   values: function() {
24289     var values = [];
24290     for (var property in this) if (property[0] === prefix) values.push(this[property]);
24291     return values;
24292   },
24293   entries: function() {
24294     var entries = [];
24295     for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
24296     return entries;
24297   },
24298   size: function() {
24299     var size = 0;
24300     for (var property in this) if (property[0] === prefix) ++size;
24301     return size;
24302   },
24303   empty: function() {
24304     for (var property in this) if (property[0] === prefix) return false;
24305     return true;
24306   },
24307   each: function(f) {
24308     for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
24309   }
24310 };
24311
24312 function map$1(object, f) {
24313   var map = new Map;
24314
24315   // Copy constructor.
24316   if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
24317
24318   // Index array by numeric index or specified key function.
24319   else if (Array.isArray(object)) {
24320     var i = -1,
24321         n = object.length,
24322         o;
24323
24324     if (f == null) while (++i < n) map.set(i, object[i]);
24325     else while (++i < n) map.set(f(o = object[i], i, object), o);
24326   }
24327
24328   // Convert object to map.
24329   else if (object) for (var key in object) map.set(key, object[key]);
24330
24331   return map;
24332 }
24333
24334 var nest = function() {
24335   var keys = [],
24336       sortKeys = [],
24337       sortValues,
24338       rollup,
24339       nest;
24340
24341   function apply(array, depth, createResult, setResult) {
24342     if (depth >= keys.length) return rollup != null
24343         ? rollup(array) : (sortValues != null
24344         ? array.sort(sortValues)
24345         : array);
24346
24347     var i = -1,
24348         n = array.length,
24349         key = keys[depth++],
24350         keyValue,
24351         value,
24352         valuesByKey = map$1(),
24353         values,
24354         result = createResult();
24355
24356     while (++i < n) {
24357       if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
24358         values.push(value);
24359       } else {
24360         valuesByKey.set(keyValue, [value]);
24361       }
24362     }
24363
24364     valuesByKey.each(function(values, key) {
24365       setResult(result, key, apply(values, depth, createResult, setResult));
24366     });
24367
24368     return result;
24369   }
24370
24371   function entries(map, depth) {
24372     if (++depth > keys.length) return map;
24373     var array, sortKey = sortKeys[depth - 1];
24374     if (rollup != null && depth >= keys.length) array = map.entries();
24375     else array = [], map.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
24376     return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
24377   }
24378
24379   return nest = {
24380     object: function(array) { return apply(array, 0, createObject, setObject); },
24381     map: function(array) { return apply(array, 0, createMap, setMap); },
24382     entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
24383     key: function(d) { keys.push(d); return nest; },
24384     sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
24385     sortValues: function(order) { sortValues = order; return nest; },
24386     rollup: function(f) { rollup = f; return nest; }
24387   };
24388 };
24389
24390 function createObject() {
24391   return {};
24392 }
24393
24394 function setObject(object, key, value) {
24395   object[key] = value;
24396 }
24397
24398 function createMap() {
24399   return map$1();
24400 }
24401
24402 function setMap(map, key, value) {
24403   map.set(key, value);
24404 }
24405
24406 function Set() {}
24407
24408 var proto = map$1.prototype;
24409
24410 Set.prototype = set$2.prototype = {
24411   constructor: Set,
24412   has: proto.has,
24413   add: function(value) {
24414     value += "";
24415     this[prefix + value] = value;
24416     return this;
24417   },
24418   remove: proto.remove,
24419   clear: proto.clear,
24420   values: proto.keys,
24421   size: proto.size,
24422   empty: proto.empty,
24423   each: proto.each
24424 };
24425
24426 function set$2(object, f) {
24427   var set = new Set;
24428
24429   // Copy constructor.
24430   if (object instanceof Set) object.each(function(value) { set.add(value); });
24431
24432   // Otherwise, assume it’s an array.
24433   else if (object) {
24434     var i = -1, n = object.length;
24435     if (f == null) while (++i < n) set.add(object[i]);
24436     else while (++i < n) set.add(f(object[i], i, object));
24437   }
24438
24439   return set;
24440 }
24441
24442 var keys = function(map) {
24443   var keys = [];
24444   for (var key in map) keys.push(key);
24445   return keys;
24446 };
24447
24448 var values = function(map) {
24449   var values = [];
24450   for (var key in map) values.push(map[key]);
24451   return values;
24452 };
24453
24454 var entries = function(map) {
24455   var entries = [];
24456   for (var key in map) entries.push({key: key, value: map[key]});
24457   return entries;
24458 };
24459
24460 function objectConverter(columns) {
24461   return new Function("d", "return {" + columns.map(function(name, i) {
24462     return JSON.stringify(name) + ": d[" + i + "]";
24463   }).join(",") + "}");
24464 }
24465
24466 function customConverter(columns, f) {
24467   var object = objectConverter(columns);
24468   return function(row, i) {
24469     return f(object(row), i, columns);
24470   };
24471 }
24472
24473 // Compute unique columns in order of discovery.
24474 function inferColumns(rows) {
24475   var columnSet = Object.create(null),
24476       columns = [];
24477
24478   rows.forEach(function(row) {
24479     for (var column in row) {
24480       if (!(column in columnSet)) {
24481         columns.push(columnSet[column] = column);
24482       }
24483     }
24484   });
24485
24486   return columns;
24487 }
24488
24489 var dsv = function(delimiter) {
24490   var reFormat = new RegExp("[\"" + delimiter + "\n\r]"),
24491       delimiterCode = delimiter.charCodeAt(0);
24492
24493   function parse(text, f) {
24494     var convert, columns, rows = parseRows(text, function(row, i) {
24495       if (convert) return convert(row, i - 1);
24496       columns = row, convert = f ? customConverter(row, f) : objectConverter(row);
24497     });
24498     rows.columns = columns;
24499     return rows;
24500   }
24501
24502   function parseRows(text, f) {
24503     var EOL = {}, // sentinel value for end-of-line
24504         EOF = {}, // sentinel value for end-of-file
24505         rows = [], // output rows
24506         N = text.length,
24507         I = 0, // current character index
24508         n = 0, // the current line number
24509         t, // the current token
24510         eol; // is the current token followed by EOL?
24511
24512     function token() {
24513       if (I >= N) return EOF; // special case: end of file
24514       if (eol) return eol = false, EOL; // special case: end of line
24515
24516       // special case: quotes
24517       var j = I, c;
24518       if (text.charCodeAt(j) === 34) {
24519         var i = j;
24520         while (i++ < N) {
24521           if (text.charCodeAt(i) === 34) {
24522             if (text.charCodeAt(i + 1) !== 34) break;
24523             ++i;
24524           }
24525         }
24526         I = i + 2;
24527         c = text.charCodeAt(i + 1);
24528         if (c === 13) {
24529           eol = true;
24530           if (text.charCodeAt(i + 2) === 10) ++I;
24531         } else if (c === 10) {
24532           eol = true;
24533         }
24534         return text.slice(j + 1, i).replace(/""/g, "\"");
24535       }
24536
24537       // common case: find next delimiter or newline
24538       while (I < N) {
24539         var k = 1;
24540         c = text.charCodeAt(I++);
24541         if (c === 10) eol = true; // \n
24542         else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \r|\r\n
24543         else if (c !== delimiterCode) continue;
24544         return text.slice(j, I - k);
24545       }
24546
24547       // special case: last token before EOF
24548       return text.slice(j);
24549     }
24550
24551     while ((t = token()) !== EOF) {
24552       var a = [];
24553       while (t !== EOL && t !== EOF) {
24554         a.push(t);
24555         t = token();
24556       }
24557       if (f && (a = f(a, n++)) == null) continue;
24558       rows.push(a);
24559     }
24560
24561     return rows;
24562   }
24563
24564   function format(rows, columns) {
24565     if (columns == null) columns = inferColumns(rows);
24566     return [columns.map(formatValue).join(delimiter)].concat(rows.map(function(row) {
24567       return columns.map(function(column) {
24568         return formatValue(row[column]);
24569       }).join(delimiter);
24570     })).join("\n");
24571   }
24572
24573   function formatRows(rows) {
24574     return rows.map(formatRow).join("\n");
24575   }
24576
24577   function formatRow(row) {
24578     return row.map(formatValue).join(delimiter);
24579   }
24580
24581   function formatValue(text) {
24582     return text == null ? ""
24583         : reFormat.test(text += "") ? "\"" + text.replace(/\"/g, "\"\"") + "\""
24584         : text;
24585   }
24586
24587   return {
24588     parse: parse,
24589     parseRows: parseRows,
24590     format: format,
24591     formatRows: formatRows
24592   };
24593 };
24594
24595 var csv = dsv(",");
24596
24597 var csvParse = csv.parse;
24598 var csvParseRows = csv.parseRows;
24599 var csvFormat = csv.format;
24600 var csvFormatRows = csv.formatRows;
24601
24602 var tsv = dsv("\t");
24603
24604 var tsvParse = tsv.parse;
24605 var tsvParseRows = tsv.parseRows;
24606 var tsvFormat = tsv.format;
24607 var tsvFormatRows = tsv.formatRows;
24608
24609 var center$1 = function(x, y) {
24610   var nodes;
24611
24612   if (x == null) x = 0;
24613   if (y == null) y = 0;
24614
24615   function force() {
24616     var i,
24617         n = nodes.length,
24618         node,
24619         sx = 0,
24620         sy = 0;
24621
24622     for (i = 0; i < n; ++i) {
24623       node = nodes[i], sx += node.x, sy += node.y;
24624     }
24625
24626     for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
24627       node = nodes[i], node.x -= sx, node.y -= sy;
24628     }
24629   }
24630
24631   force.initialize = function(_) {
24632     nodes = _;
24633   };
24634
24635   force.x = function(_) {
24636     return arguments.length ? (x = +_, force) : x;
24637   };
24638
24639   force.y = function(_) {
24640     return arguments.length ? (y = +_, force) : y;
24641   };
24642
24643   return force;
24644 };
24645
24646 var constant$6 = function(x) {
24647   return function() {
24648     return x;
24649   };
24650 };
24651
24652 var jiggle = function() {
24653   return (Math.random() - 0.5) * 1e-6;
24654 };
24655
24656 var tree_add = function(d) {
24657   var x = +this._x.call(null, d),
24658       y = +this._y.call(null, d);
24659   return add(this.cover(x, y), x, y, d);
24660 };
24661
24662 function add(tree, x, y, d) {
24663   if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
24664
24665   var parent,
24666       node = tree._root,
24667       leaf = {data: d},
24668       x0 = tree._x0,
24669       y0 = tree._y0,
24670       x1 = tree._x1,
24671       y1 = tree._y1,
24672       xm,
24673       ym,
24674       xp,
24675       yp,
24676       right,
24677       bottom,
24678       i,
24679       j;
24680
24681   // If the tree is empty, initialize the root as a leaf.
24682   if (!node) return tree._root = leaf, tree;
24683
24684   // Find the existing leaf for the new point, or add it.
24685   while (node.length) {
24686     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24687     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24688     if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
24689   }
24690
24691   // Is the new point is exactly coincident with the existing point?
24692   xp = +tree._x.call(null, node.data);
24693   yp = +tree._y.call(null, node.data);
24694   if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
24695
24696   // Otherwise, split the leaf node until the old and new point are separated.
24697   do {
24698     parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
24699     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24700     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24701   } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
24702   return parent[j] = node, parent[i] = leaf, tree;
24703 }
24704
24705 function addAll(data) {
24706   var d, i, n = data.length,
24707       x,
24708       y,
24709       xz = new Array(n),
24710       yz = new Array(n),
24711       x0 = Infinity,
24712       y0 = Infinity,
24713       x1 = -Infinity,
24714       y1 = -Infinity;
24715
24716   // Compute the points and their extent.
24717   for (i = 0; i < n; ++i) {
24718     if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
24719     xz[i] = x;
24720     yz[i] = y;
24721     if (x < x0) x0 = x;
24722     if (x > x1) x1 = x;
24723     if (y < y0) y0 = y;
24724     if (y > y1) y1 = y;
24725   }
24726
24727   // If there were no (valid) points, inherit the existing extent.
24728   if (x1 < x0) x0 = this._x0, x1 = this._x1;
24729   if (y1 < y0) y0 = this._y0, y1 = this._y1;
24730
24731   // Expand the tree to cover the new points.
24732   this.cover(x0, y0).cover(x1, y1);
24733
24734   // Add the new points.
24735   for (i = 0; i < n; ++i) {
24736     add(this, xz[i], yz[i], data[i]);
24737   }
24738
24739   return this;
24740 }
24741
24742 var tree_cover = function(x, y) {
24743   if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points
24744
24745   var x0 = this._x0,
24746       y0 = this._y0,
24747       x1 = this._x1,
24748       y1 = this._y1;
24749
24750   // If the quadtree has no extent, initialize them.
24751   // Integer extent are necessary so that if we later double the extent,
24752   // the existing quadrant boundaries don’t change due to floating point error!
24753   if (isNaN(x0)) {
24754     x1 = (x0 = Math.floor(x)) + 1;
24755     y1 = (y0 = Math.floor(y)) + 1;
24756   }
24757
24758   // Otherwise, double repeatedly to cover.
24759   else if (x0 > x || x > x1 || y0 > y || y > y1) {
24760     var z = x1 - x0,
24761         node = this._root,
24762         parent,
24763         i;
24764
24765     switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
24766       case 0: {
24767         do parent = new Array(4), parent[i] = node, node = parent;
24768         while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1);
24769         break;
24770       }
24771       case 1: {
24772         do parent = new Array(4), parent[i] = node, node = parent;
24773         while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1);
24774         break;
24775       }
24776       case 2: {
24777         do parent = new Array(4), parent[i] = node, node = parent;
24778         while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y);
24779         break;
24780       }
24781       case 3: {
24782         do parent = new Array(4), parent[i] = node, node = parent;
24783         while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y);
24784         break;
24785       }
24786     }
24787
24788     if (this._root && this._root.length) this._root = node;
24789   }
24790
24791   // If the quadtree covers the point already, just return.
24792   else return this;
24793
24794   this._x0 = x0;
24795   this._y0 = y0;
24796   this._x1 = x1;
24797   this._y1 = y1;
24798   return this;
24799 };
24800
24801 var tree_data = function() {
24802   var data = [];
24803   this.visit(function(node) {
24804     if (!node.length) do data.push(node.data); while (node = node.next)
24805   });
24806   return data;
24807 };
24808
24809 var tree_extent = function(_) {
24810   return arguments.length
24811       ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1])
24812       : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]];
24813 };
24814
24815 var Quad = function(node, x0, y0, x1, y1) {
24816   this.node = node;
24817   this.x0 = x0;
24818   this.y0 = y0;
24819   this.x1 = x1;
24820   this.y1 = y1;
24821 };
24822
24823 var tree_find = function(x, y, radius) {
24824   var data,
24825       x0 = this._x0,
24826       y0 = this._y0,
24827       x1,
24828       y1,
24829       x2,
24830       y2,
24831       x3 = this._x1,
24832       y3 = this._y1,
24833       quads = [],
24834       node = this._root,
24835       q,
24836       i;
24837
24838   if (node) quads.push(new Quad(node, x0, y0, x3, y3));
24839   if (radius == null) radius = Infinity;
24840   else {
24841     x0 = x - radius, y0 = y - radius;
24842     x3 = x + radius, y3 = y + radius;
24843     radius *= radius;
24844   }
24845
24846   while (q = quads.pop()) {
24847
24848     // Stop searching if this quadrant can’t contain a closer node.
24849     if (!(node = q.node)
24850         || (x1 = q.x0) > x3
24851         || (y1 = q.y0) > y3
24852         || (x2 = q.x1) < x0
24853         || (y2 = q.y1) < y0) continue;
24854
24855     // Bisect the current quadrant.
24856     if (node.length) {
24857       var xm = (x1 + x2) / 2,
24858           ym = (y1 + y2) / 2;
24859
24860       quads.push(
24861         new Quad(node[3], xm, ym, x2, y2),
24862         new Quad(node[2], x1, ym, xm, y2),
24863         new Quad(node[1], xm, y1, x2, ym),
24864         new Quad(node[0], x1, y1, xm, ym)
24865       );
24866
24867       // Visit the closest quadrant first.
24868       if (i = (y >= ym) << 1 | (x >= xm)) {
24869         q = quads[quads.length - 1];
24870         quads[quads.length - 1] = quads[quads.length - 1 - i];
24871         quads[quads.length - 1 - i] = q;
24872       }
24873     }
24874
24875     // Visit this point. (Visiting coincident points isn’t necessary!)
24876     else {
24877       var dx = x - +this._x.call(null, node.data),
24878           dy = y - +this._y.call(null, node.data),
24879           d2 = dx * dx + dy * dy;
24880       if (d2 < radius) {
24881         var d = Math.sqrt(radius = d2);
24882         x0 = x - d, y0 = y - d;
24883         x3 = x + d, y3 = y + d;
24884         data = node.data;
24885       }
24886     }
24887   }
24888
24889   return data;
24890 };
24891
24892 var tree_remove = function(d) {
24893   if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
24894
24895   var parent,
24896       node = this._root,
24897       retainer,
24898       previous,
24899       next,
24900       x0 = this._x0,
24901       y0 = this._y0,
24902       x1 = this._x1,
24903       y1 = this._y1,
24904       x,
24905       y,
24906       xm,
24907       ym,
24908       right,
24909       bottom,
24910       i,
24911       j;
24912
24913   // If the tree is empty, initialize the root as a leaf.
24914   if (!node) return this;
24915
24916   // Find the leaf node for the point.
24917   // While descending, also retain the deepest parent with a non-removed sibling.
24918   if (node.length) while (true) {
24919     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24920     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24921     if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
24922     if (!node.length) break;
24923     if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
24924   }
24925
24926   // Find the point to remove.
24927   while (node.data !== d) if (!(previous = node, node = node.next)) return this;
24928   if (next = node.next) delete node.next;
24929
24930   // If there are multiple coincident points, remove just the point.
24931   if (previous) return (next ? previous.next = next : delete previous.next), this;
24932
24933   // If this is the root point, remove it.
24934   if (!parent) return this._root = next, this;
24935
24936   // Remove this leaf.
24937   next ? parent[i] = next : delete parent[i];
24938
24939   // If the parent now contains exactly one leaf, collapse superfluous parents.
24940   if ((node = parent[0] || parent[1] || parent[2] || parent[3])
24941       && node === (parent[3] || parent[2] || parent[1] || parent[0])
24942       && !node.length) {
24943     if (retainer) retainer[j] = node;
24944     else this._root = node;
24945   }
24946
24947   return this;
24948 };
24949
24950 function removeAll(data) {
24951   for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
24952   return this;
24953 }
24954
24955 var tree_root = function() {
24956   return this._root;
24957 };
24958
24959 var tree_size = function() {
24960   var size = 0;
24961   this.visit(function(node) {
24962     if (!node.length) do ++size; while (node = node.next)
24963   });
24964   return size;
24965 };
24966
24967 var tree_visit = function(callback) {
24968   var quads = [], q, node = this._root, child, x0, y0, x1, y1;
24969   if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1));
24970   while (q = quads.pop()) {
24971     if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
24972       var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
24973       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
24974       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
24975       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
24976       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
24977     }
24978   }
24979   return this;
24980 };
24981
24982 var tree_visitAfter = function(callback) {
24983   var quads = [], next = [], q;
24984   if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1));
24985   while (q = quads.pop()) {
24986     var node = q.node;
24987     if (node.length) {
24988       var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
24989       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
24990       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
24991       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
24992       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
24993     }
24994     next.push(q);
24995   }
24996   while (q = next.pop()) {
24997     callback(q.node, q.x0, q.y0, q.x1, q.y1);
24998   }
24999   return this;
25000 };
25001
25002 function defaultX(d) {
25003   return d[0];
25004 }
25005
25006 var tree_x = function(_) {
25007   return arguments.length ? (this._x = _, this) : this._x;
25008 };
25009
25010 function defaultY(d) {
25011   return d[1];
25012 }
25013
25014 var tree_y = function(_) {
25015   return arguments.length ? (this._y = _, this) : this._y;
25016 };
25017
25018 function quadtree(nodes, x, y) {
25019   var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
25020   return nodes == null ? tree : tree.addAll(nodes);
25021 }
25022
25023 function Quadtree(x, y, x0, y0, x1, y1) {
25024   this._x = x;
25025   this._y = y;
25026   this._x0 = x0;
25027   this._y0 = y0;
25028   this._x1 = x1;
25029   this._y1 = y1;
25030   this._root = undefined;
25031 }
25032
25033 function leaf_copy(leaf) {
25034   var copy = {data: leaf.data}, next = copy;
25035   while (leaf = leaf.next) next = next.next = {data: leaf.data};
25036   return copy;
25037 }
25038
25039 var treeProto = quadtree.prototype = Quadtree.prototype;
25040
25041 treeProto.copy = function() {
25042   var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1),
25043       node = this._root,
25044       nodes,
25045       child;
25046
25047   if (!node) return copy;
25048
25049   if (!node.length) return copy._root = leaf_copy(node), copy;
25050
25051   nodes = [{source: node, target: copy._root = new Array(4)}];
25052   while (node = nodes.pop()) {
25053     for (var i = 0; i < 4; ++i) {
25054       if (child = node.source[i]) {
25055         if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)});
25056         else node.target[i] = leaf_copy(child);
25057       }
25058     }
25059   }
25060
25061   return copy;
25062 };
25063
25064 treeProto.add = tree_add;
25065 treeProto.addAll = addAll;
25066 treeProto.cover = tree_cover;
25067 treeProto.data = tree_data;
25068 treeProto.extent = tree_extent;
25069 treeProto.find = tree_find;
25070 treeProto.remove = tree_remove;
25071 treeProto.removeAll = removeAll;
25072 treeProto.root = tree_root;
25073 treeProto.size = tree_size;
25074 treeProto.visit = tree_visit;
25075 treeProto.visitAfter = tree_visitAfter;
25076 treeProto.x = tree_x;
25077 treeProto.y = tree_y;
25078
25079 function x(d) {
25080   return d.x + d.vx;
25081 }
25082
25083 function y(d) {
25084   return d.y + d.vy;
25085 }
25086
25087 var collide = function(radius) {
25088   var nodes,
25089       radii,
25090       strength = 1,
25091       iterations = 1;
25092
25093   if (typeof radius !== "function") radius = constant$6(radius == null ? 1 : +radius);
25094
25095   function force() {
25096     var i, n = nodes.length,
25097         tree,
25098         node,
25099         xi,
25100         yi,
25101         ri,
25102         ri2;
25103
25104     for (var k = 0; k < iterations; ++k) {
25105       tree = quadtree(nodes, x, y).visitAfter(prepare);
25106       for (i = 0; i < n; ++i) {
25107         node = nodes[i];
25108         ri = radii[node.index], ri2 = ri * ri;
25109         xi = node.x + node.vx;
25110         yi = node.y + node.vy;
25111         tree.visit(apply);
25112       }
25113     }
25114
25115     function apply(quad, x0, y0, x1, y1) {
25116       var data = quad.data, rj = quad.r, r = ri + rj;
25117       if (data) {
25118         if (data.index > node.index) {
25119           var x = xi - data.x - data.vx,
25120               y = yi - data.y - data.vy,
25121               l = x * x + y * y;
25122           if (l < r * r) {
25123             if (x === 0) x = jiggle(), l += x * x;
25124             if (y === 0) y = jiggle(), l += y * y;
25125             l = (r - (l = Math.sqrt(l))) / l * strength;
25126             node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
25127             node.vy += (y *= l) * r;
25128             data.vx -= x * (r = 1 - r);
25129             data.vy -= y * r;
25130           }
25131         }
25132         return;
25133       }
25134       return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
25135     }
25136   }
25137
25138   function prepare(quad) {
25139     if (quad.data) return quad.r = radii[quad.data.index];
25140     for (var i = quad.r = 0; i < 4; ++i) {
25141       if (quad[i] && quad[i].r > quad.r) {
25142         quad.r = quad[i].r;
25143       }
25144     }
25145   }
25146
25147   function initialize() {
25148     if (!nodes) return;
25149     var i, n = nodes.length, node;
25150     radii = new Array(n);
25151     for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
25152   }
25153
25154   force.initialize = function(_) {
25155     nodes = _;
25156     initialize();
25157   };
25158
25159   force.iterations = function(_) {
25160     return arguments.length ? (iterations = +_, force) : iterations;
25161   };
25162
25163   force.strength = function(_) {
25164     return arguments.length ? (strength = +_, force) : strength;
25165   };
25166
25167   force.radius = function(_) {
25168     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : radius;
25169   };
25170
25171   return force;
25172 };
25173
25174 function index$3(d) {
25175   return d.index;
25176 }
25177
25178 function find(nodeById, nodeId) {
25179   var node = nodeById.get(nodeId);
25180   if (!node) throw new Error("missing: " + nodeId);
25181   return node;
25182 }
25183
25184 var link = function(links) {
25185   var id = index$3,
25186       strength = defaultStrength,
25187       strengths,
25188       distance = constant$6(30),
25189       distances,
25190       nodes,
25191       count,
25192       bias,
25193       iterations = 1;
25194
25195   if (links == null) links = [];
25196
25197   function defaultStrength(link) {
25198     return 1 / Math.min(count[link.source.index], count[link.target.index]);
25199   }
25200
25201   function force(alpha) {
25202     for (var k = 0, n = links.length; k < iterations; ++k) {
25203       for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
25204         link = links[i], source = link.source, target = link.target;
25205         x = target.x + target.vx - source.x - source.vx || jiggle();
25206         y = target.y + target.vy - source.y - source.vy || jiggle();
25207         l = Math.sqrt(x * x + y * y);
25208         l = (l - distances[i]) / l * alpha * strengths[i];
25209         x *= l, y *= l;
25210         target.vx -= x * (b = bias[i]);
25211         target.vy -= y * b;
25212         source.vx += x * (b = 1 - b);
25213         source.vy += y * b;
25214       }
25215     }
25216   }
25217
25218   function initialize() {
25219     if (!nodes) return;
25220
25221     var i,
25222         n = nodes.length,
25223         m = links.length,
25224         nodeById = map$1(nodes, id),
25225         link;
25226
25227     for (i = 0, count = new Array(n); i < m; ++i) {
25228       link = links[i], link.index = i;
25229       if (typeof link.source !== "object") link.source = find(nodeById, link.source);
25230       if (typeof link.target !== "object") link.target = find(nodeById, link.target);
25231       count[link.source.index] = (count[link.source.index] || 0) + 1;
25232       count[link.target.index] = (count[link.target.index] || 0) + 1;
25233     }
25234
25235     for (i = 0, bias = new Array(m); i < m; ++i) {
25236       link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
25237     }
25238
25239     strengths = new Array(m), initializeStrength();
25240     distances = new Array(m), initializeDistance();
25241   }
25242
25243   function initializeStrength() {
25244     if (!nodes) return;
25245
25246     for (var i = 0, n = links.length; i < n; ++i) {
25247       strengths[i] = +strength(links[i], i, links);
25248     }
25249   }
25250
25251   function initializeDistance() {
25252     if (!nodes) return;
25253
25254     for (var i = 0, n = links.length; i < n; ++i) {
25255       distances[i] = +distance(links[i], i, links);
25256     }
25257   }
25258
25259   force.initialize = function(_) {
25260     nodes = _;
25261     initialize();
25262   };
25263
25264   force.links = function(_) {
25265     return arguments.length ? (links = _, initialize(), force) : links;
25266   };
25267
25268   force.id = function(_) {
25269     return arguments.length ? (id = _, force) : id;
25270   };
25271
25272   force.iterations = function(_) {
25273     return arguments.length ? (iterations = +_, force) : iterations;
25274   };
25275
25276   force.strength = function(_) {
25277     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initializeStrength(), force) : strength;
25278   };
25279
25280   force.distance = function(_) {
25281     return arguments.length ? (distance = typeof _ === "function" ? _ : constant$6(+_), initializeDistance(), force) : distance;
25282   };
25283
25284   return force;
25285 };
25286
25287 function x$1(d) {
25288   return d.x;
25289 }
25290
25291 function y$1(d) {
25292   return d.y;
25293 }
25294
25295 var initialRadius = 10;
25296 var initialAngle = Math.PI * (3 - Math.sqrt(5));
25297
25298 var simulation = function(nodes) {
25299   var simulation,
25300       alpha = 1,
25301       alphaMin = 0.001,
25302       alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
25303       alphaTarget = 0,
25304       velocityDecay = 0.6,
25305       forces = map$1(),
25306       stepper = timer(step),
25307       event = dispatch("tick", "end");
25308
25309   if (nodes == null) nodes = [];
25310
25311   function step() {
25312     tick();
25313     event.call("tick", simulation);
25314     if (alpha < alphaMin) {
25315       stepper.stop();
25316       event.call("end", simulation);
25317     }
25318   }
25319
25320   function tick() {
25321     var i, n = nodes.length, node;
25322
25323     alpha += (alphaTarget - alpha) * alphaDecay;
25324
25325     forces.each(function(force) {
25326       force(alpha);
25327     });
25328
25329     for (i = 0; i < n; ++i) {
25330       node = nodes[i];
25331       if (node.fx == null) node.x += node.vx *= velocityDecay;
25332       else node.x = node.fx, node.vx = 0;
25333       if (node.fy == null) node.y += node.vy *= velocityDecay;
25334       else node.y = node.fy, node.vy = 0;
25335     }
25336   }
25337
25338   function initializeNodes() {
25339     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25340       node = nodes[i], node.index = i;
25341       if (isNaN(node.x) || isNaN(node.y)) {
25342         var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
25343         node.x = radius * Math.cos(angle);
25344         node.y = radius * Math.sin(angle);
25345       }
25346       if (isNaN(node.vx) || isNaN(node.vy)) {
25347         node.vx = node.vy = 0;
25348       }
25349     }
25350   }
25351
25352   function initializeForce(force) {
25353     if (force.initialize) force.initialize(nodes);
25354     return force;
25355   }
25356
25357   initializeNodes();
25358
25359   return simulation = {
25360     tick: tick,
25361
25362     restart: function() {
25363       return stepper.restart(step), simulation;
25364     },
25365
25366     stop: function() {
25367       return stepper.stop(), simulation;
25368     },
25369
25370     nodes: function(_) {
25371       return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes;
25372     },
25373
25374     alpha: function(_) {
25375       return arguments.length ? (alpha = +_, simulation) : alpha;
25376     },
25377
25378     alphaMin: function(_) {
25379       return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
25380     },
25381
25382     alphaDecay: function(_) {
25383       return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
25384     },
25385
25386     alphaTarget: function(_) {
25387       return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
25388     },
25389
25390     velocityDecay: function(_) {
25391       return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
25392     },
25393
25394     force: function(name, _) {
25395       return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
25396     },
25397
25398     find: function(x, y, radius) {
25399       var i = 0,
25400           n = nodes.length,
25401           dx,
25402           dy,
25403           d2,
25404           node,
25405           closest;
25406
25407       if (radius == null) radius = Infinity;
25408       else radius *= radius;
25409
25410       for (i = 0; i < n; ++i) {
25411         node = nodes[i];
25412         dx = x - node.x;
25413         dy = y - node.y;
25414         d2 = dx * dx + dy * dy;
25415         if (d2 < radius) closest = node, radius = d2;
25416       }
25417
25418       return closest;
25419     },
25420
25421     on: function(name, _) {
25422       return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
25423     }
25424   };
25425 };
25426
25427 var manyBody = function() {
25428   var nodes,
25429       node,
25430       alpha,
25431       strength = constant$6(-30),
25432       strengths,
25433       distanceMin2 = 1,
25434       distanceMax2 = Infinity,
25435       theta2 = 0.81;
25436
25437   function force(_) {
25438     var i, n = nodes.length, tree = quadtree(nodes, x$1, y$1).visitAfter(accumulate);
25439     for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
25440   }
25441
25442   function initialize() {
25443     if (!nodes) return;
25444     var i, n = nodes.length, node;
25445     strengths = new Array(n);
25446     for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
25447   }
25448
25449   function accumulate(quad) {
25450     var strength = 0, q, c, x$$1, y$$1, i;
25451
25452     // For internal nodes, accumulate forces from child quadrants.
25453     if (quad.length) {
25454       for (x$$1 = y$$1 = i = 0; i < 4; ++i) {
25455         if ((q = quad[i]) && (c = q.value)) {
25456           strength += c, x$$1 += c * q.x, y$$1 += c * q.y;
25457         }
25458       }
25459       quad.x = x$$1 / strength;
25460       quad.y = y$$1 / strength;
25461     }
25462
25463     // For leaf nodes, accumulate forces from coincident quadrants.
25464     else {
25465       q = quad;
25466       q.x = q.data.x;
25467       q.y = q.data.y;
25468       do strength += strengths[q.data.index];
25469       while (q = q.next);
25470     }
25471
25472     quad.value = strength;
25473   }
25474
25475   function apply(quad, x1, _, x2) {
25476     if (!quad.value) return true;
25477
25478     var x$$1 = quad.x - node.x,
25479         y$$1 = quad.y - node.y,
25480         w = x2 - x1,
25481         l = x$$1 * x$$1 + y$$1 * y$$1;
25482
25483     // Apply the Barnes-Hut approximation if possible.
25484     // Limit forces for very close nodes; randomize direction if coincident.
25485     if (w * w / theta2 < l) {
25486       if (l < distanceMax2) {
25487         if (x$$1 === 0) x$$1 = jiggle(), l += x$$1 * x$$1;
25488         if (y$$1 === 0) y$$1 = jiggle(), l += y$$1 * y$$1;
25489         if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25490         node.vx += x$$1 * quad.value * alpha / l;
25491         node.vy += y$$1 * quad.value * alpha / l;
25492       }
25493       return true;
25494     }
25495
25496     // Otherwise, process points directly.
25497     else if (quad.length || l >= distanceMax2) return;
25498
25499     // Limit forces for very close nodes; randomize direction if coincident.
25500     if (quad.data !== node || quad.next) {
25501       if (x$$1 === 0) x$$1 = jiggle(), l += x$$1 * x$$1;
25502       if (y$$1 === 0) y$$1 = jiggle(), l += y$$1 * y$$1;
25503       if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25504     }
25505
25506     do if (quad.data !== node) {
25507       w = strengths[quad.data.index] * alpha / l;
25508       node.vx += x$$1 * w;
25509       node.vy += y$$1 * w;
25510     } while (quad = quad.next);
25511   }
25512
25513   force.initialize = function(_) {
25514     nodes = _;
25515     initialize();
25516   };
25517
25518   force.strength = function(_) {
25519     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25520   };
25521
25522   force.distanceMin = function(_) {
25523     return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
25524   };
25525
25526   force.distanceMax = function(_) {
25527     return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
25528   };
25529
25530   force.theta = function(_) {
25531     return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
25532   };
25533
25534   return force;
25535 };
25536
25537 var x$2 = function(x) {
25538   var strength = constant$6(0.1),
25539       nodes,
25540       strengths,
25541       xz;
25542
25543   if (typeof x !== "function") x = constant$6(x == null ? 0 : +x);
25544
25545   function force(alpha) {
25546     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25547       node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
25548     }
25549   }
25550
25551   function initialize() {
25552     if (!nodes) return;
25553     var i, n = nodes.length;
25554     strengths = new Array(n);
25555     xz = new Array(n);
25556     for (i = 0; i < n; ++i) {
25557       strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25558     }
25559   }
25560
25561   force.initialize = function(_) {
25562     nodes = _;
25563     initialize();
25564   };
25565
25566   force.strength = function(_) {
25567     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25568   };
25569
25570   force.x = function(_) {
25571     return arguments.length ? (x = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : x;
25572   };
25573
25574   return force;
25575 };
25576
25577 var y$2 = function(y) {
25578   var strength = constant$6(0.1),
25579       nodes,
25580       strengths,
25581       yz;
25582
25583   if (typeof y !== "function") y = constant$6(y == null ? 0 : +y);
25584
25585   function force(alpha) {
25586     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25587       node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
25588     }
25589   }
25590
25591   function initialize() {
25592     if (!nodes) return;
25593     var i, n = nodes.length;
25594     strengths = new Array(n);
25595     yz = new Array(n);
25596     for (i = 0; i < n; ++i) {
25597       strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25598     }
25599   }
25600
25601   force.initialize = function(_) {
25602     nodes = _;
25603     initialize();
25604   };
25605
25606   force.strength = function(_) {
25607     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25608   };
25609
25610   force.y = function(_) {
25611     return arguments.length ? (y = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : y;
25612   };
25613
25614   return force;
25615 };
25616
25617 // Computes the decimal coefficient and exponent of the specified number x with
25618 // significant digits p, where x is positive and p is in [1, 21] or undefined.
25619 // For example, formatDecimal(1.23) returns ["123", 0].
25620 var formatDecimal = function(x, p) {
25621   if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
25622   var i, coefficient = x.slice(0, i);
25623
25624   // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
25625   // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
25626   return [
25627     coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
25628     +x.slice(i + 1)
25629   ];
25630 };
25631
25632 var exponent$1 = function(x) {
25633   return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
25634 };
25635
25636 var formatGroup = function(grouping, thousands) {
25637   return function(value, width) {
25638     var i = value.length,
25639         t = [],
25640         j = 0,
25641         g = grouping[0],
25642         length = 0;
25643
25644     while (i > 0 && g > 0) {
25645       if (length + g + 1 > width) g = Math.max(1, width - length);
25646       t.push(value.substring(i -= g, i + g));
25647       if ((length += g + 1) > width) break;
25648       g = grouping[j = (j + 1) % grouping.length];
25649     }
25650
25651     return t.reverse().join(thousands);
25652   };
25653 };
25654
25655 var formatNumerals = function(numerals) {
25656   return function(value) {
25657     return value.replace(/[0-9]/g, function(i) {
25658       return numerals[+i];
25659     });
25660   };
25661 };
25662
25663 var formatDefault = function(x, p) {
25664   x = x.toPrecision(p);
25665
25666   out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
25667     switch (x[i]) {
25668       case ".": i0 = i1 = i; break;
25669       case "0": if (i0 === 0) i0 = i; i1 = i; break;
25670       case "e": break out;
25671       default: if (i0 > 0) i0 = 0; break;
25672     }
25673   }
25674
25675   return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
25676 };
25677
25678 var prefixExponent;
25679
25680 var formatPrefixAuto = function(x, p) {
25681   var d = formatDecimal(x, p);
25682   if (!d) return x + "";
25683   var coefficient = d[0],
25684       exponent = d[1],
25685       i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
25686       n = coefficient.length;
25687   return i === n ? coefficient
25688       : i > n ? coefficient + new Array(i - n + 1).join("0")
25689       : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
25690       : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
25691 };
25692
25693 var formatRounded = function(x, p) {
25694   var d = formatDecimal(x, p);
25695   if (!d) return x + "";
25696   var coefficient = d[0],
25697       exponent = d[1];
25698   return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
25699       : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
25700       : coefficient + new Array(exponent - coefficient.length + 2).join("0");
25701 };
25702
25703 var formatTypes = {
25704   "": formatDefault,
25705   "%": function(x, p) { return (x * 100).toFixed(p); },
25706   "b": function(x) { return Math.round(x).toString(2); },
25707   "c": function(x) { return x + ""; },
25708   "d": function(x) { return Math.round(x).toString(10); },
25709   "e": function(x, p) { return x.toExponential(p); },
25710   "f": function(x, p) { return x.toFixed(p); },
25711   "g": function(x, p) { return x.toPrecision(p); },
25712   "o": function(x) { return Math.round(x).toString(8); },
25713   "p": function(x, p) { return formatRounded(x * 100, p); },
25714   "r": formatRounded,
25715   "s": formatPrefixAuto,
25716   "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
25717   "x": function(x) { return Math.round(x).toString(16); }
25718 };
25719
25720 // [[fill]align][sign][symbol][0][width][,][.precision][type]
25721 var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
25722
25723 function formatSpecifier(specifier) {
25724   return new FormatSpecifier(specifier);
25725 }
25726
25727 formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
25728
25729 function FormatSpecifier(specifier) {
25730   if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
25731
25732   var match,
25733       fill = match[1] || " ",
25734       align = match[2] || ">",
25735       sign = match[3] || "-",
25736       symbol = match[4] || "",
25737       zero = !!match[5],
25738       width = match[6] && +match[6],
25739       comma = !!match[7],
25740       precision = match[8] && +match[8].slice(1),
25741       type = match[9] || "";
25742
25743   // The "n" type is an alias for ",g".
25744   if (type === "n") comma = true, type = "g";
25745
25746   // Map invalid types to the default format.
25747   else if (!formatTypes[type]) type = "";
25748
25749   // If zero fill is specified, padding goes after sign and before digits.
25750   if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
25751
25752   this.fill = fill;
25753   this.align = align;
25754   this.sign = sign;
25755   this.symbol = symbol;
25756   this.zero = zero;
25757   this.width = width;
25758   this.comma = comma;
25759   this.precision = precision;
25760   this.type = type;
25761 }
25762
25763 FormatSpecifier.prototype.toString = function() {
25764   return this.fill
25765       + this.align
25766       + this.sign
25767       + this.symbol
25768       + (this.zero ? "0" : "")
25769       + (this.width == null ? "" : Math.max(1, this.width | 0))
25770       + (this.comma ? "," : "")
25771       + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
25772       + this.type;
25773 };
25774
25775 var identity$3 = function(x) {
25776   return x;
25777 };
25778
25779 var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
25780
25781 var formatLocale = function(locale) {
25782   var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3,
25783       currency = locale.currency,
25784       decimal = locale.decimal,
25785       numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$3,
25786       percent = locale.percent || "%";
25787
25788   function newFormat(specifier) {
25789     specifier = formatSpecifier(specifier);
25790
25791     var fill = specifier.fill,
25792         align = specifier.align,
25793         sign = specifier.sign,
25794         symbol = specifier.symbol,
25795         zero = specifier.zero,
25796         width = specifier.width,
25797         comma = specifier.comma,
25798         precision = specifier.precision,
25799         type = specifier.type;
25800
25801     // Compute the prefix and suffix.
25802     // For SI-prefix, the suffix is lazily computed.
25803     var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
25804         suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : "";
25805
25806     // What format function should we use?
25807     // Is this an integer type?
25808     // Can this type generate exponential notation?
25809     var formatType = formatTypes[type],
25810         maybeSuffix = !type || /[defgprs%]/.test(type);
25811
25812     // Set the default precision if not specified,
25813     // or clamp the specified precision to the supported range.
25814     // For significant precision, it must be in [1, 21].
25815     // For fixed precision, it must be in [0, 20].
25816     precision = precision == null ? (type ? 6 : 12)
25817         : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
25818         : Math.max(0, Math.min(20, precision));
25819
25820     function format(value) {
25821       var valuePrefix = prefix,
25822           valueSuffix = suffix,
25823           i, n, c;
25824
25825       if (type === "c") {
25826         valueSuffix = formatType(value) + valueSuffix;
25827         value = "";
25828       } else {
25829         value = +value;
25830
25831         // Perform the initial formatting.
25832         var valueNegative = value < 0;
25833         value = formatType(Math.abs(value), precision);
25834
25835         // If a negative value rounds to zero during formatting, treat as positive.
25836         if (valueNegative && +value === 0) valueNegative = false;
25837
25838         // Compute the prefix and suffix.
25839         valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
25840         valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
25841
25842         // Break the formatted value into the integer “value” part that can be
25843         // grouped, and fractional or exponential “suffix” part that is not.
25844         if (maybeSuffix) {
25845           i = -1, n = value.length;
25846           while (++i < n) {
25847             if (c = value.charCodeAt(i), 48 > c || c > 57) {
25848               valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
25849               value = value.slice(0, i);
25850               break;
25851             }
25852           }
25853         }
25854       }
25855
25856       // If the fill character is not "0", grouping is applied before padding.
25857       if (comma && !zero) value = group(value, Infinity);
25858
25859       // Compute the padding.
25860       var length = valuePrefix.length + value.length + valueSuffix.length,
25861           padding = length < width ? new Array(width - length + 1).join(fill) : "";
25862
25863       // If the fill character is "0", grouping is applied after padding.
25864       if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
25865
25866       // Reconstruct the final output based on the desired alignment.
25867       switch (align) {
25868         case "<": value = valuePrefix + value + valueSuffix + padding; break;
25869         case "=": value = valuePrefix + padding + value + valueSuffix; break;
25870         case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
25871         default: value = padding + valuePrefix + value + valueSuffix; break;
25872       }
25873
25874       return numerals(value);
25875     }
25876
25877     format.toString = function() {
25878       return specifier + "";
25879     };
25880
25881     return format;
25882   }
25883
25884   function formatPrefix(specifier, value) {
25885     var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
25886         e = Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3,
25887         k = Math.pow(10, -e),
25888         prefix = prefixes[8 + e / 3];
25889     return function(value) {
25890       return f(k * value) + prefix;
25891     };
25892   }
25893
25894   return {
25895     format: newFormat,
25896     formatPrefix: formatPrefix
25897   };
25898 };
25899
25900 var locale$1;
25901 var format;
25902 var formatPrefix;
25903
25904 defaultLocale({
25905   decimal: ".",
25906   thousands: ",",
25907   grouping: [3],
25908   currency: ["$", ""]
25909 });
25910
25911 function defaultLocale(definition) {
25912   locale$1 = formatLocale(definition);
25913   format = locale$1.format;
25914   formatPrefix = locale$1.formatPrefix;
25915   return locale$1;
25916 }
25917
25918 var precisionFixed = function(step) {
25919   return Math.max(0, -exponent$1(Math.abs(step)));
25920 };
25921
25922 var precisionPrefix = function(step, value) {
25923   return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3 - exponent$1(Math.abs(step)));
25924 };
25925
25926 var precisionRound = function(step, max) {
25927   step = Math.abs(step), max = Math.abs(max) - step;
25928   return Math.max(0, exponent$1(max) - exponent$1(step)) + 1;
25929 };
25930
25931 // Adds floating point numbers with twice the normal precision.
25932 // Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
25933 // Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
25934 // 305–363 (1997).
25935 // Code adapted from GeographicLib by Charles F. F. Karney,
25936 // http://geographiclib.sourceforge.net/
25937
25938 var adder = function() {
25939   return new Adder;
25940 };
25941
25942 function Adder() {
25943   this.reset();
25944 }
25945
25946 Adder.prototype = {
25947   constructor: Adder,
25948   reset: function() {
25949     this.s = // rounded value
25950     this.t = 0; // exact error
25951   },
25952   add: function(y) {
25953     add$1(temp, y, this.t);
25954     add$1(this, temp.s, this.s);
25955     if (this.s) this.t += temp.t;
25956     else this.s = temp.t;
25957   },
25958   valueOf: function() {
25959     return this.s;
25960   }
25961 };
25962
25963 var temp = new Adder;
25964
25965 function add$1(adder, a, b) {
25966   var x = adder.s = a + b,
25967       bv = x - a,
25968       av = x - bv;
25969   adder.t = (a - av) + (b - bv);
25970 }
25971
25972 var epsilon$2 = 1e-6;
25973 var epsilon2$1 = 1e-12;
25974 var pi$3 = Math.PI;
25975 var halfPi$2 = pi$3 / 2;
25976 var quarterPi = pi$3 / 4;
25977 var tau$3 = pi$3 * 2;
25978
25979 var degrees$1 = 180 / pi$3;
25980 var radians = pi$3 / 180;
25981
25982 var abs = Math.abs;
25983 var atan = Math.atan;
25984 var atan2 = Math.atan2;
25985 var cos$1 = Math.cos;
25986 var ceil = Math.ceil;
25987 var exp = Math.exp;
25988
25989 var log = Math.log;
25990 var pow = Math.pow;
25991 var sin$1 = Math.sin;
25992 var sign = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
25993 var sqrt = Math.sqrt;
25994 var tan = Math.tan;
25995
25996 function acos(x) {
25997   return x > 1 ? 0 : x < -1 ? pi$3 : Math.acos(x);
25998 }
25999
26000 function asin(x) {
26001   return x > 1 ? halfPi$2 : x < -1 ? -halfPi$2 : Math.asin(x);
26002 }
26003
26004 function haversin(x) {
26005   return (x = sin$1(x / 2)) * x;
26006 }
26007
26008 function noop$1() {}
26009
26010 function streamGeometry(geometry, stream) {
26011   if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
26012     streamGeometryType[geometry.type](geometry, stream);
26013   }
26014 }
26015
26016 var streamObjectType = {
26017   Feature: function(object, stream) {
26018     streamGeometry(object.geometry, stream);
26019   },
26020   FeatureCollection: function(object, stream) {
26021     var features = object.features, i = -1, n = features.length;
26022     while (++i < n) streamGeometry(features[i].geometry, stream);
26023   }
26024 };
26025
26026 var streamGeometryType = {
26027   Sphere: function(object, stream) {
26028     stream.sphere();
26029   },
26030   Point: function(object, stream) {
26031     object = object.coordinates;
26032     stream.point(object[0], object[1], object[2]);
26033   },
26034   MultiPoint: function(object, stream) {
26035     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26036     while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
26037   },
26038   LineString: function(object, stream) {
26039     streamLine(object.coordinates, stream, 0);
26040   },
26041   MultiLineString: function(object, stream) {
26042     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26043     while (++i < n) streamLine(coordinates[i], stream, 0);
26044   },
26045   Polygon: function(object, stream) {
26046     streamPolygon(object.coordinates, stream);
26047   },
26048   MultiPolygon: function(object, stream) {
26049     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26050     while (++i < n) streamPolygon(coordinates[i], stream);
26051   },
26052   GeometryCollection: function(object, stream) {
26053     var geometries = object.geometries, i = -1, n = geometries.length;
26054     while (++i < n) streamGeometry(geometries[i], stream);
26055   }
26056 };
26057
26058 function streamLine(coordinates, stream, closed) {
26059   var i = -1, n = coordinates.length - closed, coordinate;
26060   stream.lineStart();
26061   while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
26062   stream.lineEnd();
26063 }
26064
26065 function streamPolygon(coordinates, stream) {
26066   var i = -1, n = coordinates.length;
26067   stream.polygonStart();
26068   while (++i < n) streamLine(coordinates[i], stream, 1);
26069   stream.polygonEnd();
26070 }
26071
26072 var geoStream = function(object, stream) {
26073   if (object && streamObjectType.hasOwnProperty(object.type)) {
26074     streamObjectType[object.type](object, stream);
26075   } else {
26076     streamGeometry(object, stream);
26077   }
26078 };
26079
26080 var areaRingSum = adder();
26081
26082 var areaSum = adder();
26083 var lambda00;
26084 var phi00;
26085 var lambda0;
26086 var cosPhi0;
26087 var sinPhi0;
26088
26089 var areaStream = {
26090   point: noop$1,
26091   lineStart: noop$1,
26092   lineEnd: noop$1,
26093   polygonStart: function() {
26094     areaRingSum.reset();
26095     areaStream.lineStart = areaRingStart;
26096     areaStream.lineEnd = areaRingEnd;
26097   },
26098   polygonEnd: function() {
26099     var areaRing = +areaRingSum;
26100     areaSum.add(areaRing < 0 ? tau$3 + areaRing : areaRing);
26101     this.lineStart = this.lineEnd = this.point = noop$1;
26102   },
26103   sphere: function() {
26104     areaSum.add(tau$3);
26105   }
26106 };
26107
26108 function areaRingStart() {
26109   areaStream.point = areaPointFirst;
26110 }
26111
26112 function areaRingEnd() {
26113   areaPoint(lambda00, phi00);
26114 }
26115
26116 function areaPointFirst(lambda, phi) {
26117   areaStream.point = areaPoint;
26118   lambda00 = lambda, phi00 = phi;
26119   lambda *= radians, phi *= radians;
26120   lambda0 = lambda, cosPhi0 = cos$1(phi = phi / 2 + quarterPi), sinPhi0 = sin$1(phi);
26121 }
26122
26123 function areaPoint(lambda, phi) {
26124   lambda *= radians, phi *= radians;
26125   phi = phi / 2 + quarterPi; // half the angular distance from south pole
26126
26127   // Spherical excess E for a spherical triangle with vertices: south pole,
26128   // previous point, current point.  Uses a formula derived from Cagnoli’s
26129   // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
26130   var dLambda = lambda - lambda0,
26131       sdLambda = dLambda >= 0 ? 1 : -1,
26132       adLambda = sdLambda * dLambda,
26133       cosPhi = cos$1(phi),
26134       sinPhi = sin$1(phi),
26135       k = sinPhi0 * sinPhi,
26136       u = cosPhi0 * cosPhi + k * cos$1(adLambda),
26137       v = k * sdLambda * sin$1(adLambda);
26138   areaRingSum.add(atan2(v, u));
26139
26140   // Advance the previous points.
26141   lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
26142 }
26143
26144 var area = function(object) {
26145   areaSum.reset();
26146   geoStream(object, areaStream);
26147   return areaSum * 2;
26148 };
26149
26150 function spherical(cartesian) {
26151   return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
26152 }
26153
26154 function cartesian(spherical) {
26155   var lambda = spherical[0], phi = spherical[1], cosPhi = cos$1(phi);
26156   return [cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi)];
26157 }
26158
26159 function cartesianDot(a, b) {
26160   return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
26161 }
26162
26163 function cartesianCross(a, b) {
26164   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]];
26165 }
26166
26167 // TODO return a
26168 function cartesianAddInPlace(a, b) {
26169   a[0] += b[0], a[1] += b[1], a[2] += b[2];
26170 }
26171
26172 function cartesianScale(vector, k) {
26173   return [vector[0] * k, vector[1] * k, vector[2] * k];
26174 }
26175
26176 // TODO return d
26177 function cartesianNormalizeInPlace(d) {
26178   var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
26179   d[0] /= l, d[1] /= l, d[2] /= l;
26180 }
26181
26182 var lambda0$1;
26183 var phi0;
26184 var lambda1;
26185 var phi1;
26186 var lambda2;
26187 var lambda00$1;
26188 var phi00$1;
26189 var p0;
26190 var deltaSum = adder();
26191 var ranges;
26192 var range;
26193
26194 var boundsStream = {
26195   point: boundsPoint,
26196   lineStart: boundsLineStart,
26197   lineEnd: boundsLineEnd,
26198   polygonStart: function() {
26199     boundsStream.point = boundsRingPoint;
26200     boundsStream.lineStart = boundsRingStart;
26201     boundsStream.lineEnd = boundsRingEnd;
26202     deltaSum.reset();
26203     areaStream.polygonStart();
26204   },
26205   polygonEnd: function() {
26206     areaStream.polygonEnd();
26207     boundsStream.point = boundsPoint;
26208     boundsStream.lineStart = boundsLineStart;
26209     boundsStream.lineEnd = boundsLineEnd;
26210     if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
26211     else if (deltaSum > epsilon$2) phi1 = 90;
26212     else if (deltaSum < -epsilon$2) phi0 = -90;
26213     range[0] = lambda0$1, range[1] = lambda1;
26214   }
26215 };
26216
26217 function boundsPoint(lambda, phi) {
26218   ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26219   if (phi < phi0) phi0 = phi;
26220   if (phi > phi1) phi1 = phi;
26221 }
26222
26223 function linePoint(lambda, phi) {
26224   var p = cartesian([lambda * radians, phi * radians]);
26225   if (p0) {
26226     var normal = cartesianCross(p0, p),
26227         equatorial = [normal[1], -normal[0], 0],
26228         inflection = cartesianCross(equatorial, normal);
26229     cartesianNormalizeInPlace(inflection);
26230     inflection = spherical(inflection);
26231     var delta = lambda - lambda2,
26232         sign$$1 = delta > 0 ? 1 : -1,
26233         lambdai = inflection[0] * degrees$1 * sign$$1,
26234         phii,
26235         antimeridian = abs(delta) > 180;
26236     if (antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26237       phii = inflection[1] * degrees$1;
26238       if (phii > phi1) phi1 = phii;
26239     } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26240       phii = -inflection[1] * degrees$1;
26241       if (phii < phi0) phi0 = phii;
26242     } else {
26243       if (phi < phi0) phi0 = phi;
26244       if (phi > phi1) phi1 = phi;
26245     }
26246     if (antimeridian) {
26247       if (lambda < lambda2) {
26248         if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26249       } else {
26250         if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26251       }
26252     } else {
26253       if (lambda1 >= lambda0$1) {
26254         if (lambda < lambda0$1) lambda0$1 = lambda;
26255         if (lambda > lambda1) lambda1 = lambda;
26256       } else {
26257         if (lambda > lambda2) {
26258           if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26259         } else {
26260           if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26261         }
26262       }
26263     }
26264   } else {
26265     ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26266   }
26267   if (phi < phi0) phi0 = phi;
26268   if (phi > phi1) phi1 = phi;
26269   p0 = p, lambda2 = lambda;
26270 }
26271
26272 function boundsLineStart() {
26273   boundsStream.point = linePoint;
26274 }
26275
26276 function boundsLineEnd() {
26277   range[0] = lambda0$1, range[1] = lambda1;
26278   boundsStream.point = boundsPoint;
26279   p0 = null;
26280 }
26281
26282 function boundsRingPoint(lambda, phi) {
26283   if (p0) {
26284     var delta = lambda - lambda2;
26285     deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
26286   } else {
26287     lambda00$1 = lambda, phi00$1 = phi;
26288   }
26289   areaStream.point(lambda, phi);
26290   linePoint(lambda, phi);
26291 }
26292
26293 function boundsRingStart() {
26294   areaStream.lineStart();
26295 }
26296
26297 function boundsRingEnd() {
26298   boundsRingPoint(lambda00$1, phi00$1);
26299   areaStream.lineEnd();
26300   if (abs(deltaSum) > epsilon$2) lambda0$1 = -(lambda1 = 180);
26301   range[0] = lambda0$1, range[1] = lambda1;
26302   p0 = null;
26303 }
26304
26305 // Finds the left-right distance between two longitudes.
26306 // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
26307 // the distance between ±180° to be 360°.
26308 function angle(lambda0, lambda1) {
26309   return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
26310 }
26311
26312 function rangeCompare(a, b) {
26313   return a[0] - b[0];
26314 }
26315
26316 function rangeContains(range, x) {
26317   return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
26318 }
26319
26320 var bounds = function(feature) {
26321   var i, n, a, b, merged, deltaMax, delta;
26322
26323   phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
26324   ranges = [];
26325   geoStream(feature, boundsStream);
26326
26327   // First, sort ranges by their minimum longitudes.
26328   if (n = ranges.length) {
26329     ranges.sort(rangeCompare);
26330
26331     // Then, merge any ranges that overlap.
26332     for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
26333       b = ranges[i];
26334       if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
26335         if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
26336         if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
26337       } else {
26338         merged.push(a = b);
26339       }
26340     }
26341
26342     // Finally, find the largest gap between the merged ranges.
26343     // The final bounding box will be the inverse of this gap.
26344     for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
26345       b = merged[i];
26346       if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
26347     }
26348   }
26349
26350   ranges = range = null;
26351
26352   return lambda0$1 === Infinity || phi0 === Infinity
26353       ? [[NaN, NaN], [NaN, NaN]]
26354       : [[lambda0$1, phi0], [lambda1, phi1]];
26355 };
26356
26357 var W0;
26358 var W1;
26359 var X0;
26360 var Y0;
26361 var Z0;
26362 var X1;
26363 var Y1;
26364 var Z1;
26365 var X2;
26366 var Y2;
26367 var Z2;
26368 var lambda00$2;
26369 var phi00$2;
26370 var x0;
26371 var y0;
26372 var z0; // previous point
26373
26374 var centroidStream = {
26375   sphere: noop$1,
26376   point: centroidPoint,
26377   lineStart: centroidLineStart,
26378   lineEnd: centroidLineEnd,
26379   polygonStart: function() {
26380     centroidStream.lineStart = centroidRingStart;
26381     centroidStream.lineEnd = centroidRingEnd;
26382   },
26383   polygonEnd: function() {
26384     centroidStream.lineStart = centroidLineStart;
26385     centroidStream.lineEnd = centroidLineEnd;
26386   }
26387 };
26388
26389 // Arithmetic mean of Cartesian vectors.
26390 function centroidPoint(lambda, phi) {
26391   lambda *= radians, phi *= radians;
26392   var cosPhi = cos$1(phi);
26393   centroidPointCartesian(cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi));
26394 }
26395
26396 function centroidPointCartesian(x, y, z) {
26397   ++W0;
26398   X0 += (x - X0) / W0;
26399   Y0 += (y - Y0) / W0;
26400   Z0 += (z - Z0) / W0;
26401 }
26402
26403 function centroidLineStart() {
26404   centroidStream.point = centroidLinePointFirst;
26405 }
26406
26407 function centroidLinePointFirst(lambda, phi) {
26408   lambda *= radians, phi *= radians;
26409   var cosPhi = cos$1(phi);
26410   x0 = cosPhi * cos$1(lambda);
26411   y0 = cosPhi * sin$1(lambda);
26412   z0 = sin$1(phi);
26413   centroidStream.point = centroidLinePoint;
26414   centroidPointCartesian(x0, y0, z0);
26415 }
26416
26417 function centroidLinePoint(lambda, phi) {
26418   lambda *= radians, phi *= radians;
26419   var cosPhi = cos$1(phi),
26420       x = cosPhi * cos$1(lambda),
26421       y = cosPhi * sin$1(lambda),
26422       z = sin$1(phi),
26423       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);
26424   W1 += w;
26425   X1 += w * (x0 + (x0 = x));
26426   Y1 += w * (y0 + (y0 = y));
26427   Z1 += w * (z0 + (z0 = z));
26428   centroidPointCartesian(x0, y0, z0);
26429 }
26430
26431 function centroidLineEnd() {
26432   centroidStream.point = centroidPoint;
26433 }
26434
26435 // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
26436 // J. Applied Mechanics 42, 239 (1975).
26437 function centroidRingStart() {
26438   centroidStream.point = centroidRingPointFirst;
26439 }
26440
26441 function centroidRingEnd() {
26442   centroidRingPoint(lambda00$2, phi00$2);
26443   centroidStream.point = centroidPoint;
26444 }
26445
26446 function centroidRingPointFirst(lambda, phi) {
26447   lambda00$2 = lambda, phi00$2 = phi;
26448   lambda *= radians, phi *= radians;
26449   centroidStream.point = centroidRingPoint;
26450   var cosPhi = cos$1(phi);
26451   x0 = cosPhi * cos$1(lambda);
26452   y0 = cosPhi * sin$1(lambda);
26453   z0 = sin$1(phi);
26454   centroidPointCartesian(x0, y0, z0);
26455 }
26456
26457 function centroidRingPoint(lambda, phi) {
26458   lambda *= radians, phi *= radians;
26459   var cosPhi = cos$1(phi),
26460       x = cosPhi * cos$1(lambda),
26461       y = cosPhi * sin$1(lambda),
26462       z = sin$1(phi),
26463       cx = y0 * z - z0 * y,
26464       cy = z0 * x - x0 * z,
26465       cz = x0 * y - y0 * x,
26466       m = sqrt(cx * cx + cy * cy + cz * cz),
26467       w = asin(m), // line weight = angle
26468       v = m && -w / m; // area weight multiplier
26469   X2 += v * cx;
26470   Y2 += v * cy;
26471   Z2 += v * cz;
26472   W1 += w;
26473   X1 += w * (x0 + (x0 = x));
26474   Y1 += w * (y0 + (y0 = y));
26475   Z1 += w * (z0 + (z0 = z));
26476   centroidPointCartesian(x0, y0, z0);
26477 }
26478
26479 var d3GeoCentroid = function(object) {
26480   W0 = W1 =
26481   X0 = Y0 = Z0 =
26482   X1 = Y1 = Z1 =
26483   X2 = Y2 = Z2 = 0;
26484   geoStream(object, centroidStream);
26485
26486   var x = X2,
26487       y = Y2,
26488       z = Z2,
26489       m = x * x + y * y + z * z;
26490
26491   // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
26492   if (m < epsilon2$1) {
26493     x = X1, y = Y1, z = Z1;
26494     // If the feature has zero length, fall back to arithmetic mean of point vectors.
26495     if (W1 < epsilon$2) x = X0, y = Y0, z = Z0;
26496     m = x * x + y * y + z * z;
26497     // If the feature still has an undefined ccentroid, then return.
26498     if (m < epsilon2$1) return [NaN, NaN];
26499   }
26500
26501   return [atan2(y, x) * degrees$1, asin(z / sqrt(m)) * degrees$1];
26502 };
26503
26504 var constant$7 = function(x) {
26505   return function() {
26506     return x;
26507   };
26508 };
26509
26510 var compose = function(a, b) {
26511
26512   function compose(x, y) {
26513     return x = a(x, y), b(x[0], x[1]);
26514   }
26515
26516   if (a.invert && b.invert) compose.invert = function(x, y) {
26517     return x = b.invert(x, y), x && a.invert(x[0], x[1]);
26518   };
26519
26520   return compose;
26521 };
26522
26523 function rotationIdentity(lambda, phi) {
26524   return [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26525 }
26526
26527 rotationIdentity.invert = rotationIdentity;
26528
26529 function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
26530   return (deltaLambda %= tau$3) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
26531     : rotationLambda(deltaLambda))
26532     : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
26533     : rotationIdentity);
26534 }
26535
26536 function forwardRotationLambda(deltaLambda) {
26537   return function(lambda, phi) {
26538     return lambda += deltaLambda, [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26539   };
26540 }
26541
26542 function rotationLambda(deltaLambda) {
26543   var rotation = forwardRotationLambda(deltaLambda);
26544   rotation.invert = forwardRotationLambda(-deltaLambda);
26545   return rotation;
26546 }
26547
26548 function rotationPhiGamma(deltaPhi, deltaGamma) {
26549   var cosDeltaPhi = cos$1(deltaPhi),
26550       sinDeltaPhi = sin$1(deltaPhi),
26551       cosDeltaGamma = cos$1(deltaGamma),
26552       sinDeltaGamma = sin$1(deltaGamma);
26553
26554   function rotation(lambda, phi) {
26555     var cosPhi = cos$1(phi),
26556         x = cos$1(lambda) * cosPhi,
26557         y = sin$1(lambda) * cosPhi,
26558         z = sin$1(phi),
26559         k = z * cosDeltaPhi + x * sinDeltaPhi;
26560     return [
26561       atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
26562       asin(k * cosDeltaGamma + y * sinDeltaGamma)
26563     ];
26564   }
26565
26566   rotation.invert = function(lambda, phi) {
26567     var cosPhi = cos$1(phi),
26568         x = cos$1(lambda) * cosPhi,
26569         y = sin$1(lambda) * cosPhi,
26570         z = sin$1(phi),
26571         k = z * cosDeltaGamma - y * sinDeltaGamma;
26572     return [
26573       atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
26574       asin(k * cosDeltaPhi - x * sinDeltaPhi)
26575     ];
26576   };
26577
26578   return rotation;
26579 }
26580
26581 var rotation = function(rotate) {
26582   rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
26583
26584   function forward(coordinates) {
26585     coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
26586     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26587   }
26588
26589   forward.invert = function(coordinates) {
26590     coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
26591     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26592   };
26593
26594   return forward;
26595 };
26596
26597 // Generates a circle centered at [0°, 0°], with a given radius and precision.
26598 function circleStream(stream, radius, delta, direction, t0, t1) {
26599   if (!delta) return;
26600   var cosRadius = cos$1(radius),
26601       sinRadius = sin$1(radius),
26602       step = direction * delta;
26603   if (t0 == null) {
26604     t0 = radius + direction * tau$3;
26605     t1 = radius - step / 2;
26606   } else {
26607     t0 = circleRadius(cosRadius, t0);
26608     t1 = circleRadius(cosRadius, t1);
26609     if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$3;
26610   }
26611   for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
26612     point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(t)]);
26613     stream.point(point[0], point[1]);
26614   }
26615 }
26616
26617 // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
26618 function circleRadius(cosRadius, point) {
26619   point = cartesian(point), point[0] -= cosRadius;
26620   cartesianNormalizeInPlace(point);
26621   var radius = acos(-point[1]);
26622   return ((-point[2] < 0 ? -radius : radius) + tau$3 - epsilon$2) % tau$3;
26623 }
26624
26625 var circle = function() {
26626   var center = constant$7([0, 0]),
26627       radius = constant$7(90),
26628       precision = constant$7(6),
26629       ring,
26630       rotate,
26631       stream = {point: point};
26632
26633   function point(x, y) {
26634     ring.push(x = rotate(x, y));
26635     x[0] *= degrees$1, x[1] *= degrees$1;
26636   }
26637
26638   function circle() {
26639     var c = center.apply(this, arguments),
26640         r = radius.apply(this, arguments) * radians,
26641         p = precision.apply(this, arguments) * radians;
26642     ring = [];
26643     rotate = rotateRadians(-c[0] * radians, -c[1] * radians, 0).invert;
26644     circleStream(stream, r, p, 1);
26645     c = {type: "Polygon", coordinates: [ring]};
26646     ring = rotate = null;
26647     return c;
26648   }
26649
26650   circle.center = function(_) {
26651     return arguments.length ? (center = typeof _ === "function" ? _ : constant$7([+_[0], +_[1]]), circle) : center;
26652   };
26653
26654   circle.radius = function(_) {
26655     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$7(+_), circle) : radius;
26656   };
26657
26658   circle.precision = function(_) {
26659     return arguments.length ? (precision = typeof _ === "function" ? _ : constant$7(+_), circle) : precision;
26660   };
26661
26662   return circle;
26663 };
26664
26665 var clipBuffer = function() {
26666   var lines = [],
26667       line;
26668   return {
26669     point: function(x, y) {
26670       line.push([x, y]);
26671     },
26672     lineStart: function() {
26673       lines.push(line = []);
26674     },
26675     lineEnd: noop$1,
26676     rejoin: function() {
26677       if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
26678     },
26679     result: function() {
26680       var result = lines;
26681       lines = [];
26682       line = null;
26683       return result;
26684     }
26685   };
26686 };
26687
26688 var clipLine = function(a, b, x0, y0, x1, y1) {
26689   var ax = a[0],
26690       ay = a[1],
26691       bx = b[0],
26692       by = b[1],
26693       t0 = 0,
26694       t1 = 1,
26695       dx = bx - ax,
26696       dy = by - ay,
26697       r;
26698
26699   r = x0 - ax;
26700   if (!dx && r > 0) return;
26701   r /= dx;
26702   if (dx < 0) {
26703     if (r < t0) return;
26704     if (r < t1) t1 = r;
26705   } else if (dx > 0) {
26706     if (r > t1) return;
26707     if (r > t0) t0 = r;
26708   }
26709
26710   r = x1 - ax;
26711   if (!dx && r < 0) return;
26712   r /= dx;
26713   if (dx < 0) {
26714     if (r > t1) return;
26715     if (r > t0) t0 = r;
26716   } else if (dx > 0) {
26717     if (r < t0) return;
26718     if (r < t1) t1 = r;
26719   }
26720
26721   r = y0 - ay;
26722   if (!dy && r > 0) return;
26723   r /= dy;
26724   if (dy < 0) {
26725     if (r < t0) return;
26726     if (r < t1) t1 = r;
26727   } else if (dy > 0) {
26728     if (r > t1) return;
26729     if (r > t0) t0 = r;
26730   }
26731
26732   r = y1 - ay;
26733   if (!dy && r < 0) return;
26734   r /= dy;
26735   if (dy < 0) {
26736     if (r > t1) return;
26737     if (r > t0) t0 = r;
26738   } else if (dy > 0) {
26739     if (r < t0) return;
26740     if (r < t1) t1 = r;
26741   }
26742
26743   if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
26744   if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
26745   return true;
26746 };
26747
26748 var pointEqual = function(a, b) {
26749   return abs(a[0] - b[0]) < epsilon$2 && abs(a[1] - b[1]) < epsilon$2;
26750 };
26751
26752 function Intersection(point, points, other, entry) {
26753   this.x = point;
26754   this.z = points;
26755   this.o = other; // another intersection
26756   this.e = entry; // is an entry?
26757   this.v = false; // visited
26758   this.n = this.p = null; // next & previous
26759 }
26760
26761 // A generalized polygon clipping algorithm: given a polygon that has been cut
26762 // into its visible line segments, and rejoins the segments by interpolating
26763 // along the clip edge.
26764 var clipPolygon = function(segments, compareIntersection, startInside, interpolate, stream) {
26765   var subject = [],
26766       clip = [],
26767       i,
26768       n;
26769
26770   segments.forEach(function(segment) {
26771     if ((n = segment.length - 1) <= 0) return;
26772     var n, p0 = segment[0], p1 = segment[n], x;
26773
26774     // If the first and last points of a segment are coincident, then treat as a
26775     // closed ring. TODO if all rings are closed, then the winding order of the
26776     // exterior ring should be checked.
26777     if (pointEqual(p0, p1)) {
26778       stream.lineStart();
26779       for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
26780       stream.lineEnd();
26781       return;
26782     }
26783
26784     subject.push(x = new Intersection(p0, segment, null, true));
26785     clip.push(x.o = new Intersection(p0, null, x, false));
26786     subject.push(x = new Intersection(p1, segment, null, false));
26787     clip.push(x.o = new Intersection(p1, null, x, true));
26788   });
26789
26790   if (!subject.length) return;
26791
26792   clip.sort(compareIntersection);
26793   link$1(subject);
26794   link$1(clip);
26795
26796   for (i = 0, n = clip.length; i < n; ++i) {
26797     clip[i].e = startInside = !startInside;
26798   }
26799
26800   var start = subject[0],
26801       points,
26802       point;
26803
26804   while (1) {
26805     // Find first unvisited intersection.
26806     var current = start,
26807         isSubject = true;
26808     while (current.v) if ((current = current.n) === start) return;
26809     points = current.z;
26810     stream.lineStart();
26811     do {
26812       current.v = current.o.v = true;
26813       if (current.e) {
26814         if (isSubject) {
26815           for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]);
26816         } else {
26817           interpolate(current.x, current.n.x, 1, stream);
26818         }
26819         current = current.n;
26820       } else {
26821         if (isSubject) {
26822           points = current.p.z;
26823           for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]);
26824         } else {
26825           interpolate(current.x, current.p.x, -1, stream);
26826         }
26827         current = current.p;
26828       }
26829       current = current.o;
26830       points = current.z;
26831       isSubject = !isSubject;
26832     } while (!current.v);
26833     stream.lineEnd();
26834   }
26835 };
26836
26837 function link$1(array) {
26838   if (!(n = array.length)) return;
26839   var n,
26840       i = 0,
26841       a = array[0],
26842       b;
26843   while (++i < n) {
26844     a.n = b = array[i];
26845     b.p = a;
26846     a = b;
26847   }
26848   a.n = b = array[0];
26849   b.p = a;
26850 }
26851
26852 var clipMax = 1e9;
26853 var clipMin = -clipMax;
26854
26855 // TODO Use d3-polygon’s polygonContains here for the ring check?
26856 // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
26857
26858 function clipExtent(x0, y0, x1, y1) {
26859
26860   function visible(x, y) {
26861     return x0 <= x && x <= x1 && y0 <= y && y <= y1;
26862   }
26863
26864   function interpolate(from, to, direction, stream) {
26865     var a = 0, a1 = 0;
26866     if (from == null
26867         || (a = corner(from, direction)) !== (a1 = corner(to, direction))
26868         || comparePoint(from, to) < 0 ^ direction > 0) {
26869       do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
26870       while ((a = (a + direction + 4) % 4) !== a1);
26871     } else {
26872       stream.point(to[0], to[1]);
26873     }
26874   }
26875
26876   function corner(p, direction) {
26877     return abs(p[0] - x0) < epsilon$2 ? direction > 0 ? 0 : 3
26878         : abs(p[0] - x1) < epsilon$2 ? direction > 0 ? 2 : 1
26879         : abs(p[1] - y0) < epsilon$2 ? direction > 0 ? 1 : 0
26880         : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
26881   }
26882
26883   function compareIntersection(a, b) {
26884     return comparePoint(a.x, b.x);
26885   }
26886
26887   function comparePoint(a, b) {
26888     var ca = corner(a, 1),
26889         cb = corner(b, 1);
26890     return ca !== cb ? ca - cb
26891         : ca === 0 ? b[1] - a[1]
26892         : ca === 1 ? a[0] - b[0]
26893         : ca === 2 ? a[1] - b[1]
26894         : b[0] - a[0];
26895   }
26896
26897   return function(stream) {
26898     var activeStream = stream,
26899         bufferStream = clipBuffer(),
26900         segments,
26901         polygon,
26902         ring,
26903         x__, y__, v__, // first point
26904         x_, y_, v_, // previous point
26905         first,
26906         clean;
26907
26908     var clipStream = {
26909       point: point,
26910       lineStart: lineStart,
26911       lineEnd: lineEnd,
26912       polygonStart: polygonStart,
26913       polygonEnd: polygonEnd
26914     };
26915
26916     function point(x, y) {
26917       if (visible(x, y)) activeStream.point(x, y);
26918     }
26919
26920     function polygonInside() {
26921       var winding = 0;
26922
26923       for (var i = 0, n = polygon.length; i < n; ++i) {
26924         for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
26925           a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
26926           if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
26927           else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
26928         }
26929       }
26930
26931       return winding;
26932     }
26933
26934     // Buffer geometry within a polygon and then clip it en masse.
26935     function polygonStart() {
26936       activeStream = bufferStream, segments = [], polygon = [], clean = true;
26937     }
26938
26939     function polygonEnd() {
26940       var startInside = polygonInside(),
26941           cleanInside = clean && startInside,
26942           visible = (segments = merge(segments)).length;
26943       if (cleanInside || visible) {
26944         stream.polygonStart();
26945         if (cleanInside) {
26946           stream.lineStart();
26947           interpolate(null, null, 1, stream);
26948           stream.lineEnd();
26949         }
26950         if (visible) {
26951           clipPolygon(segments, compareIntersection, startInside, interpolate, stream);
26952         }
26953         stream.polygonEnd();
26954       }
26955       activeStream = stream, segments = polygon = ring = null;
26956     }
26957
26958     function lineStart() {
26959       clipStream.point = linePoint;
26960       if (polygon) polygon.push(ring = []);
26961       first = true;
26962       v_ = false;
26963       x_ = y_ = NaN;
26964     }
26965
26966     // TODO rather than special-case polygons, simply handle them separately.
26967     // Ideally, coincident intersection points should be jittered to avoid
26968     // clipping issues.
26969     function lineEnd() {
26970       if (segments) {
26971         linePoint(x__, y__);
26972         if (v__ && v_) bufferStream.rejoin();
26973         segments.push(bufferStream.result());
26974       }
26975       clipStream.point = point;
26976       if (v_) activeStream.lineEnd();
26977     }
26978
26979     function linePoint(x, y) {
26980       var v = visible(x, y);
26981       if (polygon) ring.push([x, y]);
26982       if (first) {
26983         x__ = x, y__ = y, v__ = v;
26984         first = false;
26985         if (v) {
26986           activeStream.lineStart();
26987           activeStream.point(x, y);
26988         }
26989       } else {
26990         if (v && v_) activeStream.point(x, y);
26991         else {
26992           var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
26993               b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
26994           if (clipLine(a, b, x0, y0, x1, y1)) {
26995             if (!v_) {
26996               activeStream.lineStart();
26997               activeStream.point(a[0], a[1]);
26998             }
26999             activeStream.point(b[0], b[1]);
27000             if (!v) activeStream.lineEnd();
27001             clean = false;
27002           } else if (v) {
27003             activeStream.lineStart();
27004             activeStream.point(x, y);
27005             clean = false;
27006           }
27007         }
27008       }
27009       x_ = x, y_ = y, v_ = v;
27010     }
27011
27012     return clipStream;
27013   };
27014 }
27015
27016 var extent$1 = function() {
27017   var x0 = 0,
27018       y0 = 0,
27019       x1 = 960,
27020       y1 = 500,
27021       cache,
27022       cacheStream,
27023       clip;
27024
27025   return clip = {
27026     stream: function(stream) {
27027       return cache && cacheStream === stream ? cache : cache = clipExtent(x0, y0, x1, y1)(cacheStream = stream);
27028     },
27029     extent: function(_) {
27030       return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], cache = cacheStream = null, clip) : [[x0, y0], [x1, y1]];
27031     }
27032   };
27033 };
27034
27035 var sum$1 = adder();
27036
27037 var polygonContains = function(polygon, point) {
27038   var lambda = point[0],
27039       phi = point[1],
27040       normal = [sin$1(lambda), -cos$1(lambda), 0],
27041       angle = 0,
27042       winding = 0;
27043
27044   sum$1.reset();
27045
27046   for (var i = 0, n = polygon.length; i < n; ++i) {
27047     if (!(m = (ring = polygon[i]).length)) continue;
27048     var ring,
27049         m,
27050         point0 = ring[m - 1],
27051         lambda0 = point0[0],
27052         phi0 = point0[1] / 2 + quarterPi,
27053         sinPhi0 = sin$1(phi0),
27054         cosPhi0 = cos$1(phi0);
27055
27056     for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
27057       var point1 = ring[j],
27058           lambda1 = point1[0],
27059           phi1 = point1[1] / 2 + quarterPi,
27060           sinPhi1 = sin$1(phi1),
27061           cosPhi1 = cos$1(phi1),
27062           delta = lambda1 - lambda0,
27063           sign$$1 = delta >= 0 ? 1 : -1,
27064           absDelta = sign$$1 * delta,
27065           antimeridian = absDelta > pi$3,
27066           k = sinPhi0 * sinPhi1;
27067
27068       sum$1.add(atan2(k * sign$$1 * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta)));
27069       angle += antimeridian ? delta + sign$$1 * tau$3 : delta;
27070
27071       // Are the longitudes either side of the point’s meridian (lambda),
27072       // and are the latitudes smaller than the parallel (phi)?
27073       if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
27074         var arc = cartesianCross(cartesian(point0), cartesian(point1));
27075         cartesianNormalizeInPlace(arc);
27076         var intersection = cartesianCross(normal, arc);
27077         cartesianNormalizeInPlace(intersection);
27078         var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
27079         if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
27080           winding += antimeridian ^ delta >= 0 ? 1 : -1;
27081         }
27082       }
27083     }
27084   }
27085
27086   // First, determine whether the South pole is inside or outside:
27087   //
27088   // It is inside if:
27089   // * the polygon winds around it in a clockwise direction.
27090   // * the polygon does not (cumulatively) wind around it, but has a negative
27091   //   (counter-clockwise) area.
27092   //
27093   // Second, count the (signed) number of times a segment crosses a lambda
27094   // from the point to the South pole.  If it is zero, then the point is the
27095   // same side as the South pole.
27096
27097   return (angle < -epsilon$2 || angle < epsilon$2 && sum$1 < -epsilon$2) ^ (winding & 1);
27098 };
27099
27100 var lengthSum = adder();
27101 var lambda0$2;
27102 var sinPhi0$1;
27103 var cosPhi0$1;
27104
27105 var lengthStream = {
27106   sphere: noop$1,
27107   point: noop$1,
27108   lineStart: lengthLineStart,
27109   lineEnd: noop$1,
27110   polygonStart: noop$1,
27111   polygonEnd: noop$1
27112 };
27113
27114 function lengthLineStart() {
27115   lengthStream.point = lengthPointFirst;
27116   lengthStream.lineEnd = lengthLineEnd;
27117 }
27118
27119 function lengthLineEnd() {
27120   lengthStream.point = lengthStream.lineEnd = noop$1;
27121 }
27122
27123 function lengthPointFirst(lambda, phi) {
27124   lambda *= radians, phi *= radians;
27125   lambda0$2 = lambda, sinPhi0$1 = sin$1(phi), cosPhi0$1 = cos$1(phi);
27126   lengthStream.point = lengthPoint;
27127 }
27128
27129 function lengthPoint(lambda, phi) {
27130   lambda *= radians, phi *= radians;
27131   var sinPhi = sin$1(phi),
27132       cosPhi = cos$1(phi),
27133       delta = abs(lambda - lambda0$2),
27134       cosDelta = cos$1(delta),
27135       sinDelta = sin$1(delta),
27136       x = cosPhi * sinDelta,
27137       y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
27138       z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
27139   lengthSum.add(atan2(sqrt(x * x + y * y), z));
27140   lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
27141 }
27142
27143 var d3GeoLength = function(object) {
27144   lengthSum.reset();
27145   geoStream(object, lengthStream);
27146   return +lengthSum;
27147 };
27148
27149 var coordinates = [null, null];
27150 var object$1 = {type: "LineString", coordinates: coordinates};
27151
27152 var distance = function(a, b) {
27153   coordinates[0] = a;
27154   coordinates[1] = b;
27155   return d3GeoLength(object$1);
27156 };
27157
27158 var containsObjectType = {
27159   Feature: function(object, point) {
27160     return containsGeometry(object.geometry, point);
27161   },
27162   FeatureCollection: function(object, point) {
27163     var features = object.features, i = -1, n = features.length;
27164     while (++i < n) if (containsGeometry(features[i].geometry, point)) return true;
27165     return false;
27166   }
27167 };
27168
27169 var containsGeometryType = {
27170   Sphere: function() {
27171     return true;
27172   },
27173   Point: function(object, point) {
27174     return containsPoint(object.coordinates, point);
27175   },
27176   MultiPoint: function(object, point) {
27177     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27178     while (++i < n) if (containsPoint(coordinates[i], point)) return true;
27179     return false;
27180   },
27181   LineString: function(object, point) {
27182     return containsLine(object.coordinates, point);
27183   },
27184   MultiLineString: function(object, point) {
27185     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27186     while (++i < n) if (containsLine(coordinates[i], point)) return true;
27187     return false;
27188   },
27189   Polygon: function(object, point) {
27190     return containsPolygon(object.coordinates, point);
27191   },
27192   MultiPolygon: function(object, point) {
27193     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27194     while (++i < n) if (containsPolygon(coordinates[i], point)) return true;
27195     return false;
27196   },
27197   GeometryCollection: function(object, point) {
27198     var geometries = object.geometries, i = -1, n = geometries.length;
27199     while (++i < n) if (containsGeometry(geometries[i], point)) return true;
27200     return false;
27201   }
27202 };
27203
27204 function containsGeometry(geometry, point) {
27205   return geometry && containsGeometryType.hasOwnProperty(geometry.type)
27206       ? containsGeometryType[geometry.type](geometry, point)
27207       : false;
27208 }
27209
27210 function containsPoint(coordinates, point) {
27211   return distance(coordinates, point) === 0;
27212 }
27213
27214 function containsLine(coordinates, point) {
27215   var ab = distance(coordinates[0], coordinates[1]),
27216       ao = distance(coordinates[0], point),
27217       ob = distance(point, coordinates[1]);
27218   return ao + ob <= ab + epsilon$2;
27219 }
27220
27221 function containsPolygon(coordinates, point) {
27222   return !!polygonContains(coordinates.map(ringRadians), pointRadians(point));
27223 }
27224
27225 function ringRadians(ring) {
27226   return ring = ring.map(pointRadians), ring.pop(), ring;
27227 }
27228
27229 function pointRadians(point) {
27230   return [point[0] * radians, point[1] * radians];
27231 }
27232
27233 var contains = function(object, point) {
27234   return (object && containsObjectType.hasOwnProperty(object.type)
27235       ? containsObjectType[object.type]
27236       : containsGeometry)(object, point);
27237 };
27238
27239 function graticuleX(y0, y1, dy) {
27240   var y = sequence(y0, y1 - epsilon$2, dy).concat(y1);
27241   return function(x) { return y.map(function(y) { return [x, y]; }); };
27242 }
27243
27244 function graticuleY(x0, x1, dx) {
27245   var x = sequence(x0, x1 - epsilon$2, dx).concat(x1);
27246   return function(y) { return x.map(function(x) { return [x, y]; }); };
27247 }
27248
27249 function graticule() {
27250   var x1, x0, X1, X0,
27251       y1, y0, Y1, Y0,
27252       dx = 10, dy = dx, DX = 90, DY = 360,
27253       x, y, X, Y,
27254       precision = 2.5;
27255
27256   function graticule() {
27257     return {type: "MultiLineString", coordinates: lines()};
27258   }
27259
27260   function lines() {
27261     return sequence(ceil(X0 / DX) * DX, X1, DX).map(X)
27262         .concat(sequence(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
27263         .concat(sequence(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs(x % DX) > epsilon$2; }).map(x))
27264         .concat(sequence(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > epsilon$2; }).map(y));
27265   }
27266
27267   graticule.lines = function() {
27268     return lines().map(function(coordinates) { return {type: "LineString", coordinates: coordinates}; });
27269   };
27270
27271   graticule.outline = function() {
27272     return {
27273       type: "Polygon",
27274       coordinates: [
27275         X(X0).concat(
27276         Y(Y1).slice(1),
27277         X(X1).reverse().slice(1),
27278         Y(Y0).reverse().slice(1))
27279       ]
27280     };
27281   };
27282
27283   graticule.extent = function(_) {
27284     if (!arguments.length) return graticule.extentMinor();
27285     return graticule.extentMajor(_).extentMinor(_);
27286   };
27287
27288   graticule.extentMajor = function(_) {
27289     if (!arguments.length) return [[X0, Y0], [X1, Y1]];
27290     X0 = +_[0][0], X1 = +_[1][0];
27291     Y0 = +_[0][1], Y1 = +_[1][1];
27292     if (X0 > X1) _ = X0, X0 = X1, X1 = _;
27293     if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
27294     return graticule.precision(precision);
27295   };
27296
27297   graticule.extentMinor = 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.step = function(_) {
27307     if (!arguments.length) return graticule.stepMinor();
27308     return graticule.stepMajor(_).stepMinor(_);
27309   };
27310
27311   graticule.stepMajor = function(_) {
27312     if (!arguments.length) return [DX, DY];
27313     DX = +_[0], DY = +_[1];
27314     return graticule;
27315   };
27316
27317   graticule.stepMinor = function(_) {
27318     if (!arguments.length) return [dx, dy];
27319     dx = +_[0], dy = +_[1];
27320     return graticule;
27321   };
27322
27323   graticule.precision = function(_) {
27324     if (!arguments.length) return precision;
27325     precision = +_;
27326     x = graticuleX(y0, y1, 90);
27327     y = graticuleY(x0, x1, precision);
27328     X = graticuleX(Y0, Y1, 90);
27329     Y = graticuleY(X0, X1, precision);
27330     return graticule;
27331   };
27332
27333   return graticule
27334       .extentMajor([[-180, -90 + epsilon$2], [180, 90 - epsilon$2]])
27335       .extentMinor([[-180, -80 - epsilon$2], [180, 80 + epsilon$2]]);
27336 }
27337
27338 function graticule10() {
27339   return graticule()();
27340 }
27341
27342 var interpolate$1 = function(a, b) {
27343   var x0 = a[0] * radians,
27344       y0 = a[1] * radians,
27345       x1 = b[0] * radians,
27346       y1 = b[1] * radians,
27347       cy0 = cos$1(y0),
27348       sy0 = sin$1(y0),
27349       cy1 = cos$1(y1),
27350       sy1 = sin$1(y1),
27351       kx0 = cy0 * cos$1(x0),
27352       ky0 = cy0 * sin$1(x0),
27353       kx1 = cy1 * cos$1(x1),
27354       ky1 = cy1 * sin$1(x1),
27355       d = 2 * asin(sqrt(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
27356       k = sin$1(d);
27357
27358   var interpolate = d ? function(t) {
27359     var B = sin$1(t *= d) / k,
27360         A = sin$1(d - t) / k,
27361         x = A * kx0 + B * kx1,
27362         y = A * ky0 + B * ky1,
27363         z = A * sy0 + B * sy1;
27364     return [
27365       atan2(y, x) * degrees$1,
27366       atan2(z, sqrt(x * x + y * y)) * degrees$1
27367     ];
27368   } : function() {
27369     return [x0 * degrees$1, y0 * degrees$1];
27370   };
27371
27372   interpolate.distance = d;
27373
27374   return interpolate;
27375 };
27376
27377 var identity$4 = function(x) {
27378   return x;
27379 };
27380
27381 var areaSum$1 = adder();
27382 var areaRingSum$1 = adder();
27383 var x00;
27384 var y00;
27385 var x0$1;
27386 var y0$1;
27387
27388 var areaStream$1 = {
27389   point: noop$1,
27390   lineStart: noop$1,
27391   lineEnd: noop$1,
27392   polygonStart: function() {
27393     areaStream$1.lineStart = areaRingStart$1;
27394     areaStream$1.lineEnd = areaRingEnd$1;
27395   },
27396   polygonEnd: function() {
27397     areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop$1;
27398     areaSum$1.add(abs(areaRingSum$1));
27399     areaRingSum$1.reset();
27400   },
27401   result: function() {
27402     var area = areaSum$1 / 2;
27403     areaSum$1.reset();
27404     return area;
27405   }
27406 };
27407
27408 function areaRingStart$1() {
27409   areaStream$1.point = areaPointFirst$1;
27410 }
27411
27412 function areaPointFirst$1(x, y) {
27413   areaStream$1.point = areaPoint$1;
27414   x00 = x0$1 = x, y00 = y0$1 = y;
27415 }
27416
27417 function areaPoint$1(x, y) {
27418   areaRingSum$1.add(y0$1 * x - x0$1 * y);
27419   x0$1 = x, y0$1 = y;
27420 }
27421
27422 function areaRingEnd$1() {
27423   areaPoint$1(x00, y00);
27424 }
27425
27426 var x0$2 = Infinity;
27427 var y0$2 = x0$2;
27428 var x1 = -x0$2;
27429 var y1 = x1;
27430
27431 var boundsStream$1 = {
27432   point: boundsPoint$1,
27433   lineStart: noop$1,
27434   lineEnd: noop$1,
27435   polygonStart: noop$1,
27436   polygonEnd: noop$1,
27437   result: function() {
27438     var bounds = [[x0$2, y0$2], [x1, y1]];
27439     x1 = y1 = -(y0$2 = x0$2 = Infinity);
27440     return bounds;
27441   }
27442 };
27443
27444 function boundsPoint$1(x, y) {
27445   if (x < x0$2) x0$2 = x;
27446   if (x > x1) x1 = x;
27447   if (y < y0$2) y0$2 = y;
27448   if (y > y1) y1 = y;
27449 }
27450
27451 // TODO Enforce positive area for exterior, negative area for interior?
27452
27453 var X0$1 = 0;
27454 var Y0$1 = 0;
27455 var Z0$1 = 0;
27456 var X1$1 = 0;
27457 var Y1$1 = 0;
27458 var Z1$1 = 0;
27459 var X2$1 = 0;
27460 var Y2$1 = 0;
27461 var Z2$1 = 0;
27462 var x00$1;
27463 var y00$1;
27464 var x0$3;
27465 var y0$3;
27466
27467 var centroidStream$1 = {
27468   point: centroidPoint$1,
27469   lineStart: centroidLineStart$1,
27470   lineEnd: centroidLineEnd$1,
27471   polygonStart: function() {
27472     centroidStream$1.lineStart = centroidRingStart$1;
27473     centroidStream$1.lineEnd = centroidRingEnd$1;
27474   },
27475   polygonEnd: function() {
27476     centroidStream$1.point = centroidPoint$1;
27477     centroidStream$1.lineStart = centroidLineStart$1;
27478     centroidStream$1.lineEnd = centroidLineEnd$1;
27479   },
27480   result: function() {
27481     var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1]
27482         : Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1]
27483         : Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1]
27484         : [NaN, NaN];
27485     X0$1 = Y0$1 = Z0$1 =
27486     X1$1 = Y1$1 = Z1$1 =
27487     X2$1 = Y2$1 = Z2$1 = 0;
27488     return centroid;
27489   }
27490 };
27491
27492 function centroidPoint$1(x, y) {
27493   X0$1 += x;
27494   Y0$1 += y;
27495   ++Z0$1;
27496 }
27497
27498 function centroidLineStart$1() {
27499   centroidStream$1.point = centroidPointFirstLine;
27500 }
27501
27502 function centroidPointFirstLine(x, y) {
27503   centroidStream$1.point = centroidPointLine;
27504   centroidPoint$1(x0$3 = x, y0$3 = y);
27505 }
27506
27507 function centroidPointLine(x, y) {
27508   var dx = x - x0$3, dy = y - y0$3, z = sqrt(dx * dx + dy * dy);
27509   X1$1 += z * (x0$3 + x) / 2;
27510   Y1$1 += z * (y0$3 + y) / 2;
27511   Z1$1 += z;
27512   centroidPoint$1(x0$3 = x, y0$3 = y);
27513 }
27514
27515 function centroidLineEnd$1() {
27516   centroidStream$1.point = centroidPoint$1;
27517 }
27518
27519 function centroidRingStart$1() {
27520   centroidStream$1.point = centroidPointFirstRing;
27521 }
27522
27523 function centroidRingEnd$1() {
27524   centroidPointRing(x00$1, y00$1);
27525 }
27526
27527 function centroidPointFirstRing(x, y) {
27528   centroidStream$1.point = centroidPointRing;
27529   centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
27530 }
27531
27532 function centroidPointRing(x, y) {
27533   var dx = x - x0$3,
27534       dy = y - y0$3,
27535       z = sqrt(dx * dx + dy * dy);
27536
27537   X1$1 += z * (x0$3 + x) / 2;
27538   Y1$1 += z * (y0$3 + y) / 2;
27539   Z1$1 += z;
27540
27541   z = y0$3 * x - x0$3 * y;
27542   X2$1 += z * (x0$3 + x);
27543   Y2$1 += z * (y0$3 + y);
27544   Z2$1 += z * 3;
27545   centroidPoint$1(x0$3 = x, y0$3 = y);
27546 }
27547
27548 function PathContext(context) {
27549   this._context = context;
27550 }
27551
27552 PathContext.prototype = {
27553   _radius: 4.5,
27554   pointRadius: function(_) {
27555     return this._radius = _, this;
27556   },
27557   polygonStart: function() {
27558     this._line = 0;
27559   },
27560   polygonEnd: function() {
27561     this._line = NaN;
27562   },
27563   lineStart: function() {
27564     this._point = 0;
27565   },
27566   lineEnd: function() {
27567     if (this._line === 0) this._context.closePath();
27568     this._point = NaN;
27569   },
27570   point: function(x, y) {
27571     switch (this._point) {
27572       case 0: {
27573         this._context.moveTo(x, y);
27574         this._point = 1;
27575         break;
27576       }
27577       case 1: {
27578         this._context.lineTo(x, y);
27579         break;
27580       }
27581       default: {
27582         this._context.moveTo(x + this._radius, y);
27583         this._context.arc(x, y, this._radius, 0, tau$3);
27584         break;
27585       }
27586     }
27587   },
27588   result: noop$1
27589 };
27590
27591 var lengthSum$1 = adder();
27592 var lengthRing;
27593 var x00$2;
27594 var y00$2;
27595 var x0$4;
27596 var y0$4;
27597
27598 var lengthStream$1 = {
27599   point: noop$1,
27600   lineStart: function() {
27601     lengthStream$1.point = lengthPointFirst$1;
27602   },
27603   lineEnd: function() {
27604     if (lengthRing) lengthPoint$1(x00$2, y00$2);
27605     lengthStream$1.point = noop$1;
27606   },
27607   polygonStart: function() {
27608     lengthRing = true;
27609   },
27610   polygonEnd: function() {
27611     lengthRing = null;
27612   },
27613   result: function() {
27614     var length = +lengthSum$1;
27615     lengthSum$1.reset();
27616     return length;
27617   }
27618 };
27619
27620 function lengthPointFirst$1(x, y) {
27621   lengthStream$1.point = lengthPoint$1;
27622   x00$2 = x0$4 = x, y00$2 = y0$4 = y;
27623 }
27624
27625 function lengthPoint$1(x, y) {
27626   x0$4 -= x, y0$4 -= y;
27627   lengthSum$1.add(sqrt(x0$4 * x0$4 + y0$4 * y0$4));
27628   x0$4 = x, y0$4 = y;
27629 }
27630
27631 function PathString() {
27632   this._string = [];
27633 }
27634
27635 PathString.prototype = {
27636   _circle: circle$1(4.5),
27637   pointRadius: function(_) {
27638     return this._circle = circle$1(_), this;
27639   },
27640   polygonStart: function() {
27641     this._line = 0;
27642   },
27643   polygonEnd: function() {
27644     this._line = NaN;
27645   },
27646   lineStart: function() {
27647     this._point = 0;
27648   },
27649   lineEnd: function() {
27650     if (this._line === 0) this._string.push("Z");
27651     this._point = NaN;
27652   },
27653   point: function(x, y) {
27654     switch (this._point) {
27655       case 0: {
27656         this._string.push("M", x, ",", y);
27657         this._point = 1;
27658         break;
27659       }
27660       case 1: {
27661         this._string.push("L", x, ",", y);
27662         break;
27663       }
27664       default: {
27665         this._string.push("M", x, ",", y, this._circle);
27666         break;
27667       }
27668     }
27669   },
27670   result: function() {
27671     if (this._string.length) {
27672       var result = this._string.join("");
27673       this._string = [];
27674       return result;
27675     }
27676   }
27677 };
27678
27679 function circle$1(radius) {
27680   return "m0," + radius
27681       + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
27682       + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
27683       + "z";
27684 }
27685
27686 var index$4 = function(projection, context) {
27687   var pointRadius = 4.5,
27688       projectionStream,
27689       contextStream;
27690
27691   function path(object) {
27692     if (object) {
27693       if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
27694       geoStream(object, projectionStream(contextStream));
27695     }
27696     return contextStream.result();
27697   }
27698
27699   path.area = function(object) {
27700     geoStream(object, projectionStream(areaStream$1));
27701     return areaStream$1.result();
27702   };
27703
27704   path.measure = function(object) {
27705     geoStream(object, projectionStream(lengthStream$1));
27706     return lengthStream$1.result();
27707   };
27708
27709   path.bounds = function(object) {
27710     geoStream(object, projectionStream(boundsStream$1));
27711     return boundsStream$1.result();
27712   };
27713
27714   path.centroid = function(object) {
27715     geoStream(object, projectionStream(centroidStream$1));
27716     return centroidStream$1.result();
27717   };
27718
27719   path.projection = function(_) {
27720     return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$4) : (projection = _).stream, path) : projection;
27721   };
27722
27723   path.context = function(_) {
27724     if (!arguments.length) return context;
27725     contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _);
27726     if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
27727     return path;
27728   };
27729
27730   path.pointRadius = function(_) {
27731     if (!arguments.length) return pointRadius;
27732     pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
27733     return path;
27734   };
27735
27736   return path.projection(projection).context(context);
27737 };
27738
27739 var clip = function(pointVisible, clipLine, interpolate, start) {
27740   return function(rotate, sink) {
27741     var line = clipLine(sink),
27742         rotatedStart = rotate.invert(start[0], start[1]),
27743         ringBuffer = clipBuffer(),
27744         ringSink = clipLine(ringBuffer),
27745         polygonStarted = false,
27746         polygon,
27747         segments,
27748         ring;
27749
27750     var clip = {
27751       point: point,
27752       lineStart: lineStart,
27753       lineEnd: lineEnd,
27754       polygonStart: function() {
27755         clip.point = pointRing;
27756         clip.lineStart = ringStart;
27757         clip.lineEnd = ringEnd;
27758         segments = [];
27759         polygon = [];
27760       },
27761       polygonEnd: function() {
27762         clip.point = point;
27763         clip.lineStart = lineStart;
27764         clip.lineEnd = lineEnd;
27765         segments = merge(segments);
27766         var startInside = polygonContains(polygon, rotatedStart);
27767         if (segments.length) {
27768           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27769           clipPolygon(segments, compareIntersection, startInside, interpolate, sink);
27770         } else if (startInside) {
27771           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27772           sink.lineStart();
27773           interpolate(null, null, 1, sink);
27774           sink.lineEnd();
27775         }
27776         if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
27777         segments = polygon = null;
27778       },
27779       sphere: function() {
27780         sink.polygonStart();
27781         sink.lineStart();
27782         interpolate(null, null, 1, sink);
27783         sink.lineEnd();
27784         sink.polygonEnd();
27785       }
27786     };
27787
27788     function point(lambda, phi) {
27789       var point = rotate(lambda, phi);
27790       if (pointVisible(lambda = point[0], phi = point[1])) sink.point(lambda, phi);
27791     }
27792
27793     function pointLine(lambda, phi) {
27794       var point = rotate(lambda, phi);
27795       line.point(point[0], point[1]);
27796     }
27797
27798     function lineStart() {
27799       clip.point = pointLine;
27800       line.lineStart();
27801     }
27802
27803     function lineEnd() {
27804       clip.point = point;
27805       line.lineEnd();
27806     }
27807
27808     function pointRing(lambda, phi) {
27809       ring.push([lambda, phi]);
27810       var point = rotate(lambda, phi);
27811       ringSink.point(point[0], point[1]);
27812     }
27813
27814     function ringStart() {
27815       ringSink.lineStart();
27816       ring = [];
27817     }
27818
27819     function ringEnd() {
27820       pointRing(ring[0][0], ring[0][1]);
27821       ringSink.lineEnd();
27822
27823       var clean = ringSink.clean(),
27824           ringSegments = ringBuffer.result(),
27825           i, n = ringSegments.length, m,
27826           segment,
27827           point;
27828
27829       ring.pop();
27830       polygon.push(ring);
27831       ring = null;
27832
27833       if (!n) return;
27834
27835       // No intersections.
27836       if (clean & 1) {
27837         segment = ringSegments[0];
27838         if ((m = segment.length - 1) > 0) {
27839           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27840           sink.lineStart();
27841           for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]);
27842           sink.lineEnd();
27843         }
27844         return;
27845       }
27846
27847       // Rejoin connected segments.
27848       // TODO reuse ringBuffer.rejoin()?
27849       if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
27850
27851       segments.push(ringSegments.filter(validSegment));
27852     }
27853
27854     return clip;
27855   };
27856 };
27857
27858 function validSegment(segment) {
27859   return segment.length > 1;
27860 }
27861
27862 // Intersections are sorted along the clip edge. For both antimeridian cutting
27863 // and circle clipping, the same comparison is used.
27864 function compareIntersection(a, b) {
27865   return ((a = a.x)[0] < 0 ? a[1] - halfPi$2 - epsilon$2 : halfPi$2 - a[1])
27866        - ((b = b.x)[0] < 0 ? b[1] - halfPi$2 - epsilon$2 : halfPi$2 - b[1]);
27867 }
27868
27869 var clipAntimeridian = clip(
27870   function() { return true; },
27871   clipAntimeridianLine,
27872   clipAntimeridianInterpolate,
27873   [-pi$3, -halfPi$2]
27874 );
27875
27876 // Takes a line and cuts into visible segments. Return values: 0 - there were
27877 // intersections or the line was empty; 1 - no intersections; 2 - there were
27878 // intersections, and the first and last segments should be rejoined.
27879 function clipAntimeridianLine(stream) {
27880   var lambda0 = NaN,
27881       phi0 = NaN,
27882       sign0 = NaN,
27883       clean; // no intersections
27884
27885   return {
27886     lineStart: function() {
27887       stream.lineStart();
27888       clean = 1;
27889     },
27890     point: function(lambda1, phi1) {
27891       var sign1 = lambda1 > 0 ? pi$3 : -pi$3,
27892           delta = abs(lambda1 - lambda0);
27893       if (abs(delta - pi$3) < epsilon$2) { // line crosses a pole
27894         stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$2 : -halfPi$2);
27895         stream.point(sign0, phi0);
27896         stream.lineEnd();
27897         stream.lineStart();
27898         stream.point(sign1, phi0);
27899         stream.point(lambda1, phi0);
27900         clean = 0;
27901       } else if (sign0 !== sign1 && delta >= pi$3) { // line crosses antimeridian
27902         if (abs(lambda0 - sign0) < epsilon$2) lambda0 -= sign0 * epsilon$2; // handle degeneracies
27903         if (abs(lambda1 - sign1) < epsilon$2) lambda1 -= sign1 * epsilon$2;
27904         phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
27905         stream.point(sign0, phi0);
27906         stream.lineEnd();
27907         stream.lineStart();
27908         stream.point(sign1, phi0);
27909         clean = 0;
27910       }
27911       stream.point(lambda0 = lambda1, phi0 = phi1);
27912       sign0 = sign1;
27913     },
27914     lineEnd: function() {
27915       stream.lineEnd();
27916       lambda0 = phi0 = NaN;
27917     },
27918     clean: function() {
27919       return 2 - clean; // if intersections, rejoin first and last segments
27920     }
27921   };
27922 }
27923
27924 function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
27925   var cosPhi0,
27926       cosPhi1,
27927       sinLambda0Lambda1 = sin$1(lambda0 - lambda1);
27928   return abs(sinLambda0Lambda1) > epsilon$2
27929       ? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1)
27930           - sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0))
27931           / (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
27932       : (phi0 + phi1) / 2;
27933 }
27934
27935 function clipAntimeridianInterpolate(from, to, direction, stream) {
27936   var phi;
27937   if (from == null) {
27938     phi = direction * halfPi$2;
27939     stream.point(-pi$3, phi);
27940     stream.point(0, phi);
27941     stream.point(pi$3, phi);
27942     stream.point(pi$3, 0);
27943     stream.point(pi$3, -phi);
27944     stream.point(0, -phi);
27945     stream.point(-pi$3, -phi);
27946     stream.point(-pi$3, 0);
27947     stream.point(-pi$3, phi);
27948   } else if (abs(from[0] - to[0]) > epsilon$2) {
27949     var lambda = from[0] < to[0] ? pi$3 : -pi$3;
27950     phi = direction * lambda / 2;
27951     stream.point(-lambda, phi);
27952     stream.point(0, phi);
27953     stream.point(lambda, phi);
27954   } else {
27955     stream.point(to[0], to[1]);
27956   }
27957 }
27958
27959 var clipCircle = function(radius, delta) {
27960   var cr = cos$1(radius),
27961       smallRadius = cr > 0,
27962       notHemisphere = abs(cr) > epsilon$2; // TODO optimise for this common case
27963
27964   function interpolate(from, to, direction, stream) {
27965     circleStream(stream, radius, delta, direction, from, to);
27966   }
27967
27968   function visible(lambda, phi) {
27969     return cos$1(lambda) * cos$1(phi) > cr;
27970   }
27971
27972   // Takes a line and cuts into visible segments. Return values used for polygon
27973   // clipping: 0 - there were intersections or the line was empty; 1 - no
27974   // intersections 2 - there were intersections, and the first and last segments
27975   // should be rejoined.
27976   function clipLine(stream) {
27977     var point0, // previous point
27978         c0, // code for previous point
27979         v0, // visibility of previous point
27980         v00, // visibility of first point
27981         clean; // no intersections
27982     return {
27983       lineStart: function() {
27984         v00 = v0 = false;
27985         clean = 1;
27986       },
27987       point: function(lambda, phi) {
27988         var point1 = [lambda, phi],
27989             point2,
27990             v = visible(lambda, phi),
27991             c = smallRadius
27992               ? v ? 0 : code(lambda, phi)
27993               : v ? code(lambda + (lambda < 0 ? pi$3 : -pi$3), phi) : 0;
27994         if (!point0 && (v00 = v0 = v)) stream.lineStart();
27995         // Handle degeneracies.
27996         // TODO ignore if not clipping polygons.
27997         if (v !== v0) {
27998           point2 = intersect(point0, point1);
27999           if (pointEqual(point0, point2) || pointEqual(point1, point2)) {
28000             point1[0] += epsilon$2;
28001             point1[1] += epsilon$2;
28002             v = visible(point1[0], point1[1]);
28003           }
28004         }
28005         if (v !== v0) {
28006           clean = 0;
28007           if (v) {
28008             // outside going in
28009             stream.lineStart();
28010             point2 = intersect(point1, point0);
28011             stream.point(point2[0], point2[1]);
28012           } else {
28013             // inside going out
28014             point2 = intersect(point0, point1);
28015             stream.point(point2[0], point2[1]);
28016             stream.lineEnd();
28017           }
28018           point0 = point2;
28019         } else if (notHemisphere && point0 && smallRadius ^ v) {
28020           var t;
28021           // If the codes for two points are different, or are both zero,
28022           // and there this segment intersects with the small circle.
28023           if (!(c & c0) && (t = intersect(point1, point0, true))) {
28024             clean = 0;
28025             if (smallRadius) {
28026               stream.lineStart();
28027               stream.point(t[0][0], t[0][1]);
28028               stream.point(t[1][0], t[1][1]);
28029               stream.lineEnd();
28030             } else {
28031               stream.point(t[1][0], t[1][1]);
28032               stream.lineEnd();
28033               stream.lineStart();
28034               stream.point(t[0][0], t[0][1]);
28035             }
28036           }
28037         }
28038         if (v && (!point0 || !pointEqual(point0, point1))) {
28039           stream.point(point1[0], point1[1]);
28040         }
28041         point0 = point1, v0 = v, c0 = c;
28042       },
28043       lineEnd: function() {
28044         if (v0) stream.lineEnd();
28045         point0 = null;
28046       },
28047       // Rejoin first and last segments if there were intersections and the first
28048       // and last points were visible.
28049       clean: function() {
28050         return clean | ((v00 && v0) << 1);
28051       }
28052     };
28053   }
28054
28055   // Intersects the great circle between a and b with the clip circle.
28056   function intersect(a, b, two) {
28057     var pa = cartesian(a),
28058         pb = cartesian(b);
28059
28060     // We have two planes, n1.p = d1 and n2.p = d2.
28061     // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
28062     var n1 = [1, 0, 0], // normal
28063         n2 = cartesianCross(pa, pb),
28064         n2n2 = cartesianDot(n2, n2),
28065         n1n2 = n2[0], // cartesianDot(n1, n2),
28066         determinant = n2n2 - n1n2 * n1n2;
28067
28068     // Two polar points.
28069     if (!determinant) return !two && a;
28070
28071     var c1 =  cr * n2n2 / determinant,
28072         c2 = -cr * n1n2 / determinant,
28073         n1xn2 = cartesianCross(n1, n2),
28074         A = cartesianScale(n1, c1),
28075         B = cartesianScale(n2, c2);
28076     cartesianAddInPlace(A, B);
28077
28078     // Solve |p(t)|^2 = 1.
28079     var u = n1xn2,
28080         w = cartesianDot(A, u),
28081         uu = cartesianDot(u, u),
28082         t2 = w * w - uu * (cartesianDot(A, A) - 1);
28083
28084     if (t2 < 0) return;
28085
28086     var t = sqrt(t2),
28087         q = cartesianScale(u, (-w - t) / uu);
28088     cartesianAddInPlace(q, A);
28089     q = spherical(q);
28090
28091     if (!two) return q;
28092
28093     // Two intersection points.
28094     var lambda0 = a[0],
28095         lambda1 = b[0],
28096         phi0 = a[1],
28097         phi1 = b[1],
28098         z;
28099
28100     if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
28101
28102     var delta = lambda1 - lambda0,
28103         polar = abs(delta - pi$3) < epsilon$2,
28104         meridian = polar || delta < epsilon$2;
28105
28106     if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
28107
28108     // Check that the first point is between a and b.
28109     if (meridian
28110         ? polar
28111           ? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon$2 ? phi0 : phi1)
28112           : phi0 <= q[1] && q[1] <= phi1
28113         : delta > pi$3 ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
28114       var q1 = cartesianScale(u, (-w + t) / uu);
28115       cartesianAddInPlace(q1, A);
28116       return [q, spherical(q1)];
28117     }
28118   }
28119
28120   // Generates a 4-bit vector representing the location of a point relative to
28121   // the small circle's bounding box.
28122   function code(lambda, phi) {
28123     var r = smallRadius ? radius : pi$3 - radius,
28124         code = 0;
28125     if (lambda < -r) code |= 1; // left
28126     else if (lambda > r) code |= 2; // right
28127     if (phi < -r) code |= 4; // below
28128     else if (phi > r) code |= 8; // above
28129     return code;
28130   }
28131
28132   return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$3, radius - pi$3]);
28133 };
28134
28135 var transform = function(methods) {
28136   return {
28137     stream: transformer(methods)
28138   };
28139 };
28140
28141 function transformer(methods) {
28142   return function(stream) {
28143     var s = new TransformStream;
28144     for (var key in methods) s[key] = methods[key];
28145     s.stream = stream;
28146     return s;
28147   };
28148 }
28149
28150 function TransformStream() {}
28151
28152 TransformStream.prototype = {
28153   constructor: TransformStream,
28154   point: function(x, y) { this.stream.point(x, y); },
28155   sphere: function() { this.stream.sphere(); },
28156   lineStart: function() { this.stream.lineStart(); },
28157   lineEnd: function() { this.stream.lineEnd(); },
28158   polygonStart: function() { this.stream.polygonStart(); },
28159   polygonEnd: function() { this.stream.polygonEnd(); }
28160 };
28161
28162 function fitExtent(projection, extent, object) {
28163   var w = extent[1][0] - extent[0][0],
28164       h = extent[1][1] - extent[0][1],
28165       clip = projection.clipExtent && projection.clipExtent();
28166
28167   projection
28168       .scale(150)
28169       .translate([0, 0]);
28170
28171   if (clip != null) projection.clipExtent(null);
28172
28173   geoStream(object, projection.stream(boundsStream$1));
28174
28175   var b = boundsStream$1.result(),
28176       k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
28177       x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
28178       y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
28179
28180   if (clip != null) projection.clipExtent(clip);
28181
28182   return projection
28183       .scale(k * 150)
28184       .translate([x, y]);
28185 }
28186
28187 function fitSize(projection, size, object) {
28188   return fitExtent(projection, [[0, 0], size], object);
28189 }
28190
28191 var maxDepth = 16;
28192 var cosMinDistance = cos$1(30 * radians); // cos(minimum angular distance)
28193
28194 var resample = function(project, delta2) {
28195   return +delta2 ? resample$1(project, delta2) : resampleNone(project);
28196 };
28197
28198 function resampleNone(project) {
28199   return transformer({
28200     point: function(x, y) {
28201       x = project(x, y);
28202       this.stream.point(x[0], x[1]);
28203     }
28204   });
28205 }
28206
28207 function resample$1(project, delta2) {
28208
28209   function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
28210     var dx = x1 - x0,
28211         dy = y1 - y0,
28212         d2 = dx * dx + dy * dy;
28213     if (d2 > 4 * delta2 && depth--) {
28214       var a = a0 + a1,
28215           b = b0 + b1,
28216           c = c0 + c1,
28217           m = sqrt(a * a + b * b + c * c),
28218           phi2 = asin(c /= m),
28219           lambda2 = abs(abs(c) - 1) < epsilon$2 || abs(lambda0 - lambda1) < epsilon$2 ? (lambda0 + lambda1) / 2 : atan2(b, a),
28220           p = project(lambda2, phi2),
28221           x2 = p[0],
28222           y2 = p[1],
28223           dx2 = x2 - x0,
28224           dy2 = y2 - y0,
28225           dz = dy * dx2 - dx * dy2;
28226       if (dz * dz / d2 > delta2 // perpendicular projected distance
28227           || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
28228           || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
28229         resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
28230         stream.point(x2, y2);
28231         resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
28232       }
28233     }
28234   }
28235   return function(stream) {
28236     var lambda00, x00, y00, a00, b00, c00, // first point
28237         lambda0, x0, y0, a0, b0, c0; // previous point
28238
28239     var resampleStream = {
28240       point: point,
28241       lineStart: lineStart,
28242       lineEnd: lineEnd,
28243       polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
28244       polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
28245     };
28246
28247     function point(x, y) {
28248       x = project(x, y);
28249       stream.point(x[0], x[1]);
28250     }
28251
28252     function lineStart() {
28253       x0 = NaN;
28254       resampleStream.point = linePoint;
28255       stream.lineStart();
28256     }
28257
28258     function linePoint(lambda, phi) {
28259       var c = cartesian([lambda, phi]), p = project(lambda, phi);
28260       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);
28261       stream.point(x0, y0);
28262     }
28263
28264     function lineEnd() {
28265       resampleStream.point = point;
28266       stream.lineEnd();
28267     }
28268
28269     function ringStart() {
28270       lineStart();
28271       resampleStream.point = ringPoint;
28272       resampleStream.lineEnd = ringEnd;
28273     }
28274
28275     function ringPoint(lambda, phi) {
28276       linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
28277       resampleStream.point = linePoint;
28278     }
28279
28280     function ringEnd() {
28281       resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
28282       resampleStream.lineEnd = lineEnd;
28283       lineEnd();
28284     }
28285
28286     return resampleStream;
28287   };
28288 }
28289
28290 var transformRadians = transformer({
28291   point: function(x, y) {
28292     this.stream.point(x * radians, y * radians);
28293   }
28294 });
28295
28296 function projection(project) {
28297   return projectionMutator(function() { return project; })();
28298 }
28299
28300 function projectionMutator(projectAt) {
28301   var project,
28302       k = 150, // scale
28303       x = 480, y = 250, // translate
28304       dx, dy, lambda = 0, phi = 0, // center
28305       deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate
28306       theta = null, preclip = clipAntimeridian, // clip angle
28307       x0 = null, y0, x1, y1, postclip = identity$4, // clip extent
28308       delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision
28309       cache,
28310       cacheStream;
28311
28312   function projection(point) {
28313     point = projectRotate(point[0] * radians, point[1] * radians);
28314     return [point[0] * k + dx, dy - point[1] * k];
28315   }
28316
28317   function invert(point) {
28318     point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k);
28319     return point && [point[0] * degrees$1, point[1] * degrees$1];
28320   }
28321
28322   function projectTransform(x, y) {
28323     return x = project(x, y), [x[0] * k + dx, dy - x[1] * k];
28324   }
28325
28326   projection.stream = function(stream) {
28327     return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream))));
28328   };
28329
28330   projection.clipAngle = function(_) {
28331     return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
28332   };
28333
28334   projection.clipExtent = function(_) {
28335     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]];
28336   };
28337
28338   projection.scale = function(_) {
28339     return arguments.length ? (k = +_, recenter()) : k;
28340   };
28341
28342   projection.translate = function(_) {
28343     return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
28344   };
28345
28346   projection.center = function(_) {
28347     return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
28348   };
28349
28350   projection.rotate = function(_) {
28351     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];
28352   };
28353
28354   projection.precision = function(_) {
28355     return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
28356   };
28357
28358   projection.fitExtent = function(extent, object) {
28359     return fitExtent(projection, extent, object);
28360   };
28361
28362   projection.fitSize = function(size, object) {
28363     return fitSize(projection, size, object);
28364   };
28365
28366   function recenter() {
28367     projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project);
28368     var center = project(lambda, phi);
28369     dx = x - center[0] * k;
28370     dy = y + center[1] * k;
28371     return reset();
28372   }
28373
28374   function reset() {
28375     cache = cacheStream = null;
28376     return projection;
28377   }
28378
28379   return function() {
28380     project = projectAt.apply(this, arguments);
28381     projection.invert = project.invert && invert;
28382     return recenter();
28383   };
28384 }
28385
28386 function conicProjection(projectAt) {
28387   var phi0 = 0,
28388       phi1 = pi$3 / 3,
28389       m = projectionMutator(projectAt),
28390       p = m(phi0, phi1);
28391
28392   p.parallels = function(_) {
28393     return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees$1, phi1 * degrees$1];
28394   };
28395
28396   return p;
28397 }
28398
28399 function cylindricalEqualAreaRaw(phi0) {
28400   var cosPhi0 = cos$1(phi0);
28401
28402   function forward(lambda, phi) {
28403     return [lambda * cosPhi0, sin$1(phi) / cosPhi0];
28404   }
28405
28406   forward.invert = function(x, y) {
28407     return [x / cosPhi0, asin(y * cosPhi0)];
28408   };
28409
28410   return forward;
28411 }
28412
28413 function conicEqualAreaRaw(y0, y1) {
28414   var sy0 = sin$1(y0), n = (sy0 + sin$1(y1)) / 2;
28415
28416   // Are the parallels symmetrical around the Equator?
28417   if (abs(n) < epsilon$2) return cylindricalEqualAreaRaw(y0);
28418
28419   var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt(c) / n;
28420
28421   function project(x, y) {
28422     var r = sqrt(c - 2 * n * sin$1(y)) / n;
28423     return [r * sin$1(x *= n), r0 - r * cos$1(x)];
28424   }
28425
28426   project.invert = function(x, y) {
28427     var r0y = r0 - y;
28428     return [atan2(x, abs(r0y)) / n * sign(r0y), asin((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
28429   };
28430
28431   return project;
28432 }
28433
28434 var conicEqualArea = function() {
28435   return conicProjection(conicEqualAreaRaw)
28436       .scale(155.424)
28437       .center([0, 33.6442]);
28438 };
28439
28440 var albers = function() {
28441   return conicEqualArea()
28442       .parallels([29.5, 45.5])
28443       .scale(1070)
28444       .translate([480, 250])
28445       .rotate([96, 0])
28446       .center([-0.6, 38.7]);
28447 };
28448
28449 // The projections must have mutually exclusive clip regions on the sphere,
28450 // as this will avoid emitting interleaving lines and polygons.
28451 function multiplex(streams) {
28452   var n = streams.length;
28453   return {
28454     point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); },
28455     sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); },
28456     lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); },
28457     lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); },
28458     polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); },
28459     polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); }
28460   };
28461 }
28462
28463 // A composite projection for the United States, configured by default for
28464 // 960×500. The projection also works quite well at 960×600 if you change the
28465 // scale to 1285 and adjust the translate accordingly. The set of standard
28466 // parallels for each region comes from USGS, which is published here:
28467 // http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
28468 var albersUsa = function() {
28469   var cache,
28470       cacheStream,
28471       lower48 = albers(), lower48Point,
28472       alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338
28473       hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007
28474       point, pointStream = {point: function(x, y) { point = [x, y]; }};
28475
28476   function albersUsa(coordinates) {
28477     var x = coordinates[0], y = coordinates[1];
28478     return point = null,
28479         (lower48Point.point(x, y), point)
28480         || (alaskaPoint.point(x, y), point)
28481         || (hawaiiPoint.point(x, y), point);
28482   }
28483
28484   albersUsa.invert = function(coordinates) {
28485     var k = lower48.scale(),
28486         t = lower48.translate(),
28487         x = (coordinates[0] - t[0]) / k,
28488         y = (coordinates[1] - t[1]) / k;
28489     return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska
28490         : y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii
28491         : lower48).invert(coordinates);
28492   };
28493
28494   albersUsa.stream = function(stream) {
28495     return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]);
28496   };
28497
28498   albersUsa.precision = function(_) {
28499     if (!arguments.length) return lower48.precision();
28500     lower48.precision(_), alaska.precision(_), hawaii.precision(_);
28501     return reset();
28502   };
28503
28504   albersUsa.scale = function(_) {
28505     if (!arguments.length) return lower48.scale();
28506     lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_);
28507     return albersUsa.translate(lower48.translate());
28508   };
28509
28510   albersUsa.translate = function(_) {
28511     if (!arguments.length) return lower48.translate();
28512     var k = lower48.scale(), x = +_[0], y = +_[1];
28513
28514     lower48Point = lower48
28515         .translate(_)
28516         .clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]])
28517         .stream(pointStream);
28518
28519     alaskaPoint = alaska
28520         .translate([x - 0.307 * k, y + 0.201 * k])
28521         .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]])
28522         .stream(pointStream);
28523
28524     hawaiiPoint = hawaii
28525         .translate([x - 0.205 * k, y + 0.212 * k])
28526         .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]])
28527         .stream(pointStream);
28528
28529     return reset();
28530   };
28531
28532   albersUsa.fitExtent = function(extent, object) {
28533     return fitExtent(albersUsa, extent, object);
28534   };
28535
28536   albersUsa.fitSize = function(size, object) {
28537     return fitSize(albersUsa, size, object);
28538   };
28539
28540   function reset() {
28541     cache = cacheStream = null;
28542     return albersUsa;
28543   }
28544
28545   return albersUsa.scale(1070);
28546 };
28547
28548 function azimuthalRaw(scale) {
28549   return function(x, y) {
28550     var cx = cos$1(x),
28551         cy = cos$1(y),
28552         k = scale(cx * cy);
28553     return [
28554       k * cy * sin$1(x),
28555       k * sin$1(y)
28556     ];
28557   }
28558 }
28559
28560 function azimuthalInvert(angle) {
28561   return function(x, y) {
28562     var z = sqrt(x * x + y * y),
28563         c = angle(z),
28564         sc = sin$1(c),
28565         cc = cos$1(c);
28566     return [
28567       atan2(x * sc, z * cc),
28568       asin(z && y * sc / z)
28569     ];
28570   }
28571 }
28572
28573 var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) {
28574   return sqrt(2 / (1 + cxcy));
28575 });
28576
28577 azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) {
28578   return 2 * asin(z / 2);
28579 });
28580
28581 var azimuthalEqualArea = function() {
28582   return projection(azimuthalEqualAreaRaw)
28583       .scale(124.75)
28584       .clipAngle(180 - 1e-3);
28585 };
28586
28587 var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
28588   return (c = acos(c)) && c / sin$1(c);
28589 });
28590
28591 azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
28592   return z;
28593 });
28594
28595 var azimuthalEquidistant = function() {
28596   return projection(azimuthalEquidistantRaw)
28597       .scale(79.4188)
28598       .clipAngle(180 - 1e-3);
28599 };
28600
28601 function mercatorRaw(lambda, phi) {
28602   return [lambda, log(tan((halfPi$2 + phi) / 2))];
28603 }
28604
28605 mercatorRaw.invert = function(x, y) {
28606   return [x, 2 * atan(exp(y)) - halfPi$2];
28607 };
28608
28609 var mercator = function() {
28610   return mercatorProjection(mercatorRaw)
28611       .scale(961 / tau$3);
28612 };
28613
28614 function mercatorProjection(project) {
28615   var m = projection(project),
28616       center = m.center,
28617       scale = m.scale,
28618       translate = m.translate,
28619       clipExtent = m.clipExtent,
28620       x0 = null, y0, x1, y1; // clip extent
28621
28622   m.scale = function(_) {
28623     return arguments.length ? (scale(_), reclip()) : scale();
28624   };
28625
28626   m.translate = function(_) {
28627     return arguments.length ? (translate(_), reclip()) : translate();
28628   };
28629
28630   m.center = function(_) {
28631     return arguments.length ? (center(_), reclip()) : center();
28632   };
28633
28634   m.clipExtent = function(_) {
28635     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]];
28636   };
28637
28638   function reclip() {
28639     var k = pi$3 * scale(),
28640         t = m(rotation(m.rotate()).invert([0, 0]));
28641     return clipExtent(x0 == null
28642         ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw
28643         ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]]
28644         : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]);
28645   }
28646
28647   return reclip();
28648 }
28649
28650 function tany(y) {
28651   return tan((halfPi$2 + y) / 2);
28652 }
28653
28654 function conicConformalRaw(y0, y1) {
28655   var cy0 = cos$1(y0),
28656       n = y0 === y1 ? sin$1(y0) : log(cy0 / cos$1(y1)) / log(tany(y1) / tany(y0)),
28657       f = cy0 * pow(tany(y0), n) / n;
28658
28659   if (!n) return mercatorRaw;
28660
28661   function project(x, y) {
28662     if (f > 0) { if (y < -halfPi$2 + epsilon$2) y = -halfPi$2 + epsilon$2; }
28663     else { if (y > halfPi$2 - epsilon$2) y = halfPi$2 - epsilon$2; }
28664     var r = f / pow(tany(y), n);
28665     return [r * sin$1(n * x), f - r * cos$1(n * x)];
28666   }
28667
28668   project.invert = function(x, y) {
28669     var fy = f - y, r = sign(n) * sqrt(x * x + fy * fy);
28670     return [atan2(x, abs(fy)) / n * sign(fy), 2 * atan(pow(f / r, 1 / n)) - halfPi$2];
28671   };
28672
28673   return project;
28674 }
28675
28676 var conicConformal = function() {
28677   return conicProjection(conicConformalRaw)
28678       .scale(109.5)
28679       .parallels([30, 30]);
28680 };
28681
28682 function equirectangularRaw(lambda, phi) {
28683   return [lambda, phi];
28684 }
28685
28686 equirectangularRaw.invert = equirectangularRaw;
28687
28688 var equirectangular = function() {
28689   return projection(equirectangularRaw)
28690       .scale(152.63);
28691 };
28692
28693 function conicEquidistantRaw(y0, y1) {
28694   var cy0 = cos$1(y0),
28695       n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(y1)) / (y1 - y0),
28696       g = cy0 / n + y0;
28697
28698   if (abs(n) < epsilon$2) return equirectangularRaw;
28699
28700   function project(x, y) {
28701     var gy = g - y, nx = n * x;
28702     return [gy * sin$1(nx), g - gy * cos$1(nx)];
28703   }
28704
28705   project.invert = function(x, y) {
28706     var gy = g - y;
28707     return [atan2(x, abs(gy)) / n * sign(gy), g - sign(n) * sqrt(x * x + gy * gy)];
28708   };
28709
28710   return project;
28711 }
28712
28713 var conicEquidistant = function() {
28714   return conicProjection(conicEquidistantRaw)
28715       .scale(131.154)
28716       .center([0, 13.9389]);
28717 };
28718
28719 function gnomonicRaw(x, y) {
28720   var cy = cos$1(y), k = cos$1(x) * cy;
28721   return [cy * sin$1(x) / k, sin$1(y) / k];
28722 }
28723
28724 gnomonicRaw.invert = azimuthalInvert(atan);
28725
28726 var gnomonic = function() {
28727   return projection(gnomonicRaw)
28728       .scale(144.049)
28729       .clipAngle(60);
28730 };
28731
28732 function scaleTranslate(kx, ky, tx, ty) {
28733   return kx === 1 && ky === 1 && tx === 0 && ty === 0 ? identity$4 : transformer({
28734     point: function(x, y) {
28735       this.stream.point(x * kx + tx, y * ky + ty);
28736     }
28737   });
28738 }
28739
28740 var identity$5 = function() {
28741   var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, transform = identity$4, // scale, translate and reflect
28742       x0 = null, y0, x1, y1, clip = identity$4, // clip extent
28743       cache,
28744       cacheStream,
28745       projection;
28746
28747   function reset() {
28748     cache = cacheStream = null;
28749     return projection;
28750   }
28751
28752   return projection = {
28753     stream: function(stream) {
28754       return cache && cacheStream === stream ? cache : cache = transform(clip(cacheStream = stream));
28755     },
28756     clipExtent: function(_) {
28757       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]];
28758     },
28759     scale: function(_) {
28760       return arguments.length ? (transform = scaleTranslate((k = +_) * sx, k * sy, tx, ty), reset()) : k;
28761     },
28762     translate: function(_) {
28763       return arguments.length ? (transform = scaleTranslate(k * sx, k * sy, tx = +_[0], ty = +_[1]), reset()) : [tx, ty];
28764     },
28765     reflectX: function(_) {
28766       return arguments.length ? (transform = scaleTranslate(k * (sx = _ ? -1 : 1), k * sy, tx, ty), reset()) : sx < 0;
28767     },
28768     reflectY: function(_) {
28769       return arguments.length ? (transform = scaleTranslate(k * sx, k * (sy = _ ? -1 : 1), tx, ty), reset()) : sy < 0;
28770     },
28771     fitExtent: function(extent, object) {
28772       return fitExtent(projection, extent, object);
28773     },
28774     fitSize: function(size, object) {
28775       return fitSize(projection, size, object);
28776     }
28777   };
28778 };
28779
28780 function orthographicRaw(x, y) {
28781   return [cos$1(y) * sin$1(x), sin$1(y)];
28782 }
28783
28784 orthographicRaw.invert = azimuthalInvert(asin);
28785
28786 var orthographic = function() {
28787   return projection(orthographicRaw)
28788       .scale(249.5)
28789       .clipAngle(90 + epsilon$2);
28790 };
28791
28792 function stereographicRaw(x, y) {
28793   var cy = cos$1(y), k = 1 + cos$1(x) * cy;
28794   return [cy * sin$1(x) / k, sin$1(y) / k];
28795 }
28796
28797 stereographicRaw.invert = azimuthalInvert(function(z) {
28798   return 2 * atan(z);
28799 });
28800
28801 var stereographic = function() {
28802   return projection(stereographicRaw)
28803       .scale(250)
28804       .clipAngle(142);
28805 };
28806
28807 function transverseMercatorRaw(lambda, phi) {
28808   return [log(tan((halfPi$2 + phi) / 2)), -lambda];
28809 }
28810
28811 transverseMercatorRaw.invert = function(x, y) {
28812   return [-y, 2 * atan(exp(x)) - halfPi$2];
28813 };
28814
28815 var transverseMercator = function() {
28816   var m = mercatorProjection(transverseMercatorRaw),
28817       center = m.center,
28818       rotate = m.rotate;
28819
28820   m.center = function(_) {
28821     return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]);
28822   };
28823
28824   m.rotate = function(_) {
28825     return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]);
28826   };
28827
28828   return rotate([0, 0, 90])
28829       .scale(159.155);
28830 };
28831
28832 function defaultSeparation(a, b) {
28833   return a.parent === b.parent ? 1 : 2;
28834 }
28835
28836 function meanX(children) {
28837   return children.reduce(meanXReduce, 0) / children.length;
28838 }
28839
28840 function meanXReduce(x, c) {
28841   return x + c.x;
28842 }
28843
28844 function maxY(children) {
28845   return 1 + children.reduce(maxYReduce, 0);
28846 }
28847
28848 function maxYReduce(y, c) {
28849   return Math.max(y, c.y);
28850 }
28851
28852 function leafLeft(node) {
28853   var children;
28854   while (children = node.children) node = children[0];
28855   return node;
28856 }
28857
28858 function leafRight(node) {
28859   var children;
28860   while (children = node.children) node = children[children.length - 1];
28861   return node;
28862 }
28863
28864 var cluster = function() {
28865   var separation = defaultSeparation,
28866       dx = 1,
28867       dy = 1,
28868       nodeSize = false;
28869
28870   function cluster(root) {
28871     var previousNode,
28872         x = 0;
28873
28874     // First walk, computing the initial x & y values.
28875     root.eachAfter(function(node) {
28876       var children = node.children;
28877       if (children) {
28878         node.x = meanX(children);
28879         node.y = maxY(children);
28880       } else {
28881         node.x = previousNode ? x += separation(node, previousNode) : 0;
28882         node.y = 0;
28883         previousNode = node;
28884       }
28885     });
28886
28887     var left = leafLeft(root),
28888         right = leafRight(root),
28889         x0 = left.x - separation(left, right) / 2,
28890         x1 = right.x + separation(right, left) / 2;
28891
28892     // Second walk, normalizing x & y to the desired size.
28893     return root.eachAfter(nodeSize ? function(node) {
28894       node.x = (node.x - root.x) * dx;
28895       node.y = (root.y - node.y) * dy;
28896     } : function(node) {
28897       node.x = (node.x - x0) / (x1 - x0) * dx;
28898       node.y = (1 - (root.y ? node.y / root.y : 1)) * dy;
28899     });
28900   }
28901
28902   cluster.separation = function(x) {
28903     return arguments.length ? (separation = x, cluster) : separation;
28904   };
28905
28906   cluster.size = function(x) {
28907     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]);
28908   };
28909
28910   cluster.nodeSize = function(x) {
28911     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null);
28912   };
28913
28914   return cluster;
28915 };
28916
28917 function count(node) {
28918   var sum = 0,
28919       children = node.children,
28920       i = children && children.length;
28921   if (!i) sum = 1;
28922   else while (--i >= 0) sum += children[i].value;
28923   node.value = sum;
28924 }
28925
28926 var node_count = function() {
28927   return this.eachAfter(count);
28928 };
28929
28930 var node_each = function(callback) {
28931   var node = this, current, next = [node], children, i, n;
28932   do {
28933     current = next.reverse(), next = [];
28934     while (node = current.pop()) {
28935       callback(node), children = node.children;
28936       if (children) for (i = 0, n = children.length; i < n; ++i) {
28937         next.push(children[i]);
28938       }
28939     }
28940   } while (next.length);
28941   return this;
28942 };
28943
28944 var node_eachBefore = function(callback) {
28945   var node = this, nodes = [node], children, i;
28946   while (node = nodes.pop()) {
28947     callback(node), children = node.children;
28948     if (children) for (i = children.length - 1; i >= 0; --i) {
28949       nodes.push(children[i]);
28950     }
28951   }
28952   return this;
28953 };
28954
28955 var node_eachAfter = function(callback) {
28956   var node = this, nodes = [node], next = [], children, i, n;
28957   while (node = nodes.pop()) {
28958     next.push(node), children = node.children;
28959     if (children) for (i = 0, n = children.length; i < n; ++i) {
28960       nodes.push(children[i]);
28961     }
28962   }
28963   while (node = next.pop()) {
28964     callback(node);
28965   }
28966   return this;
28967 };
28968
28969 var node_sum = function(value) {
28970   return this.eachAfter(function(node) {
28971     var sum = +value(node.data) || 0,
28972         children = node.children,
28973         i = children && children.length;
28974     while (--i >= 0) sum += children[i].value;
28975     node.value = sum;
28976   });
28977 };
28978
28979 var node_sort = function(compare) {
28980   return this.eachBefore(function(node) {
28981     if (node.children) {
28982       node.children.sort(compare);
28983     }
28984   });
28985 };
28986
28987 var node_path = function(end) {
28988   var start = this,
28989       ancestor = leastCommonAncestor(start, end),
28990       nodes = [start];
28991   while (start !== ancestor) {
28992     start = start.parent;
28993     nodes.push(start);
28994   }
28995   var k = nodes.length;
28996   while (end !== ancestor) {
28997     nodes.splice(k, 0, end);
28998     end = end.parent;
28999   }
29000   return nodes;
29001 };
29002
29003 function leastCommonAncestor(a, b) {
29004   if (a === b) return a;
29005   var aNodes = a.ancestors(),
29006       bNodes = b.ancestors(),
29007       c = null;
29008   a = aNodes.pop();
29009   b = bNodes.pop();
29010   while (a === b) {
29011     c = a;
29012     a = aNodes.pop();
29013     b = bNodes.pop();
29014   }
29015   return c;
29016 }
29017
29018 var node_ancestors = function() {
29019   var node = this, nodes = [node];
29020   while (node = node.parent) {
29021     nodes.push(node);
29022   }
29023   return nodes;
29024 };
29025
29026 var node_descendants = function() {
29027   var nodes = [];
29028   this.each(function(node) {
29029     nodes.push(node);
29030   });
29031   return nodes;
29032 };
29033
29034 var node_leaves = function() {
29035   var leaves = [];
29036   this.eachBefore(function(node) {
29037     if (!node.children) {
29038       leaves.push(node);
29039     }
29040   });
29041   return leaves;
29042 };
29043
29044 var node_links = function() {
29045   var root = this, links = [];
29046   root.each(function(node) {
29047     if (node !== root) { // Don’t include the root’s parent, if any.
29048       links.push({source: node.parent, target: node});
29049     }
29050   });
29051   return links;
29052 };
29053
29054 function hierarchy(data, children) {
29055   var root = new Node(data),
29056       valued = +data.value && (root.value = data.value),
29057       node,
29058       nodes = [root],
29059       child,
29060       childs,
29061       i,
29062       n;
29063
29064   if (children == null) children = defaultChildren;
29065
29066   while (node = nodes.pop()) {
29067     if (valued) node.value = +node.data.value;
29068     if ((childs = children(node.data)) && (n = childs.length)) {
29069       node.children = new Array(n);
29070       for (i = n - 1; i >= 0; --i) {
29071         nodes.push(child = node.children[i] = new Node(childs[i]));
29072         child.parent = node;
29073         child.depth = node.depth + 1;
29074       }
29075     }
29076   }
29077
29078   return root.eachBefore(computeHeight);
29079 }
29080
29081 function node_copy() {
29082   return hierarchy(this).eachBefore(copyData);
29083 }
29084
29085 function defaultChildren(d) {
29086   return d.children;
29087 }
29088
29089 function copyData(node) {
29090   node.data = node.data.data;
29091 }
29092
29093 function computeHeight(node) {
29094   var height = 0;
29095   do node.height = height;
29096   while ((node = node.parent) && (node.height < ++height));
29097 }
29098
29099 function Node(data) {
29100   this.data = data;
29101   this.depth =
29102   this.height = 0;
29103   this.parent = null;
29104 }
29105
29106 Node.prototype = hierarchy.prototype = {
29107   constructor: Node,
29108   count: node_count,
29109   each: node_each,
29110   eachAfter: node_eachAfter,
29111   eachBefore: node_eachBefore,
29112   sum: node_sum,
29113   sort: node_sort,
29114   path: node_path,
29115   ancestors: node_ancestors,
29116   descendants: node_descendants,
29117   leaves: node_leaves,
29118   links: node_links,
29119   copy: node_copy
29120 };
29121
29122 function Node$2(value) {
29123   this._ = value;
29124   this.next = null;
29125 }
29126
29127 var shuffle$1 = function(array) {
29128   var i,
29129       n = (array = array.slice()).length,
29130       head = null,
29131       node = head;
29132
29133   while (n) {
29134     var next = new Node$2(array[n - 1]);
29135     if (node) node = node.next = next;
29136     else node = head = next;
29137     array[i] = array[--n];
29138   }
29139
29140   return {
29141     head: head,
29142     tail: node
29143   };
29144 };
29145
29146 var enclose = function(circles) {
29147   return encloseN(shuffle$1(circles), []);
29148 };
29149
29150 function encloses(a, b) {
29151   var dx = b.x - a.x,
29152       dy = b.y - a.y,
29153       dr = a.r - b.r;
29154   return dr * dr + 1e-6 > dx * dx + dy * dy;
29155 }
29156
29157 // Returns the smallest circle that contains circles L and intersects circles B.
29158 function encloseN(L, B) {
29159   var circle,
29160       l0 = null,
29161       l1 = L.head,
29162       l2,
29163       p1;
29164
29165   switch (B.length) {
29166     case 1: circle = enclose1(B[0]); break;
29167     case 2: circle = enclose2(B[0], B[1]); break;
29168     case 3: circle = enclose3(B[0], B[1], B[2]); break;
29169   }
29170
29171   while (l1) {
29172     p1 = l1._, l2 = l1.next;
29173     if (!circle || !encloses(circle, p1)) {
29174
29175       // Temporarily truncate L before l1.
29176       if (l0) L.tail = l0, l0.next = null;
29177       else L.head = L.tail = null;
29178
29179       B.push(p1);
29180       circle = encloseN(L, B); // Note: reorders L!
29181       B.pop();
29182
29183       // Move l1 to the front of L and reconnect the truncated list L.
29184       if (L.head) l1.next = L.head, L.head = l1;
29185       else l1.next = null, L.head = L.tail = l1;
29186       l0 = L.tail, l0.next = l2;
29187
29188     } else {
29189       l0 = l1;
29190     }
29191     l1 = l2;
29192   }
29193
29194   L.tail = l0;
29195   return circle;
29196 }
29197
29198 function enclose1(a) {
29199   return {
29200     x: a.x,
29201     y: a.y,
29202     r: a.r
29203   };
29204 }
29205
29206 function enclose2(a, b) {
29207   var x1 = a.x, y1 = a.y, r1 = a.r,
29208       x2 = b.x, y2 = b.y, r2 = b.r,
29209       x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
29210       l = Math.sqrt(x21 * x21 + y21 * y21);
29211   return {
29212     x: (x1 + x2 + x21 / l * r21) / 2,
29213     y: (y1 + y2 + y21 / l * r21) / 2,
29214     r: (l + r1 + r2) / 2
29215   };
29216 }
29217
29218 function enclose3(a, b, c) {
29219   var x1 = a.x, y1 = a.y, r1 = a.r,
29220       x2 = b.x, y2 = b.y, r2 = b.r,
29221       x3 = c.x, y3 = c.y, r3 = c.r,
29222       a2 = 2 * (x1 - x2),
29223       b2 = 2 * (y1 - y2),
29224       c2 = 2 * (r2 - r1),
29225       d2 = x1 * x1 + y1 * y1 - r1 * r1 - x2 * x2 - y2 * y2 + r2 * r2,
29226       a3 = 2 * (x1 - x3),
29227       b3 = 2 * (y1 - y3),
29228       c3 = 2 * (r3 - r1),
29229       d3 = x1 * x1 + y1 * y1 - r1 * r1 - x3 * x3 - y3 * y3 + r3 * r3,
29230       ab = a3 * b2 - a2 * b3,
29231       xa = (b2 * d3 - b3 * d2) / ab - x1,
29232       xb = (b3 * c2 - b2 * c3) / ab,
29233       ya = (a3 * d2 - a2 * d3) / ab - y1,
29234       yb = (a2 * c3 - a3 * c2) / ab,
29235       A = xb * xb + yb * yb - 1,
29236       B = 2 * (xa * xb + ya * yb + r1),
29237       C = xa * xa + ya * ya - r1 * r1,
29238       r = (-B - Math.sqrt(B * B - 4 * A * C)) / (2 * A);
29239   return {
29240     x: xa + xb * r + x1,
29241     y: ya + yb * r + y1,
29242     r: r
29243   };
29244 }
29245
29246 function place(a, b, c) {
29247   var ax = a.x,
29248       ay = a.y,
29249       da = b.r + c.r,
29250       db = a.r + c.r,
29251       dx = b.x - ax,
29252       dy = b.y - ay,
29253       dc = dx * dx + dy * dy;
29254   if (dc) {
29255     var x = 0.5 + ((db *= db) - (da *= da)) / (2 * dc),
29256         y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
29257     c.x = ax + x * dx + y * dy;
29258     c.y = ay + x * dy - y * dx;
29259   } else {
29260     c.x = ax + db;
29261     c.y = ay;
29262   }
29263 }
29264
29265 function intersects(a, b) {
29266   var dx = b.x - a.x,
29267       dy = b.y - a.y,
29268       dr = a.r + b.r;
29269   return dr * dr - 1e-6 > dx * dx + dy * dy;
29270 }
29271
29272 function distance2(node, x, y) {
29273   var a = node._,
29274       b = node.next._,
29275       ab = a.r + b.r,
29276       dx = (a.x * b.r + b.x * a.r) / ab - x,
29277       dy = (a.y * b.r + b.y * a.r) / ab - y;
29278   return dx * dx + dy * dy;
29279 }
29280
29281 function Node$1(circle) {
29282   this._ = circle;
29283   this.next = null;
29284   this.previous = null;
29285 }
29286
29287 function packEnclose(circles) {
29288   if (!(n = circles.length)) return 0;
29289
29290   var a, b, c, n;
29291
29292   // Place the first circle.
29293   a = circles[0], a.x = 0, a.y = 0;
29294   if (!(n > 1)) return a.r;
29295
29296   // Place the second circle.
29297   b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
29298   if (!(n > 2)) return a.r + b.r;
29299
29300   // Place the third circle.
29301   place(b, a, c = circles[2]);
29302
29303   // Initialize the weighted centroid.
29304   var aa = a.r * a.r,
29305       ba = b.r * b.r,
29306       ca = c.r * c.r,
29307       oa = aa + ba + ca,
29308       ox = aa * a.x + ba * b.x + ca * c.x,
29309       oy = aa * a.y + ba * b.y + ca * c.y,
29310       cx, cy, i, j, k, sj, sk;
29311
29312   // Initialize the front-chain using the first three circles a, b and c.
29313   a = new Node$1(a), b = new Node$1(b), c = new Node$1(c);
29314   a.next = c.previous = b;
29315   b.next = a.previous = c;
29316   c.next = b.previous = a;
29317
29318   // Attempt to place each remaining circle…
29319   pack: for (i = 3; i < n; ++i) {
29320     place(a._, b._, c = circles[i]), c = new Node$1(c);
29321
29322     // Find the closest intersecting circle on the front-chain, if any.
29323     // “Closeness” is determined by linear distance along the front-chain.
29324     // “Ahead” or “behind” is likewise determined by linear distance.
29325     j = b.next, k = a.previous, sj = b._.r, sk = a._.r;
29326     do {
29327       if (sj <= sk) {
29328         if (intersects(j._, c._)) {
29329           b = j, a.next = b, b.previous = a, --i;
29330           continue pack;
29331         }
29332         sj += j._.r, j = j.next;
29333       } else {
29334         if (intersects(k._, c._)) {
29335           a = k, a.next = b, b.previous = a, --i;
29336           continue pack;
29337         }
29338         sk += k._.r, k = k.previous;
29339       }
29340     } while (j !== k.next);
29341
29342     // Success! Insert the new circle c between a and b.
29343     c.previous = a, c.next = b, a.next = b.previous = b = c;
29344
29345     // Update the weighted centroid.
29346     oa += ca = c._.r * c._.r;
29347     ox += ca * c._.x;
29348     oy += ca * c._.y;
29349
29350     // Compute the new closest circle pair to the centroid.
29351     aa = distance2(a, cx = ox / oa, cy = oy / oa);
29352     while ((c = c.next) !== b) {
29353       if ((ca = distance2(c, cx, cy)) < aa) {
29354         a = c, aa = ca;
29355       }
29356     }
29357     b = a.next;
29358   }
29359
29360   // Compute the enclosing circle of the front chain.
29361   a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
29362
29363   // Translate the circles to put the enclosing circle around the origin.
29364   for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
29365
29366   return c.r;
29367 }
29368
29369 var siblings = function(circles) {
29370   packEnclose(circles);
29371   return circles;
29372 };
29373
29374 function optional(f) {
29375   return f == null ? null : required(f);
29376 }
29377
29378 function required(f) {
29379   if (typeof f !== "function") throw new Error;
29380   return f;
29381 }
29382
29383 function constantZero() {
29384   return 0;
29385 }
29386
29387 var constant$8 = function(x) {
29388   return function() {
29389     return x;
29390   };
29391 };
29392
29393 function defaultRadius$1(d) {
29394   return Math.sqrt(d.value);
29395 }
29396
29397 var index$5 = function() {
29398   var radius = null,
29399       dx = 1,
29400       dy = 1,
29401       padding = constantZero;
29402
29403   function pack(root) {
29404     root.x = dx / 2, root.y = dy / 2;
29405     if (radius) {
29406       root.eachBefore(radiusLeaf(radius))
29407           .eachAfter(packChildren(padding, 0.5))
29408           .eachBefore(translateChild(1));
29409     } else {
29410       root.eachBefore(radiusLeaf(defaultRadius$1))
29411           .eachAfter(packChildren(constantZero, 1))
29412           .eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
29413           .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
29414     }
29415     return root;
29416   }
29417
29418   pack.radius = function(x) {
29419     return arguments.length ? (radius = optional(x), pack) : radius;
29420   };
29421
29422   pack.size = function(x) {
29423     return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
29424   };
29425
29426   pack.padding = function(x) {
29427     return arguments.length ? (padding = typeof x === "function" ? x : constant$8(+x), pack) : padding;
29428   };
29429
29430   return pack;
29431 };
29432
29433 function radiusLeaf(radius) {
29434   return function(node) {
29435     if (!node.children) {
29436       node.r = Math.max(0, +radius(node) || 0);
29437     }
29438   };
29439 }
29440
29441 function packChildren(padding, k) {
29442   return function(node) {
29443     if (children = node.children) {
29444       var children,
29445           i,
29446           n = children.length,
29447           r = padding(node) * k || 0,
29448           e;
29449
29450       if (r) for (i = 0; i < n; ++i) children[i].r += r;
29451       e = packEnclose(children);
29452       if (r) for (i = 0; i < n; ++i) children[i].r -= r;
29453       node.r = e + r;
29454     }
29455   };
29456 }
29457
29458 function translateChild(k) {
29459   return function(node) {
29460     var parent = node.parent;
29461     node.r *= k;
29462     if (parent) {
29463       node.x = parent.x + k * node.x;
29464       node.y = parent.y + k * node.y;
29465     }
29466   };
29467 }
29468
29469 var roundNode = function(node) {
29470   node.x0 = Math.round(node.x0);
29471   node.y0 = Math.round(node.y0);
29472   node.x1 = Math.round(node.x1);
29473   node.y1 = Math.round(node.y1);
29474 };
29475
29476 var treemapDice = function(parent, x0, y0, x1, y1) {
29477   var nodes = parent.children,
29478       node,
29479       i = -1,
29480       n = nodes.length,
29481       k = parent.value && (x1 - x0) / parent.value;
29482
29483   while (++i < n) {
29484     node = nodes[i], node.y0 = y0, node.y1 = y1;
29485     node.x0 = x0, node.x1 = x0 += node.value * k;
29486   }
29487 };
29488
29489 var partition = function() {
29490   var dx = 1,
29491       dy = 1,
29492       padding = 0,
29493       round = false;
29494
29495   function partition(root) {
29496     var n = root.height + 1;
29497     root.x0 =
29498     root.y0 = padding;
29499     root.x1 = dx;
29500     root.y1 = dy / n;
29501     root.eachBefore(positionNode(dy, n));
29502     if (round) root.eachBefore(roundNode);
29503     return root;
29504   }
29505
29506   function positionNode(dy, n) {
29507     return function(node) {
29508       if (node.children) {
29509         treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
29510       }
29511       var x0 = node.x0,
29512           y0 = node.y0,
29513           x1 = node.x1 - padding,
29514           y1 = node.y1 - padding;
29515       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29516       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29517       node.x0 = x0;
29518       node.y0 = y0;
29519       node.x1 = x1;
29520       node.y1 = y1;
29521     };
29522   }
29523
29524   partition.round = function(x) {
29525     return arguments.length ? (round = !!x, partition) : round;
29526   };
29527
29528   partition.size = function(x) {
29529     return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy];
29530   };
29531
29532   partition.padding = function(x) {
29533     return arguments.length ? (padding = +x, partition) : padding;
29534   };
29535
29536   return partition;
29537 };
29538
29539 var keyPrefix$1 = "$";
29540 var preroot = {depth: -1};
29541 var ambiguous = {};
29542
29543 function defaultId(d) {
29544   return d.id;
29545 }
29546
29547 function defaultParentId(d) {
29548   return d.parentId;
29549 }
29550
29551 var stratify = function() {
29552   var id = defaultId,
29553       parentId = defaultParentId;
29554
29555   function stratify(data) {
29556     var d,
29557         i,
29558         n = data.length,
29559         root,
29560         parent,
29561         node,
29562         nodes = new Array(n),
29563         nodeId,
29564         nodeKey,
29565         nodeByKey = {};
29566
29567     for (i = 0; i < n; ++i) {
29568       d = data[i], node = nodes[i] = new Node(d);
29569       if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
29570         nodeKey = keyPrefix$1 + (node.id = nodeId);
29571         nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node;
29572       }
29573     }
29574
29575     for (i = 0; i < n; ++i) {
29576       node = nodes[i], nodeId = parentId(data[i], i, data);
29577       if (nodeId == null || !(nodeId += "")) {
29578         if (root) throw new Error("multiple roots");
29579         root = node;
29580       } else {
29581         parent = nodeByKey[keyPrefix$1 + nodeId];
29582         if (!parent) throw new Error("missing: " + nodeId);
29583         if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
29584         if (parent.children) parent.children.push(node);
29585         else parent.children = [node];
29586         node.parent = parent;
29587       }
29588     }
29589
29590     if (!root) throw new Error("no root");
29591     root.parent = preroot;
29592     root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
29593     root.parent = null;
29594     if (n > 0) throw new Error("cycle");
29595
29596     return root;
29597   }
29598
29599   stratify.id = function(x) {
29600     return arguments.length ? (id = required(x), stratify) : id;
29601   };
29602
29603   stratify.parentId = function(x) {
29604     return arguments.length ? (parentId = required(x), stratify) : parentId;
29605   };
29606
29607   return stratify;
29608 };
29609
29610 function defaultSeparation$1(a, b) {
29611   return a.parent === b.parent ? 1 : 2;
29612 }
29613
29614 // function radialSeparation(a, b) {
29615 //   return (a.parent === b.parent ? 1 : 2) / a.depth;
29616 // }
29617
29618 // This function is used to traverse the left contour of a subtree (or
29619 // subforest). It returns the successor of v on this contour. This successor is
29620 // either given by the leftmost child of v or by the thread of v. The function
29621 // returns null if and only if v is on the highest level of its subtree.
29622 function nextLeft(v) {
29623   var children = v.children;
29624   return children ? children[0] : v.t;
29625 }
29626
29627 // This function works analogously to nextLeft.
29628 function nextRight(v) {
29629   var children = v.children;
29630   return children ? children[children.length - 1] : v.t;
29631 }
29632
29633 // Shifts the current subtree rooted at w+. This is done by increasing
29634 // prelim(w+) and mod(w+) by shift.
29635 function moveSubtree(wm, wp, shift) {
29636   var change = shift / (wp.i - wm.i);
29637   wp.c -= change;
29638   wp.s += shift;
29639   wm.c += change;
29640   wp.z += shift;
29641   wp.m += shift;
29642 }
29643
29644 // All other shifts, applied to the smaller subtrees between w- and w+, are
29645 // performed by this function. To prepare the shifts, we have to adjust
29646 // change(w+), shift(w+), and change(w-).
29647 function executeShifts(v) {
29648   var shift = 0,
29649       change = 0,
29650       children = v.children,
29651       i = children.length,
29652       w;
29653   while (--i >= 0) {
29654     w = children[i];
29655     w.z += shift;
29656     w.m += shift;
29657     shift += w.s + (change += w.c);
29658   }
29659 }
29660
29661 // If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise,
29662 // returns the specified (default) ancestor.
29663 function nextAncestor(vim, v, ancestor) {
29664   return vim.a.parent === v.parent ? vim.a : ancestor;
29665 }
29666
29667 function TreeNode(node, i) {
29668   this._ = node;
29669   this.parent = null;
29670   this.children = null;
29671   this.A = null; // default ancestor
29672   this.a = this; // ancestor
29673   this.z = 0; // prelim
29674   this.m = 0; // mod
29675   this.c = 0; // change
29676   this.s = 0; // shift
29677   this.t = null; // thread
29678   this.i = i; // number
29679 }
29680
29681 TreeNode.prototype = Object.create(Node.prototype);
29682
29683 function treeRoot(root) {
29684   var tree = new TreeNode(root, 0),
29685       node,
29686       nodes = [tree],
29687       child,
29688       children,
29689       i,
29690       n;
29691
29692   while (node = nodes.pop()) {
29693     if (children = node._.children) {
29694       node.children = new Array(n = children.length);
29695       for (i = n - 1; i >= 0; --i) {
29696         nodes.push(child = node.children[i] = new TreeNode(children[i], i));
29697         child.parent = node;
29698       }
29699     }
29700   }
29701
29702   (tree.parent = new TreeNode(null, 0)).children = [tree];
29703   return tree;
29704 }
29705
29706 // Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
29707 var tree = function() {
29708   var separation = defaultSeparation$1,
29709       dx = 1,
29710       dy = 1,
29711       nodeSize = null;
29712
29713   function tree(root) {
29714     var t = treeRoot(root);
29715
29716     // Compute the layout using Buchheim et al.’s algorithm.
29717     t.eachAfter(firstWalk), t.parent.m = -t.z;
29718     t.eachBefore(secondWalk);
29719
29720     // If a fixed node size is specified, scale x and y.
29721     if (nodeSize) root.eachBefore(sizeNode);
29722
29723     // If a fixed tree size is specified, scale x and y based on the extent.
29724     // Compute the left-most, right-most, and depth-most nodes for extents.
29725     else {
29726       var left = root,
29727           right = root,
29728           bottom = root;
29729       root.eachBefore(function(node) {
29730         if (node.x < left.x) left = node;
29731         if (node.x > right.x) right = node;
29732         if (node.depth > bottom.depth) bottom = node;
29733       });
29734       var s = left === right ? 1 : separation(left, right) / 2,
29735           tx = s - left.x,
29736           kx = dx / (right.x + s + tx),
29737           ky = dy / (bottom.depth || 1);
29738       root.eachBefore(function(node) {
29739         node.x = (node.x + tx) * kx;
29740         node.y = node.depth * ky;
29741       });
29742     }
29743
29744     return root;
29745   }
29746
29747   // Computes a preliminary x-coordinate for v. Before that, FIRST WALK is
29748   // applied recursively to the children of v, as well as the function
29749   // APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the
29750   // node v is placed to the midpoint of its outermost children.
29751   function firstWalk(v) {
29752     var children = v.children,
29753         siblings = v.parent.children,
29754         w = v.i ? siblings[v.i - 1] : null;
29755     if (children) {
29756       executeShifts(v);
29757       var midpoint = (children[0].z + children[children.length - 1].z) / 2;
29758       if (w) {
29759         v.z = w.z + separation(v._, w._);
29760         v.m = v.z - midpoint;
29761       } else {
29762         v.z = midpoint;
29763       }
29764     } else if (w) {
29765       v.z = w.z + separation(v._, w._);
29766     }
29767     v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
29768   }
29769
29770   // Computes all real x-coordinates by summing up the modifiers recursively.
29771   function secondWalk(v) {
29772     v._.x = v.z + v.parent.m;
29773     v.m += v.parent.m;
29774   }
29775
29776   // The core of the algorithm. Here, a new subtree is combined with the
29777   // previous subtrees. Threads are used to traverse the inside and outside
29778   // contours of the left and right subtree up to the highest common level. The
29779   // vertices used for the traversals are vi+, vi-, vo-, and vo+, where the
29780   // superscript o means outside and i means inside, the subscript - means left
29781   // subtree and + means right subtree. For summing up the modifiers along the
29782   // contour, we use respective variables si+, si-, so-, and so+. Whenever two
29783   // nodes of the inside contours conflict, we compute the left one of the
29784   // greatest uncommon ancestors using the function ANCESTOR and call MOVE
29785   // SUBTREE to shift the subtree and prepare the shifts of smaller subtrees.
29786   // Finally, we add a new thread (if necessary).
29787   function apportion(v, w, ancestor) {
29788     if (w) {
29789       var vip = v,
29790           vop = v,
29791           vim = w,
29792           vom = vip.parent.children[0],
29793           sip = vip.m,
29794           sop = vop.m,
29795           sim = vim.m,
29796           som = vom.m,
29797           shift;
29798       while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) {
29799         vom = nextLeft(vom);
29800         vop = nextRight(vop);
29801         vop.a = v;
29802         shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
29803         if (shift > 0) {
29804           moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
29805           sip += shift;
29806           sop += shift;
29807         }
29808         sim += vim.m;
29809         sip += vip.m;
29810         som += vom.m;
29811         sop += vop.m;
29812       }
29813       if (vim && !nextRight(vop)) {
29814         vop.t = vim;
29815         vop.m += sim - sop;
29816       }
29817       if (vip && !nextLeft(vom)) {
29818         vom.t = vip;
29819         vom.m += sip - som;
29820         ancestor = v;
29821       }
29822     }
29823     return ancestor;
29824   }
29825
29826   function sizeNode(node) {
29827     node.x *= dx;
29828     node.y = node.depth * dy;
29829   }
29830
29831   tree.separation = function(x) {
29832     return arguments.length ? (separation = x, tree) : separation;
29833   };
29834
29835   tree.size = function(x) {
29836     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]);
29837   };
29838
29839   tree.nodeSize = function(x) {
29840     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null);
29841   };
29842
29843   return tree;
29844 };
29845
29846 var treemapSlice = function(parent, x0, y0, x1, y1) {
29847   var nodes = parent.children,
29848       node,
29849       i = -1,
29850       n = nodes.length,
29851       k = parent.value && (y1 - y0) / parent.value;
29852
29853   while (++i < n) {
29854     node = nodes[i], node.x0 = x0, node.x1 = x1;
29855     node.y0 = y0, node.y1 = y0 += node.value * k;
29856   }
29857 };
29858
29859 var phi = (1 + Math.sqrt(5)) / 2;
29860
29861 function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
29862   var rows = [],
29863       nodes = parent.children,
29864       row,
29865       nodeValue,
29866       i0 = 0,
29867       i1 = 0,
29868       n = nodes.length,
29869       dx, dy,
29870       value = parent.value,
29871       sumValue,
29872       minValue,
29873       maxValue,
29874       newRatio,
29875       minRatio,
29876       alpha,
29877       beta;
29878
29879   while (i0 < n) {
29880     dx = x1 - x0, dy = y1 - y0;
29881
29882     // Find the next non-empty node.
29883     do sumValue = nodes[i1++].value; while (!sumValue && i1 < n);
29884     minValue = maxValue = sumValue;
29885     alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
29886     beta = sumValue * sumValue * alpha;
29887     minRatio = Math.max(maxValue / beta, beta / minValue);
29888
29889     // Keep adding nodes while the aspect ratio maintains or improves.
29890     for (; i1 < n; ++i1) {
29891       sumValue += nodeValue = nodes[i1].value;
29892       if (nodeValue < minValue) minValue = nodeValue;
29893       if (nodeValue > maxValue) maxValue = nodeValue;
29894       beta = sumValue * sumValue * alpha;
29895       newRatio = Math.max(maxValue / beta, beta / minValue);
29896       if (newRatio > minRatio) { sumValue -= nodeValue; break; }
29897       minRatio = newRatio;
29898     }
29899
29900     // Position and record the row orientation.
29901     rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
29902     if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
29903     else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
29904     value -= sumValue, i0 = i1;
29905   }
29906
29907   return rows;
29908 }
29909
29910 var squarify = ((function custom(ratio) {
29911
29912   function squarify(parent, x0, y0, x1, y1) {
29913     squarifyRatio(ratio, parent, x0, y0, x1, y1);
29914   }
29915
29916   squarify.ratio = function(x) {
29917     return custom((x = +x) > 1 ? x : 1);
29918   };
29919
29920   return squarify;
29921 }))(phi);
29922
29923 var index$6 = function() {
29924   var tile = squarify,
29925       round = false,
29926       dx = 1,
29927       dy = 1,
29928       paddingStack = [0],
29929       paddingInner = constantZero,
29930       paddingTop = constantZero,
29931       paddingRight = constantZero,
29932       paddingBottom = constantZero,
29933       paddingLeft = constantZero;
29934
29935   function treemap(root) {
29936     root.x0 =
29937     root.y0 = 0;
29938     root.x1 = dx;
29939     root.y1 = dy;
29940     root.eachBefore(positionNode);
29941     paddingStack = [0];
29942     if (round) root.eachBefore(roundNode);
29943     return root;
29944   }
29945
29946   function positionNode(node) {
29947     var p = paddingStack[node.depth],
29948         x0 = node.x0 + p,
29949         y0 = node.y0 + p,
29950         x1 = node.x1 - p,
29951         y1 = node.y1 - p;
29952     if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29953     if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29954     node.x0 = x0;
29955     node.y0 = y0;
29956     node.x1 = x1;
29957     node.y1 = y1;
29958     if (node.children) {
29959       p = paddingStack[node.depth + 1] = paddingInner(node) / 2;
29960       x0 += paddingLeft(node) - p;
29961       y0 += paddingTop(node) - p;
29962       x1 -= paddingRight(node) - p;
29963       y1 -= paddingBottom(node) - p;
29964       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29965       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29966       tile(node, x0, y0, x1, y1);
29967     }
29968   }
29969
29970   treemap.round = function(x) {
29971     return arguments.length ? (round = !!x, treemap) : round;
29972   };
29973
29974   treemap.size = function(x) {
29975     return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy];
29976   };
29977
29978   treemap.tile = function(x) {
29979     return arguments.length ? (tile = required(x), treemap) : tile;
29980   };
29981
29982   treemap.padding = function(x) {
29983     return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner();
29984   };
29985
29986   treemap.paddingInner = function(x) {
29987     return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$8(+x), treemap) : paddingInner;
29988   };
29989
29990   treemap.paddingOuter = function(x) {
29991     return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop();
29992   };
29993
29994   treemap.paddingTop = function(x) {
29995     return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$8(+x), treemap) : paddingTop;
29996   };
29997
29998   treemap.paddingRight = function(x) {
29999     return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$8(+x), treemap) : paddingRight;
30000   };
30001
30002   treemap.paddingBottom = function(x) {
30003     return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$8(+x), treemap) : paddingBottom;
30004   };
30005
30006   treemap.paddingLeft = function(x) {
30007     return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$8(+x), treemap) : paddingLeft;
30008   };
30009
30010   return treemap;
30011 };
30012
30013 var binary = function(parent, x0, y0, x1, y1) {
30014   var nodes = parent.children,
30015       i, n = nodes.length,
30016       sum, sums = new Array(n + 1);
30017
30018   for (sums[0] = sum = i = 0; i < n; ++i) {
30019     sums[i + 1] = sum += nodes[i].value;
30020   }
30021
30022   partition(0, n, parent.value, x0, y0, x1, y1);
30023
30024   function partition(i, j, value, x0, y0, x1, y1) {
30025     if (i >= j - 1) {
30026       var node = nodes[i];
30027       node.x0 = x0, node.y0 = y0;
30028       node.x1 = x1, node.y1 = y1;
30029       return;
30030     }
30031
30032     var valueOffset = sums[i],
30033         valueTarget = (value / 2) + valueOffset,
30034         k = i + 1,
30035         hi = j - 1;
30036
30037     while (k < hi) {
30038       var mid = k + hi >>> 1;
30039       if (sums[mid] < valueTarget) k = mid + 1;
30040       else hi = mid;
30041     }
30042
30043     if ((valueTarget - sums[k - 1]) < (sums[k] - valueTarget) && i + 1 < k) --k;
30044
30045     var valueLeft = sums[k] - valueOffset,
30046         valueRight = value - valueLeft;
30047
30048     if ((x1 - x0) > (y1 - y0)) {
30049       var xk = (x0 * valueRight + x1 * valueLeft) / value;
30050       partition(i, k, valueLeft, x0, y0, xk, y1);
30051       partition(k, j, valueRight, xk, y0, x1, y1);
30052     } else {
30053       var yk = (y0 * valueRight + y1 * valueLeft) / value;
30054       partition(i, k, valueLeft, x0, y0, x1, yk);
30055       partition(k, j, valueRight, x0, yk, x1, y1);
30056     }
30057   }
30058 };
30059
30060 var sliceDice = function(parent, x0, y0, x1, y1) {
30061   (parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1);
30062 };
30063
30064 var resquarify = ((function custom(ratio) {
30065
30066   function resquarify(parent, x0, y0, x1, y1) {
30067     if ((rows = parent._squarify) && (rows.ratio === ratio)) {
30068       var rows,
30069           row,
30070           nodes,
30071           i,
30072           j = -1,
30073           n,
30074           m = rows.length,
30075           value = parent.value;
30076
30077       while (++j < m) {
30078         row = rows[j], nodes = row.children;
30079         for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
30080         if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value);
30081         else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1);
30082         value -= row.value;
30083       }
30084     } else {
30085       parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1);
30086       rows.ratio = ratio;
30087     }
30088   }
30089
30090   resquarify.ratio = function(x) {
30091     return custom((x = +x) > 1 ? x : 1);
30092   };
30093
30094   return resquarify;
30095 }))(phi);
30096
30097 var d3polygonArea = function(polygon) {
30098   var i = -1,
30099       n = polygon.length,
30100       a,
30101       b = polygon[n - 1],
30102       area = 0;
30103
30104   while (++i < n) {
30105     a = b;
30106     b = polygon[i];
30107     area += a[1] * b[0] - a[0] * b[1];
30108   }
30109
30110   return area / 2;
30111 };
30112
30113 var d3polygonCentroid = function(polygon) {
30114   var i = -1,
30115       n = polygon.length,
30116       x = 0,
30117       y = 0,
30118       a,
30119       b = polygon[n - 1],
30120       c,
30121       k = 0;
30122
30123   while (++i < n) {
30124     a = b;
30125     b = polygon[i];
30126     k += c = a[0] * b[1] - b[0] * a[1];
30127     x += (a[0] + b[0]) * c;
30128     y += (a[1] + b[1]) * c;
30129   }
30130
30131   return k *= 3, [x / k, y / k];
30132 };
30133
30134 // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
30135 // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
30136 // right, +y is up). Returns a positive value if ABC is counter-clockwise,
30137 // negative if clockwise, and zero if the points are collinear.
30138 var cross$1 = function(a, b, c) {
30139   return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
30140 };
30141
30142 function lexicographicOrder(a, b) {
30143   return a[0] - b[0] || a[1] - b[1];
30144 }
30145
30146 // Computes the upper convex hull per the monotone chain algorithm.
30147 // Assumes points.length >= 3, is sorted by x, unique in y.
30148 // Returns an array of indices into points in left-to-right order.
30149 function computeUpperHullIndexes(points) {
30150   var n = points.length,
30151       indexes = [0, 1],
30152       size = 2;
30153
30154   for (var i = 2; i < n; ++i) {
30155     while (size > 1 && cross$1(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size;
30156     indexes[size++] = i;
30157   }
30158
30159   return indexes.slice(0, size); // remove popped points
30160 }
30161
30162 var d3polygonHull = function(points) {
30163   if ((n = points.length) < 3) return null;
30164
30165   var i,
30166       n,
30167       sortedPoints = new Array(n),
30168       flippedPoints = new Array(n);
30169
30170   for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i];
30171   sortedPoints.sort(lexicographicOrder);
30172   for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
30173
30174   var upperIndexes = computeUpperHullIndexes(sortedPoints),
30175       lowerIndexes = computeUpperHullIndexes(flippedPoints);
30176
30177   // Construct the hull polygon, removing possible duplicate endpoints.
30178   var skipLeft = lowerIndexes[0] === upperIndexes[0],
30179       skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
30180       hull = [];
30181
30182   // Add upper hull in right-to-l order.
30183   // Then add lower hull in left-to-right order.
30184   for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]);
30185   for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
30186
30187   return hull;
30188 };
30189
30190 var contains$1 = function(polygon, point) {
30191   var n = polygon.length,
30192       p = polygon[n - 1],
30193       x = point[0], y = point[1],
30194       x0 = p[0], y0 = p[1],
30195       x1, y1,
30196       inside = false;
30197
30198   for (var i = 0; i < n; ++i) {
30199     p = polygon[i], x1 = p[0], y1 = p[1];
30200     if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside;
30201     x0 = x1, y0 = y1;
30202   }
30203
30204   return inside;
30205 };
30206
30207 var length$1 = function(polygon) {
30208   var i = -1,
30209       n = polygon.length,
30210       b = polygon[n - 1],
30211       xa,
30212       ya,
30213       xb = b[0],
30214       yb = b[1],
30215       perimeter = 0;
30216
30217   while (++i < n) {
30218     xa = xb;
30219     ya = yb;
30220     b = polygon[i];
30221     xb = b[0];
30222     yb = b[1];
30223     xa -= xb;
30224     ya -= yb;
30225     perimeter += Math.sqrt(xa * xa + ya * ya);
30226   }
30227
30228   return perimeter;
30229 };
30230
30231 var slice$3 = [].slice;
30232
30233 var noabort = {};
30234
30235 function Queue(size) {
30236   if (!(size >= 1)) throw new Error;
30237   this._size = size;
30238   this._call =
30239   this._error = null;
30240   this._tasks = [];
30241   this._data = [];
30242   this._waiting =
30243   this._active =
30244   this._ended =
30245   this._start = 0; // inside a synchronous task callback?
30246 }
30247
30248 Queue.prototype = queue.prototype = {
30249   constructor: Queue,
30250   defer: function(callback) {
30251     if (typeof callback !== "function" || this._call) throw new Error;
30252     if (this._error != null) return this;
30253     var t = slice$3.call(arguments, 1);
30254     t.push(callback);
30255     ++this._waiting, this._tasks.push(t);
30256     poke$1(this);
30257     return this;
30258   },
30259   abort: function() {
30260     if (this._error == null) abort(this, new Error("abort"));
30261     return this;
30262   },
30263   await: function(callback) {
30264     if (typeof callback !== "function" || this._call) throw new Error;
30265     this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
30266     maybeNotify(this);
30267     return this;
30268   },
30269   awaitAll: function(callback) {
30270     if (typeof callback !== "function" || this._call) throw new Error;
30271     this._call = callback;
30272     maybeNotify(this);
30273     return this;
30274   }
30275 };
30276
30277 function poke$1(q) {
30278   if (!q._start) {
30279     try { start$1(q); } // let the current task complete
30280     catch (e) {
30281       if (q._tasks[q._ended + q._active - 1]) abort(q, e); // task errored synchronously
30282       else if (!q._data) throw e; // await callback errored synchronously
30283     }
30284   }
30285 }
30286
30287 function start$1(q) {
30288   while (q._start = q._waiting && q._active < q._size) {
30289     var i = q._ended + q._active,
30290         t = q._tasks[i],
30291         j = t.length - 1,
30292         c = t[j];
30293     t[j] = end(q, i);
30294     --q._waiting, ++q._active;
30295     t = c.apply(null, t);
30296     if (!q._tasks[i]) continue; // task finished synchronously
30297     q._tasks[i] = t || noabort;
30298   }
30299 }
30300
30301 function end(q, i) {
30302   return function(e, r) {
30303     if (!q._tasks[i]) return; // ignore multiple callbacks
30304     --q._active, ++q._ended;
30305     q._tasks[i] = null;
30306     if (q._error != null) return; // ignore secondary errors
30307     if (e != null) {
30308       abort(q, e);
30309     } else {
30310       q._data[i] = r;
30311       if (q._waiting) poke$1(q);
30312       else maybeNotify(q);
30313     }
30314   };
30315 }
30316
30317 function abort(q, e) {
30318   var i = q._tasks.length, t;
30319   q._error = e; // ignore active callbacks
30320   q._data = undefined; // allow gc
30321   q._waiting = NaN; // prevent starting
30322
30323   while (--i >= 0) {
30324     if (t = q._tasks[i]) {
30325       q._tasks[i] = null;
30326       if (t.abort) {
30327         try { t.abort(); }
30328         catch (e) { /* ignore */ }
30329       }
30330     }
30331   }
30332
30333   q._active = NaN; // allow notification
30334   maybeNotify(q);
30335 }
30336
30337 function maybeNotify(q) {
30338   if (!q._active && q._call) {
30339     var d = q._data;
30340     q._data = undefined; // allow gc
30341     q._call(q._error, d);
30342   }
30343 }
30344
30345 function queue(concurrency) {
30346   return new Queue(arguments.length ? +concurrency : Infinity);
30347 }
30348
30349 var uniform = function(min, max) {
30350   min = min == null ? 0 : +min;
30351   max = max == null ? 1 : +max;
30352   if (arguments.length === 1) max = min, min = 0;
30353   else max -= min;
30354   return function() {
30355     return Math.random() * max + min;
30356   };
30357 };
30358
30359 var normal = function(mu, sigma) {
30360   var x, r;
30361   mu = mu == null ? 0 : +mu;
30362   sigma = sigma == null ? 1 : +sigma;
30363   return function() {
30364     var y;
30365
30366     // If available, use the second previously-generated uniform random.
30367     if (x != null) y = x, x = null;
30368
30369     // Otherwise, generate a new x and y.
30370     else do {
30371       x = Math.random() * 2 - 1;
30372       y = Math.random() * 2 - 1;
30373       r = x * x + y * y;
30374     } while (!r || r > 1);
30375
30376     return mu + sigma * y * Math.sqrt(-2 * Math.log(r) / r);
30377   };
30378 };
30379
30380 var logNormal = function() {
30381   var randomNormal = normal.apply(this, arguments);
30382   return function() {
30383     return Math.exp(randomNormal());
30384   };
30385 };
30386
30387 var irwinHall = function(n) {
30388   return function() {
30389     for (var sum = 0, i = 0; i < n; ++i) sum += Math.random();
30390     return sum;
30391   };
30392 };
30393
30394 var bates = function(n) {
30395   var randomIrwinHall = irwinHall(n);
30396   return function() {
30397     return randomIrwinHall() / n;
30398   };
30399 };
30400
30401 var exponential$1 = function(lambda) {
30402   return function() {
30403     return -Math.log(1 - Math.random()) / lambda;
30404   };
30405 };
30406
30407 var request = function(url, callback) {
30408   var request,
30409       event = dispatch("beforesend", "progress", "load", "error"),
30410       mimeType,
30411       headers = map$1(),
30412       xhr = new XMLHttpRequest,
30413       user = null,
30414       password = null,
30415       response,
30416       responseType,
30417       timeout = 0;
30418
30419   // If IE does not support CORS, use XDomainRequest.
30420   if (typeof XDomainRequest !== "undefined"
30421       && !("withCredentials" in xhr)
30422       && /^(http(s)?:)?\/\//.test(url)) xhr = new XDomainRequest;
30423
30424   "onload" in xhr
30425       ? xhr.onload = xhr.onerror = xhr.ontimeout = respond
30426       : xhr.onreadystatechange = function(o) { xhr.readyState > 3 && respond(o); };
30427
30428   function respond(o) {
30429     var status = xhr.status, result;
30430     if (!status && hasResponse(xhr)
30431         || status >= 200 && status < 300
30432         || status === 304) {
30433       if (response) {
30434         try {
30435           result = response.call(request, xhr);
30436         } catch (e) {
30437           event.call("error", request, e);
30438           return;
30439         }
30440       } else {
30441         result = xhr;
30442       }
30443       event.call("load", request, result);
30444     } else {
30445       event.call("error", request, o);
30446     }
30447   }
30448
30449   xhr.onprogress = function(e) {
30450     event.call("progress", request, e);
30451   };
30452
30453   request = {
30454     header: function(name, value) {
30455       name = (name + "").toLowerCase();
30456       if (arguments.length < 2) return headers.get(name);
30457       if (value == null) headers.remove(name);
30458       else headers.set(name, value + "");
30459       return request;
30460     },
30461
30462     // If mimeType is non-null and no Accept header is set, a default is used.
30463     mimeType: function(value) {
30464       if (!arguments.length) return mimeType;
30465       mimeType = value == null ? null : value + "";
30466       return request;
30467     },
30468
30469     // Specifies what type the response value should take;
30470     // for instance, arraybuffer, blob, document, or text.
30471     responseType: function(value) {
30472       if (!arguments.length) return responseType;
30473       responseType = value;
30474       return request;
30475     },
30476
30477     timeout: function(value) {
30478       if (!arguments.length) return timeout;
30479       timeout = +value;
30480       return request;
30481     },
30482
30483     user: function(value) {
30484       return arguments.length < 1 ? user : (user = value == null ? null : value + "", request);
30485     },
30486
30487     password: function(value) {
30488       return arguments.length < 1 ? password : (password = value == null ? null : value + "", request);
30489     },
30490
30491     // Specify how to convert the response content to a specific type;
30492     // changes the callback value on "load" events.
30493     response: function(value) {
30494       response = value;
30495       return request;
30496     },
30497
30498     // Alias for send("GET", …).
30499     get: function(data, callback) {
30500       return request.send("GET", data, callback);
30501     },
30502
30503     // Alias for send("POST", …).
30504     post: function(data, callback) {
30505       return request.send("POST", data, callback);
30506     },
30507
30508     // If callback is non-null, it will be used for error and load events.
30509     send: function(method, data, callback) {
30510       xhr.open(method, url, true, user, password);
30511       if (mimeType != null && !headers.has("accept")) headers.set("accept", mimeType + ",*/*");
30512       if (xhr.setRequestHeader) headers.each(function(value, name) { xhr.setRequestHeader(name, value); });
30513       if (mimeType != null && xhr.overrideMimeType) xhr.overrideMimeType(mimeType);
30514       if (responseType != null) xhr.responseType = responseType;
30515       if (timeout > 0) xhr.timeout = timeout;
30516       if (callback == null && typeof data === "function") callback = data, data = null;
30517       if (callback != null && callback.length === 1) callback = fixCallback(callback);
30518       if (callback != null) request.on("error", callback).on("load", function(xhr) { callback(null, xhr); });
30519       event.call("beforesend", request, xhr);
30520       xhr.send(data == null ? null : data);
30521       return request;
30522     },
30523
30524     abort: function() {
30525       xhr.abort();
30526       return request;
30527     },
30528
30529     on: function() {
30530       var value = event.on.apply(event, arguments);
30531       return value === event ? request : value;
30532     }
30533   };
30534
30535   if (callback != null) {
30536     if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30537     return request.get(callback);
30538   }
30539
30540   return request;
30541 };
30542
30543 function fixCallback(callback) {
30544   return function(error, xhr) {
30545     callback(error == null ? xhr : null);
30546   };
30547 }
30548
30549 function hasResponse(xhr) {
30550   var type = xhr.responseType;
30551   return type && type !== "text"
30552       ? xhr.response // null on error
30553       : xhr.responseText; // "" on error
30554 }
30555
30556 var type$3 = function(defaultMimeType, response) {
30557   return function(url, callback) {
30558     var r = request(url).mimeType(defaultMimeType).response(response);
30559     if (callback != null) {
30560       if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30561       return r.get(callback);
30562     }
30563     return r;
30564   };
30565 };
30566
30567 var html = type$3("text/html", function(xhr) {
30568   return document.createRange().createContextualFragment(xhr.responseText);
30569 });
30570
30571 var json = type$3("application/json", function(xhr) {
30572   return JSON.parse(xhr.responseText);
30573 });
30574
30575 var text = type$3("text/plain", function(xhr) {
30576   return xhr.responseText;
30577 });
30578
30579 var xml = type$3("application/xml", function(xhr) {
30580   var xml = xhr.responseXML;
30581   if (!xml) throw new Error("parse error");
30582   return xml;
30583 });
30584
30585 var dsv$1 = function(defaultMimeType, parse) {
30586   return function(url, row, callback) {
30587     if (arguments.length < 3) callback = row, row = null;
30588     var r = request(url).mimeType(defaultMimeType);
30589     r.row = function(_) { return arguments.length ? r.response(responseOf(parse, row = _)) : row; };
30590     r.row(row);
30591     return callback ? r.get(callback) : r;
30592   };
30593 };
30594
30595 function responseOf(parse, row) {
30596   return function(request$$1) {
30597     return parse(request$$1.responseText, row);
30598   };
30599 }
30600
30601 var csv$1 = dsv$1("text/csv", csvParse);
30602
30603 var tsv$1 = dsv$1("text/tab-separated-values", tsvParse);
30604
30605 var array$2 = Array.prototype;
30606
30607 var map$3 = array$2.map;
30608 var slice$4 = array$2.slice;
30609
30610 var implicit = {name: "implicit"};
30611
30612 function ordinal(range) {
30613   var index = map$1(),
30614       domain = [],
30615       unknown = implicit;
30616
30617   range = range == null ? [] : slice$4.call(range);
30618
30619   function scale(d) {
30620     var key = d + "", i = index.get(key);
30621     if (!i) {
30622       if (unknown !== implicit) return unknown;
30623       index.set(key, i = domain.push(d));
30624     }
30625     return range[(i - 1) % range.length];
30626   }
30627
30628   scale.domain = function(_) {
30629     if (!arguments.length) return domain.slice();
30630     domain = [], index = map$1();
30631     var i = -1, n = _.length, d, key;
30632     while (++i < n) if (!index.has(key = (d = _[i]) + "")) index.set(key, domain.push(d));
30633     return scale;
30634   };
30635
30636   scale.range = function(_) {
30637     return arguments.length ? (range = slice$4.call(_), scale) : range.slice();
30638   };
30639
30640   scale.unknown = function(_) {
30641     return arguments.length ? (unknown = _, scale) : unknown;
30642   };
30643
30644   scale.copy = function() {
30645     return ordinal()
30646         .domain(domain)
30647         .range(range)
30648         .unknown(unknown);
30649   };
30650
30651   return scale;
30652 }
30653
30654 function band() {
30655   var scale = ordinal().unknown(undefined),
30656       domain = scale.domain,
30657       ordinalRange = scale.range,
30658       range$$1 = [0, 1],
30659       step,
30660       bandwidth,
30661       round = false,
30662       paddingInner = 0,
30663       paddingOuter = 0,
30664       align = 0.5;
30665
30666   delete scale.unknown;
30667
30668   function rescale() {
30669     var n = domain().length,
30670         reverse = range$$1[1] < range$$1[0],
30671         start = range$$1[reverse - 0],
30672         stop = range$$1[1 - reverse];
30673     step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
30674     if (round) step = Math.floor(step);
30675     start += (stop - start - step * (n - paddingInner)) * align;
30676     bandwidth = step * (1 - paddingInner);
30677     if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
30678     var values = sequence(n).map(function(i) { return start + step * i; });
30679     return ordinalRange(reverse ? values.reverse() : values);
30680   }
30681
30682   scale.domain = function(_) {
30683     return arguments.length ? (domain(_), rescale()) : domain();
30684   };
30685
30686   scale.range = function(_) {
30687     return arguments.length ? (range$$1 = [+_[0], +_[1]], rescale()) : range$$1.slice();
30688   };
30689
30690   scale.rangeRound = function(_) {
30691     return range$$1 = [+_[0], +_[1]], round = true, rescale();
30692   };
30693
30694   scale.bandwidth = function() {
30695     return bandwidth;
30696   };
30697
30698   scale.step = function() {
30699     return step;
30700   };
30701
30702   scale.round = function(_) {
30703     return arguments.length ? (round = !!_, rescale()) : round;
30704   };
30705
30706   scale.padding = function(_) {
30707     return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30708   };
30709
30710   scale.paddingInner = function(_) {
30711     return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30712   };
30713
30714   scale.paddingOuter = function(_) {
30715     return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter;
30716   };
30717
30718   scale.align = function(_) {
30719     return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
30720   };
30721
30722   scale.copy = function() {
30723     return band()
30724         .domain(domain())
30725         .range(range$$1)
30726         .round(round)
30727         .paddingInner(paddingInner)
30728         .paddingOuter(paddingOuter)
30729         .align(align);
30730   };
30731
30732   return rescale();
30733 }
30734
30735 function pointish(scale) {
30736   var copy = scale.copy;
30737
30738   scale.padding = scale.paddingOuter;
30739   delete scale.paddingInner;
30740   delete scale.paddingOuter;
30741
30742   scale.copy = function() {
30743     return pointish(copy());
30744   };
30745
30746   return scale;
30747 }
30748
30749 function point$1() {
30750   return pointish(band().paddingInner(1));
30751 }
30752
30753 var constant$9 = function(x) {
30754   return function() {
30755     return x;
30756   };
30757 };
30758
30759 var number$1 = function(x) {
30760   return +x;
30761 };
30762
30763 var unit = [0, 1];
30764
30765 function deinterpolateLinear(a, b) {
30766   return (b -= (a = +a))
30767       ? function(x) { return (x - a) / b; }
30768       : constant$9(b);
30769 }
30770
30771 function deinterpolateClamp(deinterpolate) {
30772   return function(a, b) {
30773     var d = deinterpolate(a = +a, b = +b);
30774     return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
30775   };
30776 }
30777
30778 function reinterpolateClamp(reinterpolate) {
30779   return function(a, b) {
30780     var r = reinterpolate(a = +a, b = +b);
30781     return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
30782   };
30783 }
30784
30785 function bimap(domain, range$$1, deinterpolate, reinterpolate) {
30786   var d0 = domain[0], d1 = domain[1], r0 = range$$1[0], r1 = range$$1[1];
30787   if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0);
30788   else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1);
30789   return function(x) { return r0(d0(x)); };
30790 }
30791
30792 function polymap(domain, range$$1, deinterpolate, reinterpolate) {
30793   var j = Math.min(domain.length, range$$1.length) - 1,
30794       d = new Array(j),
30795       r = new Array(j),
30796       i = -1;
30797
30798   // Reverse descending domains.
30799   if (domain[j] < domain[0]) {
30800     domain = domain.slice().reverse();
30801     range$$1 = range$$1.slice().reverse();
30802   }
30803
30804   while (++i < j) {
30805     d[i] = deinterpolate(domain[i], domain[i + 1]);
30806     r[i] = reinterpolate(range$$1[i], range$$1[i + 1]);
30807   }
30808
30809   return function(x) {
30810     var i = bisectRight(domain, x, 1, j) - 1;
30811     return r[i](d[i](x));
30812   };
30813 }
30814
30815 function copy(source, target) {
30816   return target
30817       .domain(source.domain())
30818       .range(source.range())
30819       .interpolate(source.interpolate())
30820       .clamp(source.clamp());
30821 }
30822
30823 // deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
30824 // reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
30825 function continuous(deinterpolate, reinterpolate) {
30826   var domain = unit,
30827       range$$1 = unit,
30828       interpolate$$1 = interpolateValue,
30829       clamp = false,
30830       piecewise,
30831       output,
30832       input;
30833
30834   function rescale() {
30835     piecewise = Math.min(domain.length, range$$1.length) > 2 ? polymap : bimap;
30836     output = input = null;
30837     return scale;
30838   }
30839
30840   function scale(x) {
30841     return (output || (output = piecewise(domain, range$$1, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate$$1)))(+x);
30842   }
30843
30844   scale.invert = function(y) {
30845     return (input || (input = piecewise(range$$1, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y);
30846   };
30847
30848   scale.domain = function(_) {
30849     return arguments.length ? (domain = map$3.call(_, number$1), rescale()) : domain.slice();
30850   };
30851
30852   scale.range = function(_) {
30853     return arguments.length ? (range$$1 = slice$4.call(_), rescale()) : range$$1.slice();
30854   };
30855
30856   scale.rangeRound = function(_) {
30857     return range$$1 = slice$4.call(_), interpolate$$1 = interpolateRound, rescale();
30858   };
30859
30860   scale.clamp = function(_) {
30861     return arguments.length ? (clamp = !!_, rescale()) : clamp;
30862   };
30863
30864   scale.interpolate = function(_) {
30865     return arguments.length ? (interpolate$$1 = _, rescale()) : interpolate$$1;
30866   };
30867
30868   return rescale();
30869 }
30870
30871 var tickFormat = function(domain, count, specifier) {
30872   var start = domain[0],
30873       stop = domain[domain.length - 1],
30874       step = tickStep(start, stop, count == null ? 10 : count),
30875       precision;
30876   specifier = formatSpecifier(specifier == null ? ",f" : specifier);
30877   switch (specifier.type) {
30878     case "s": {
30879       var value = Math.max(Math.abs(start), Math.abs(stop));
30880       if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
30881       return formatPrefix(specifier, value);
30882     }
30883     case "":
30884     case "e":
30885     case "g":
30886     case "p":
30887     case "r": {
30888       if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
30889       break;
30890     }
30891     case "f":
30892     case "%": {
30893       if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
30894       break;
30895     }
30896   }
30897   return format(specifier);
30898 };
30899
30900 function linearish(scale) {
30901   var domain = scale.domain;
30902
30903   scale.ticks = function(count) {
30904     var d = domain();
30905     return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
30906   };
30907
30908   scale.tickFormat = function(count, specifier) {
30909     return tickFormat(domain(), count, specifier);
30910   };
30911
30912   scale.nice = function(count) {
30913     var d = domain(),
30914         i = d.length - 1,
30915         n = count == null ? 10 : count,
30916         start = d[0],
30917         stop = d[i],
30918         step = tickStep(start, stop, n);
30919
30920     if (step) {
30921       step = tickStep(Math.floor(start / step) * step, Math.ceil(stop / step) * step, n);
30922       d[0] = Math.floor(start / step) * step;
30923       d[i] = Math.ceil(stop / step) * step;
30924       domain(d);
30925     }
30926
30927     return scale;
30928   };
30929
30930   return scale;
30931 }
30932
30933 function linear$2() {
30934   var scale = continuous(deinterpolateLinear, reinterpolate);
30935
30936   scale.copy = function() {
30937     return copy(scale, linear$2());
30938   };
30939
30940   return linearish(scale);
30941 }
30942
30943 function identity$6() {
30944   var domain = [0, 1];
30945
30946   function scale(x) {
30947     return +x;
30948   }
30949
30950   scale.invert = scale;
30951
30952   scale.domain = scale.range = function(_) {
30953     return arguments.length ? (domain = map$3.call(_, number$1), scale) : domain.slice();
30954   };
30955
30956   scale.copy = function() {
30957     return identity$6().domain(domain);
30958   };
30959
30960   return linearish(scale);
30961 }
30962
30963 var nice = function(domain, interval) {
30964   domain = domain.slice();
30965
30966   var i0 = 0,
30967       i1 = domain.length - 1,
30968       x0 = domain[i0],
30969       x1 = domain[i1],
30970       t;
30971
30972   if (x1 < x0) {
30973     t = i0, i0 = i1, i1 = t;
30974     t = x0, x0 = x1, x1 = t;
30975   }
30976
30977   domain[i0] = interval.floor(x0);
30978   domain[i1] = interval.ceil(x1);
30979   return domain;
30980 };
30981
30982 function deinterpolate(a, b) {
30983   return (b = Math.log(b / a))
30984       ? function(x) { return Math.log(x / a) / b; }
30985       : constant$9(b);
30986 }
30987
30988 function reinterpolate$1(a, b) {
30989   return a < 0
30990       ? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); }
30991       : function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); };
30992 }
30993
30994 function pow10(x) {
30995   return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
30996 }
30997
30998 function powp(base) {
30999   return base === 10 ? pow10
31000       : base === Math.E ? Math.exp
31001       : function(x) { return Math.pow(base, x); };
31002 }
31003
31004 function logp(base) {
31005   return base === Math.E ? Math.log
31006       : base === 10 && Math.log10
31007       || base === 2 && Math.log2
31008       || (base = Math.log(base), function(x) { return Math.log(x) / base; });
31009 }
31010
31011 function reflect(f) {
31012   return function(x) {
31013     return -f(-x);
31014   };
31015 }
31016
31017 function log$1() {
31018   var scale = continuous(deinterpolate, reinterpolate$1).domain([1, 10]),
31019       domain = scale.domain,
31020       base = 10,
31021       logs = logp(10),
31022       pows = powp(10);
31023
31024   function rescale() {
31025     logs = logp(base), pows = powp(base);
31026     if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows);
31027     return scale;
31028   }
31029
31030   scale.base = function(_) {
31031     return arguments.length ? (base = +_, rescale()) : base;
31032   };
31033
31034   scale.domain = function(_) {
31035     return arguments.length ? (domain(_), rescale()) : domain();
31036   };
31037
31038   scale.ticks = function(count) {
31039     var d = domain(),
31040         u = d[0],
31041         v = d[d.length - 1],
31042         r;
31043
31044     if (r = v < u) i = u, u = v, v = i;
31045
31046     var i = logs(u),
31047         j = logs(v),
31048         p,
31049         k,
31050         t,
31051         n = count == null ? 10 : +count,
31052         z = [];
31053
31054     if (!(base % 1) && j - i < n) {
31055       i = Math.round(i) - 1, j = Math.round(j) + 1;
31056       if (u > 0) for (; i < j; ++i) {
31057         for (k = 1, p = pows(i); k < base; ++k) {
31058           t = p * k;
31059           if (t < u) continue;
31060           if (t > v) break;
31061           z.push(t);
31062         }
31063       } else for (; i < j; ++i) {
31064         for (k = base - 1, p = pows(i); k >= 1; --k) {
31065           t = p * k;
31066           if (t < u) continue;
31067           if (t > v) break;
31068           z.push(t);
31069         }
31070       }
31071     } else {
31072       z = ticks(i, j, Math.min(j - i, n)).map(pows);
31073     }
31074
31075     return r ? z.reverse() : z;
31076   };
31077
31078   scale.tickFormat = function(count, specifier) {
31079     if (specifier == null) specifier = base === 10 ? ".0e" : ",";
31080     if (typeof specifier !== "function") specifier = format(specifier);
31081     if (count === Infinity) return specifier;
31082     if (count == null) count = 10;
31083     var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
31084     return function(d) {
31085       var i = d / pows(Math.round(logs(d)));
31086       if (i * base < base - 0.5) i *= base;
31087       return i <= k ? specifier(d) : "";
31088     };
31089   };
31090
31091   scale.nice = function() {
31092     return domain(nice(domain(), {
31093       floor: function(x) { return pows(Math.floor(logs(x))); },
31094       ceil: function(x) { return pows(Math.ceil(logs(x))); }
31095     }));
31096   };
31097
31098   scale.copy = function() {
31099     return copy(scale, log$1().base(base));
31100   };
31101
31102   return scale;
31103 }
31104
31105 function raise$1(x, exponent) {
31106   return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
31107 }
31108
31109 function pow$1() {
31110   var exponent = 1,
31111       scale = continuous(deinterpolate, reinterpolate),
31112       domain = scale.domain;
31113
31114   function deinterpolate(a, b) {
31115     return (b = raise$1(b, exponent) - (a = raise$1(a, exponent)))
31116         ? function(x) { return (raise$1(x, exponent) - a) / b; }
31117         : constant$9(b);
31118   }
31119
31120   function reinterpolate(a, b) {
31121     b = raise$1(b, exponent) - (a = raise$1(a, exponent));
31122     return function(t) { return raise$1(a + b * t, 1 / exponent); };
31123   }
31124
31125   scale.exponent = function(_) {
31126     return arguments.length ? (exponent = +_, domain(domain())) : exponent;
31127   };
31128
31129   scale.copy = function() {
31130     return copy(scale, pow$1().exponent(exponent));
31131   };
31132
31133   return linearish(scale);
31134 }
31135
31136 function sqrt$1() {
31137   return pow$1().exponent(0.5);
31138 }
31139
31140 function quantile$$1() {
31141   var domain = [],
31142       range$$1 = [],
31143       thresholds = [];
31144
31145   function rescale() {
31146     var i = 0, n = Math.max(1, range$$1.length);
31147     thresholds = new Array(n - 1);
31148     while (++i < n) thresholds[i - 1] = threshold(domain, i / n);
31149     return scale;
31150   }
31151
31152   function scale(x) {
31153     if (!isNaN(x = +x)) return range$$1[bisectRight(thresholds, x)];
31154   }
31155
31156   scale.invertExtent = function(y) {
31157     var i = range$$1.indexOf(y);
31158     return i < 0 ? [NaN, NaN] : [
31159       i > 0 ? thresholds[i - 1] : domain[0],
31160       i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
31161     ];
31162   };
31163
31164   scale.domain = function(_) {
31165     if (!arguments.length) return domain.slice();
31166     domain = [];
31167     for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);
31168     domain.sort(ascending);
31169     return rescale();
31170   };
31171
31172   scale.range = function(_) {
31173     return arguments.length ? (range$$1 = slice$4.call(_), rescale()) : range$$1.slice();
31174   };
31175
31176   scale.quantiles = function() {
31177     return thresholds.slice();
31178   };
31179
31180   scale.copy = function() {
31181     return quantile$$1()
31182         .domain(domain)
31183         .range(range$$1);
31184   };
31185
31186   return scale;
31187 }
31188
31189 function quantize$1() {
31190   var x0 = 0,
31191       x1 = 1,
31192       n = 1,
31193       domain = [0.5],
31194       range$$1 = [0, 1];
31195
31196   function scale(x) {
31197     if (x <= x) return range$$1[bisectRight(domain, x, 0, n)];
31198   }
31199
31200   function rescale() {
31201     var i = -1;
31202     domain = new Array(n);
31203     while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
31204     return scale;
31205   }
31206
31207   scale.domain = function(_) {
31208     return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1];
31209   };
31210
31211   scale.range = function(_) {
31212     return arguments.length ? (n = (range$$1 = slice$4.call(_)).length - 1, rescale()) : range$$1.slice();
31213   };
31214
31215   scale.invertExtent = function(y) {
31216     var i = range$$1.indexOf(y);
31217     return i < 0 ? [NaN, NaN]
31218         : i < 1 ? [x0, domain[0]]
31219         : i >= n ? [domain[n - 1], x1]
31220         : [domain[i - 1], domain[i]];
31221   };
31222
31223   scale.copy = function() {
31224     return quantize$1()
31225         .domain([x0, x1])
31226         .range(range$$1);
31227   };
31228
31229   return linearish(scale);
31230 }
31231
31232 function threshold$1() {
31233   var domain = [0.5],
31234       range$$1 = [0, 1],
31235       n = 1;
31236
31237   function scale(x) {
31238     if (x <= x) return range$$1[bisectRight(domain, x, 0, n)];
31239   }
31240
31241   scale.domain = function(_) {
31242     return arguments.length ? (domain = slice$4.call(_), n = Math.min(domain.length, range$$1.length - 1), scale) : domain.slice();
31243   };
31244
31245   scale.range = function(_) {
31246     return arguments.length ? (range$$1 = slice$4.call(_), n = Math.min(domain.length, range$$1.length - 1), scale) : range$$1.slice();
31247   };
31248
31249   scale.invertExtent = function(y) {
31250     var i = range$$1.indexOf(y);
31251     return [domain[i - 1], domain[i]];
31252   };
31253
31254   scale.copy = function() {
31255     return threshold$1()
31256         .domain(domain)
31257         .range(range$$1);
31258   };
31259
31260   return scale;
31261 }
31262
31263 var t0$1 = new Date;
31264 var t1$1 = new Date;
31265
31266 function newInterval(floori, offseti, count, field) {
31267
31268   function interval(date) {
31269     return floori(date = new Date(+date)), date;
31270   }
31271
31272   interval.floor = interval;
31273
31274   interval.ceil = function(date) {
31275     return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
31276   };
31277
31278   interval.round = function(date) {
31279     var d0 = interval(date),
31280         d1 = interval.ceil(date);
31281     return date - d0 < d1 - date ? d0 : d1;
31282   };
31283
31284   interval.offset = function(date, step) {
31285     return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
31286   };
31287
31288   interval.range = function(start, stop, step) {
31289     var range = [];
31290     start = interval.ceil(start);
31291     step = step == null ? 1 : Math.floor(step);
31292     if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
31293     do range.push(new Date(+start)); while (offseti(start, step), floori(start), start < stop)
31294     return range;
31295   };
31296
31297   interval.filter = function(test) {
31298     return newInterval(function(date) {
31299       if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);
31300     }, function(date, step) {
31301       if (date >= date) while (--step >= 0) while (offseti(date, 1), !test(date)) {} // eslint-disable-line no-empty
31302     });
31303   };
31304
31305   if (count) {
31306     interval.count = function(start, end) {
31307       t0$1.setTime(+start), t1$1.setTime(+end);
31308       floori(t0$1), floori(t1$1);
31309       return Math.floor(count(t0$1, t1$1));
31310     };
31311
31312     interval.every = function(step) {
31313       step = Math.floor(step);
31314       return !isFinite(step) || !(step > 0) ? null
31315           : !(step > 1) ? interval
31316           : interval.filter(field
31317               ? function(d) { return field(d) % step === 0; }
31318               : function(d) { return interval.count(0, d) % step === 0; });
31319     };
31320   }
31321
31322   return interval;
31323 }
31324
31325 var millisecond = newInterval(function() {
31326   // noop
31327 }, function(date, step) {
31328   date.setTime(+date + step);
31329 }, function(start, end) {
31330   return end - start;
31331 });
31332
31333 // An optimized implementation for this simple case.
31334 millisecond.every = function(k) {
31335   k = Math.floor(k);
31336   if (!isFinite(k) || !(k > 0)) return null;
31337   if (!(k > 1)) return millisecond;
31338   return newInterval(function(date) {
31339     date.setTime(Math.floor(date / k) * k);
31340   }, function(date, step) {
31341     date.setTime(+date + step * k);
31342   }, function(start, end) {
31343     return (end - start) / k;
31344   });
31345 };
31346
31347 var milliseconds = millisecond.range;
31348
31349 var durationSecond$1 = 1e3;
31350 var durationMinute$1 = 6e4;
31351 var durationHour$1 = 36e5;
31352 var durationDay$1 = 864e5;
31353 var durationWeek$1 = 6048e5;
31354
31355 var second = newInterval(function(date) {
31356   date.setTime(Math.floor(date / durationSecond$1) * durationSecond$1);
31357 }, function(date, step) {
31358   date.setTime(+date + step * durationSecond$1);
31359 }, function(start, end) {
31360   return (end - start) / durationSecond$1;
31361 }, function(date) {
31362   return date.getUTCSeconds();
31363 });
31364
31365 var seconds = second.range;
31366
31367 var minute = newInterval(function(date) {
31368   date.setTime(Math.floor(date / durationMinute$1) * durationMinute$1);
31369 }, function(date, step) {
31370   date.setTime(+date + step * durationMinute$1);
31371 }, function(start, end) {
31372   return (end - start) / durationMinute$1;
31373 }, function(date) {
31374   return date.getMinutes();
31375 });
31376
31377 var minutes = minute.range;
31378
31379 var hour = newInterval(function(date) {
31380   var offset = date.getTimezoneOffset() * durationMinute$1 % durationHour$1;
31381   if (offset < 0) offset += durationHour$1;
31382   date.setTime(Math.floor((+date - offset) / durationHour$1) * durationHour$1 + offset);
31383 }, function(date, step) {
31384   date.setTime(+date + step * durationHour$1);
31385 }, function(start, end) {
31386   return (end - start) / durationHour$1;
31387 }, function(date) {
31388   return date.getHours();
31389 });
31390
31391 var hours = hour.range;
31392
31393 var day = newInterval(function(date) {
31394   date.setHours(0, 0, 0, 0);
31395 }, function(date, step) {
31396   date.setDate(date.getDate() + step);
31397 }, function(start, end) {
31398   return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationDay$1;
31399 }, function(date) {
31400   return date.getDate() - 1;
31401 });
31402
31403 var days = day.range;
31404
31405 function weekday(i) {
31406   return newInterval(function(date) {
31407     date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
31408     date.setHours(0, 0, 0, 0);
31409   }, function(date, step) {
31410     date.setDate(date.getDate() + step * 7);
31411   }, function(start, end) {
31412     return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationWeek$1;
31413   });
31414 }
31415
31416 var sunday = weekday(0);
31417 var monday = weekday(1);
31418 var tuesday = weekday(2);
31419 var wednesday = weekday(3);
31420 var thursday = weekday(4);
31421 var friday = weekday(5);
31422 var saturday = weekday(6);
31423
31424 var sundays = sunday.range;
31425 var mondays = monday.range;
31426 var tuesdays = tuesday.range;
31427 var wednesdays = wednesday.range;
31428 var thursdays = thursday.range;
31429 var fridays = friday.range;
31430 var saturdays = saturday.range;
31431
31432 var month = newInterval(function(date) {
31433   date.setDate(1);
31434   date.setHours(0, 0, 0, 0);
31435 }, function(date, step) {
31436   date.setMonth(date.getMonth() + step);
31437 }, function(start, end) {
31438   return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
31439 }, function(date) {
31440   return date.getMonth();
31441 });
31442
31443 var months = month.range;
31444
31445 var year = newInterval(function(date) {
31446   date.setMonth(0, 1);
31447   date.setHours(0, 0, 0, 0);
31448 }, function(date, step) {
31449   date.setFullYear(date.getFullYear() + step);
31450 }, function(start, end) {
31451   return end.getFullYear() - start.getFullYear();
31452 }, function(date) {
31453   return date.getFullYear();
31454 });
31455
31456 // An optimized implementation for this simple case.
31457 year.every = function(k) {
31458   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31459     date.setFullYear(Math.floor(date.getFullYear() / k) * k);
31460     date.setMonth(0, 1);
31461     date.setHours(0, 0, 0, 0);
31462   }, function(date, step) {
31463     date.setFullYear(date.getFullYear() + step * k);
31464   });
31465 };
31466
31467 var years = year.range;
31468
31469 var utcMinute = newInterval(function(date) {
31470   date.setUTCSeconds(0, 0);
31471 }, function(date, step) {
31472   date.setTime(+date + step * durationMinute$1);
31473 }, function(start, end) {
31474   return (end - start) / durationMinute$1;
31475 }, function(date) {
31476   return date.getUTCMinutes();
31477 });
31478
31479 var utcMinutes = utcMinute.range;
31480
31481 var utcHour = newInterval(function(date) {
31482   date.setUTCMinutes(0, 0, 0);
31483 }, function(date, step) {
31484   date.setTime(+date + step * durationHour$1);
31485 }, function(start, end) {
31486   return (end - start) / durationHour$1;
31487 }, function(date) {
31488   return date.getUTCHours();
31489 });
31490
31491 var utcHours = utcHour.range;
31492
31493 var utcDay = newInterval(function(date) {
31494   date.setUTCHours(0, 0, 0, 0);
31495 }, function(date, step) {
31496   date.setUTCDate(date.getUTCDate() + step);
31497 }, function(start, end) {
31498   return (end - start) / durationDay$1;
31499 }, function(date) {
31500   return date.getUTCDate() - 1;
31501 });
31502
31503 var utcDays = utcDay.range;
31504
31505 function utcWeekday(i) {
31506   return newInterval(function(date) {
31507     date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
31508     date.setUTCHours(0, 0, 0, 0);
31509   }, function(date, step) {
31510     date.setUTCDate(date.getUTCDate() + step * 7);
31511   }, function(start, end) {
31512     return (end - start) / durationWeek$1;
31513   });
31514 }
31515
31516 var utcSunday = utcWeekday(0);
31517 var utcMonday = utcWeekday(1);
31518 var utcTuesday = utcWeekday(2);
31519 var utcWednesday = utcWeekday(3);
31520 var utcThursday = utcWeekday(4);
31521 var utcFriday = utcWeekday(5);
31522 var utcSaturday = utcWeekday(6);
31523
31524 var utcSundays = utcSunday.range;
31525 var utcMondays = utcMonday.range;
31526 var utcTuesdays = utcTuesday.range;
31527 var utcWednesdays = utcWednesday.range;
31528 var utcThursdays = utcThursday.range;
31529 var utcFridays = utcFriday.range;
31530 var utcSaturdays = utcSaturday.range;
31531
31532 var utcMonth = newInterval(function(date) {
31533   date.setUTCDate(1);
31534   date.setUTCHours(0, 0, 0, 0);
31535 }, function(date, step) {
31536   date.setUTCMonth(date.getUTCMonth() + step);
31537 }, function(start, end) {
31538   return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
31539 }, function(date) {
31540   return date.getUTCMonth();
31541 });
31542
31543 var utcMonths = utcMonth.range;
31544
31545 var utcYear = newInterval(function(date) {
31546   date.setUTCMonth(0, 1);
31547   date.setUTCHours(0, 0, 0, 0);
31548 }, function(date, step) {
31549   date.setUTCFullYear(date.getUTCFullYear() + step);
31550 }, function(start, end) {
31551   return end.getUTCFullYear() - start.getUTCFullYear();
31552 }, function(date) {
31553   return date.getUTCFullYear();
31554 });
31555
31556 // An optimized implementation for this simple case.
31557 utcYear.every = function(k) {
31558   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31559     date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
31560     date.setUTCMonth(0, 1);
31561     date.setUTCHours(0, 0, 0, 0);
31562   }, function(date, step) {
31563     date.setUTCFullYear(date.getUTCFullYear() + step * k);
31564   });
31565 };
31566
31567 var utcYears = utcYear.range;
31568
31569 function localDate(d) {
31570   if (0 <= d.y && d.y < 100) {
31571     var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);
31572     date.setFullYear(d.y);
31573     return date;
31574   }
31575   return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);
31576 }
31577
31578 function utcDate(d) {
31579   if (0 <= d.y && d.y < 100) {
31580     var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));
31581     date.setUTCFullYear(d.y);
31582     return date;
31583   }
31584   return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
31585 }
31586
31587 function newYear(y) {
31588   return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0};
31589 }
31590
31591 function formatLocale$1(locale) {
31592   var locale_dateTime = locale.dateTime,
31593       locale_date = locale.date,
31594       locale_time = locale.time,
31595       locale_periods = locale.periods,
31596       locale_weekdays = locale.days,
31597       locale_shortWeekdays = locale.shortDays,
31598       locale_months = locale.months,
31599       locale_shortMonths = locale.shortMonths;
31600
31601   var periodRe = formatRe(locale_periods),
31602       periodLookup = formatLookup(locale_periods),
31603       weekdayRe = formatRe(locale_weekdays),
31604       weekdayLookup = formatLookup(locale_weekdays),
31605       shortWeekdayRe = formatRe(locale_shortWeekdays),
31606       shortWeekdayLookup = formatLookup(locale_shortWeekdays),
31607       monthRe = formatRe(locale_months),
31608       monthLookup = formatLookup(locale_months),
31609       shortMonthRe = formatRe(locale_shortMonths),
31610       shortMonthLookup = formatLookup(locale_shortMonths);
31611
31612   var formats = {
31613     "a": formatShortWeekday,
31614     "A": formatWeekday,
31615     "b": formatShortMonth,
31616     "B": formatMonth,
31617     "c": null,
31618     "d": formatDayOfMonth,
31619     "e": formatDayOfMonth,
31620     "H": formatHour24,
31621     "I": formatHour12,
31622     "j": formatDayOfYear,
31623     "L": formatMilliseconds,
31624     "m": formatMonthNumber,
31625     "M": formatMinutes,
31626     "p": formatPeriod,
31627     "S": formatSeconds,
31628     "U": formatWeekNumberSunday,
31629     "w": formatWeekdayNumber,
31630     "W": formatWeekNumberMonday,
31631     "x": null,
31632     "X": null,
31633     "y": formatYear,
31634     "Y": formatFullYear,
31635     "Z": formatZone,
31636     "%": formatLiteralPercent
31637   };
31638
31639   var utcFormats = {
31640     "a": formatUTCShortWeekday,
31641     "A": formatUTCWeekday,
31642     "b": formatUTCShortMonth,
31643     "B": formatUTCMonth,
31644     "c": null,
31645     "d": formatUTCDayOfMonth,
31646     "e": formatUTCDayOfMonth,
31647     "H": formatUTCHour24,
31648     "I": formatUTCHour12,
31649     "j": formatUTCDayOfYear,
31650     "L": formatUTCMilliseconds,
31651     "m": formatUTCMonthNumber,
31652     "M": formatUTCMinutes,
31653     "p": formatUTCPeriod,
31654     "S": formatUTCSeconds,
31655     "U": formatUTCWeekNumberSunday,
31656     "w": formatUTCWeekdayNumber,
31657     "W": formatUTCWeekNumberMonday,
31658     "x": null,
31659     "X": null,
31660     "y": formatUTCYear,
31661     "Y": formatUTCFullYear,
31662     "Z": formatUTCZone,
31663     "%": formatLiteralPercent
31664   };
31665
31666   var parses = {
31667     "a": parseShortWeekday,
31668     "A": parseWeekday,
31669     "b": parseShortMonth,
31670     "B": parseMonth,
31671     "c": parseLocaleDateTime,
31672     "d": parseDayOfMonth,
31673     "e": parseDayOfMonth,
31674     "H": parseHour24,
31675     "I": parseHour24,
31676     "j": parseDayOfYear,
31677     "L": parseMilliseconds,
31678     "m": parseMonthNumber,
31679     "M": parseMinutes,
31680     "p": parsePeriod,
31681     "S": parseSeconds,
31682     "U": parseWeekNumberSunday,
31683     "w": parseWeekdayNumber,
31684     "W": parseWeekNumberMonday,
31685     "x": parseLocaleDate,
31686     "X": parseLocaleTime,
31687     "y": parseYear,
31688     "Y": parseFullYear,
31689     "Z": parseZone,
31690     "%": parseLiteralPercent
31691   };
31692
31693   // These recursive directive definitions must be deferred.
31694   formats.x = newFormat(locale_date, formats);
31695   formats.X = newFormat(locale_time, formats);
31696   formats.c = newFormat(locale_dateTime, formats);
31697   utcFormats.x = newFormat(locale_date, utcFormats);
31698   utcFormats.X = newFormat(locale_time, utcFormats);
31699   utcFormats.c = newFormat(locale_dateTime, utcFormats);
31700
31701   function newFormat(specifier, formats) {
31702     return function(date) {
31703       var string = [],
31704           i = -1,
31705           j = 0,
31706           n = specifier.length,
31707           c,
31708           pad,
31709           format;
31710
31711       if (!(date instanceof Date)) date = new Date(+date);
31712
31713       while (++i < n) {
31714         if (specifier.charCodeAt(i) === 37) {
31715           string.push(specifier.slice(j, i));
31716           if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
31717           else pad = c === "e" ? " " : "0";
31718           if (format = formats[c]) c = format(date, pad);
31719           string.push(c);
31720           j = i + 1;
31721         }
31722       }
31723
31724       string.push(specifier.slice(j, i));
31725       return string.join("");
31726     };
31727   }
31728
31729   function newParse(specifier, newDate) {
31730     return function(string) {
31731       var d = newYear(1900),
31732           i = parseSpecifier(d, specifier, string += "", 0);
31733       if (i != string.length) return null;
31734
31735       // The am-pm flag is 0 for AM, and 1 for PM.
31736       if ("p" in d) d.H = d.H % 12 + d.p * 12;
31737
31738       // Convert day-of-week and week-of-year to day-of-year.
31739       if ("W" in d || "U" in d) {
31740         if (!("w" in d)) d.w = "W" in d ? 1 : 0;
31741         var day$$1 = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay();
31742         d.m = 0;
31743         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;
31744       }
31745
31746       // If a time zone is specified, all fields are interpreted as UTC and then
31747       // offset according to the specified time zone.
31748       if ("Z" in d) {
31749         d.H += d.Z / 100 | 0;
31750         d.M += d.Z % 100;
31751         return utcDate(d);
31752       }
31753
31754       // Otherwise, all fields are in local time.
31755       return newDate(d);
31756     };
31757   }
31758
31759   function parseSpecifier(d, specifier, string, j) {
31760     var i = 0,
31761         n = specifier.length,
31762         m = string.length,
31763         c,
31764         parse;
31765
31766     while (i < n) {
31767       if (j >= m) return -1;
31768       c = specifier.charCodeAt(i++);
31769       if (c === 37) {
31770         c = specifier.charAt(i++);
31771         parse = parses[c in pads ? specifier.charAt(i++) : c];
31772         if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
31773       } else if (c != string.charCodeAt(j++)) {
31774         return -1;
31775       }
31776     }
31777
31778     return j;
31779   }
31780
31781   function parsePeriod(d, string, i) {
31782     var n = periodRe.exec(string.slice(i));
31783     return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31784   }
31785
31786   function parseShortWeekday(d, string, i) {
31787     var n = shortWeekdayRe.exec(string.slice(i));
31788     return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31789   }
31790
31791   function parseWeekday(d, string, i) {
31792     var n = weekdayRe.exec(string.slice(i));
31793     return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31794   }
31795
31796   function parseShortMonth(d, string, i) {
31797     var n = shortMonthRe.exec(string.slice(i));
31798     return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31799   }
31800
31801   function parseMonth(d, string, i) {
31802     var n = monthRe.exec(string.slice(i));
31803     return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31804   }
31805
31806   function parseLocaleDateTime(d, string, i) {
31807     return parseSpecifier(d, locale_dateTime, string, i);
31808   }
31809
31810   function parseLocaleDate(d, string, i) {
31811     return parseSpecifier(d, locale_date, string, i);
31812   }
31813
31814   function parseLocaleTime(d, string, i) {
31815     return parseSpecifier(d, locale_time, string, i);
31816   }
31817
31818   function formatShortWeekday(d) {
31819     return locale_shortWeekdays[d.getDay()];
31820   }
31821
31822   function formatWeekday(d) {
31823     return locale_weekdays[d.getDay()];
31824   }
31825
31826   function formatShortMonth(d) {
31827     return locale_shortMonths[d.getMonth()];
31828   }
31829
31830   function formatMonth(d) {
31831     return locale_months[d.getMonth()];
31832   }
31833
31834   function formatPeriod(d) {
31835     return locale_periods[+(d.getHours() >= 12)];
31836   }
31837
31838   function formatUTCShortWeekday(d) {
31839     return locale_shortWeekdays[d.getUTCDay()];
31840   }
31841
31842   function formatUTCWeekday(d) {
31843     return locale_weekdays[d.getUTCDay()];
31844   }
31845
31846   function formatUTCShortMonth(d) {
31847     return locale_shortMonths[d.getUTCMonth()];
31848   }
31849
31850   function formatUTCMonth(d) {
31851     return locale_months[d.getUTCMonth()];
31852   }
31853
31854   function formatUTCPeriod(d) {
31855     return locale_periods[+(d.getUTCHours() >= 12)];
31856   }
31857
31858   return {
31859     format: function(specifier) {
31860       var f = newFormat(specifier += "", formats);
31861       f.toString = function() { return specifier; };
31862       return f;
31863     },
31864     parse: function(specifier) {
31865       var p = newParse(specifier += "", localDate);
31866       p.toString = function() { return specifier; };
31867       return p;
31868     },
31869     utcFormat: function(specifier) {
31870       var f = newFormat(specifier += "", utcFormats);
31871       f.toString = function() { return specifier; };
31872       return f;
31873     },
31874     utcParse: function(specifier) {
31875       var p = newParse(specifier, utcDate);
31876       p.toString = function() { return specifier; };
31877       return p;
31878     }
31879   };
31880 }
31881
31882 var pads = {"-": "", "_": " ", "0": "0"};
31883 var numberRe = /^\s*\d+/;
31884 var percentRe = /^%/;
31885 var requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
31886
31887 function pad(value, fill, width) {
31888   var sign = value < 0 ? "-" : "",
31889       string = (sign ? -value : value) + "",
31890       length = string.length;
31891   return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
31892 }
31893
31894 function requote(s) {
31895   return s.replace(requoteRe, "\\$&");
31896 }
31897
31898 function formatRe(names) {
31899   return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
31900 }
31901
31902 function formatLookup(names) {
31903   var map = {}, i = -1, n = names.length;
31904   while (++i < n) map[names[i].toLowerCase()] = i;
31905   return map;
31906 }
31907
31908 function parseWeekdayNumber(d, string, i) {
31909   var n = numberRe.exec(string.slice(i, i + 1));
31910   return n ? (d.w = +n[0], i + n[0].length) : -1;
31911 }
31912
31913 function parseWeekNumberSunday(d, string, i) {
31914   var n = numberRe.exec(string.slice(i));
31915   return n ? (d.U = +n[0], i + n[0].length) : -1;
31916 }
31917
31918 function parseWeekNumberMonday(d, string, i) {
31919   var n = numberRe.exec(string.slice(i));
31920   return n ? (d.W = +n[0], i + n[0].length) : -1;
31921 }
31922
31923 function parseFullYear(d, string, i) {
31924   var n = numberRe.exec(string.slice(i, i + 4));
31925   return n ? (d.y = +n[0], i + n[0].length) : -1;
31926 }
31927
31928 function parseYear(d, string, i) {
31929   var n = numberRe.exec(string.slice(i, i + 2));
31930   return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
31931 }
31932
31933 function parseZone(d, string, i) {
31934   var n = /^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(string.slice(i, i + 6));
31935   return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1;
31936 }
31937
31938 function parseMonthNumber(d, string, i) {
31939   var n = numberRe.exec(string.slice(i, i + 2));
31940   return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
31941 }
31942
31943 function parseDayOfMonth(d, string, i) {
31944   var n = numberRe.exec(string.slice(i, i + 2));
31945   return n ? (d.d = +n[0], i + n[0].length) : -1;
31946 }
31947
31948 function parseDayOfYear(d, string, i) {
31949   var n = numberRe.exec(string.slice(i, i + 3));
31950   return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;
31951 }
31952
31953 function parseHour24(d, string, i) {
31954   var n = numberRe.exec(string.slice(i, i + 2));
31955   return n ? (d.H = +n[0], i + n[0].length) : -1;
31956 }
31957
31958 function parseMinutes(d, string, i) {
31959   var n = numberRe.exec(string.slice(i, i + 2));
31960   return n ? (d.M = +n[0], i + n[0].length) : -1;
31961 }
31962
31963 function parseSeconds(d, string, i) {
31964   var n = numberRe.exec(string.slice(i, i + 2));
31965   return n ? (d.S = +n[0], i + n[0].length) : -1;
31966 }
31967
31968 function parseMilliseconds(d, string, i) {
31969   var n = numberRe.exec(string.slice(i, i + 3));
31970   return n ? (d.L = +n[0], i + n[0].length) : -1;
31971 }
31972
31973 function parseLiteralPercent(d, string, i) {
31974   var n = percentRe.exec(string.slice(i, i + 1));
31975   return n ? i + n[0].length : -1;
31976 }
31977
31978 function formatDayOfMonth(d, p) {
31979   return pad(d.getDate(), p, 2);
31980 }
31981
31982 function formatHour24(d, p) {
31983   return pad(d.getHours(), p, 2);
31984 }
31985
31986 function formatHour12(d, p) {
31987   return pad(d.getHours() % 12 || 12, p, 2);
31988 }
31989
31990 function formatDayOfYear(d, p) {
31991   return pad(1 + day.count(year(d), d), p, 3);
31992 }
31993
31994 function formatMilliseconds(d, p) {
31995   return pad(d.getMilliseconds(), p, 3);
31996 }
31997
31998 function formatMonthNumber(d, p) {
31999   return pad(d.getMonth() + 1, p, 2);
32000 }
32001
32002 function formatMinutes(d, p) {
32003   return pad(d.getMinutes(), p, 2);
32004 }
32005
32006 function formatSeconds(d, p) {
32007   return pad(d.getSeconds(), p, 2);
32008 }
32009
32010 function formatWeekNumberSunday(d, p) {
32011   return pad(sunday.count(year(d), d), p, 2);
32012 }
32013
32014 function formatWeekdayNumber(d) {
32015   return d.getDay();
32016 }
32017
32018 function formatWeekNumberMonday(d, p) {
32019   return pad(monday.count(year(d), d), p, 2);
32020 }
32021
32022 function formatYear(d, p) {
32023   return pad(d.getFullYear() % 100, p, 2);
32024 }
32025
32026 function formatFullYear(d, p) {
32027   return pad(d.getFullYear() % 10000, p, 4);
32028 }
32029
32030 function formatZone(d) {
32031   var z = d.getTimezoneOffset();
32032   return (z > 0 ? "-" : (z *= -1, "+"))
32033       + pad(z / 60 | 0, "0", 2)
32034       + pad(z % 60, "0", 2);
32035 }
32036
32037 function formatUTCDayOfMonth(d, p) {
32038   return pad(d.getUTCDate(), p, 2);
32039 }
32040
32041 function formatUTCHour24(d, p) {
32042   return pad(d.getUTCHours(), p, 2);
32043 }
32044
32045 function formatUTCHour12(d, p) {
32046   return pad(d.getUTCHours() % 12 || 12, p, 2);
32047 }
32048
32049 function formatUTCDayOfYear(d, p) {
32050   return pad(1 + utcDay.count(utcYear(d), d), p, 3);
32051 }
32052
32053 function formatUTCMilliseconds(d, p) {
32054   return pad(d.getUTCMilliseconds(), p, 3);
32055 }
32056
32057 function formatUTCMonthNumber(d, p) {
32058   return pad(d.getUTCMonth() + 1, p, 2);
32059 }
32060
32061 function formatUTCMinutes(d, p) {
32062   return pad(d.getUTCMinutes(), p, 2);
32063 }
32064
32065 function formatUTCSeconds(d, p) {
32066   return pad(d.getUTCSeconds(), p, 2);
32067 }
32068
32069 function formatUTCWeekNumberSunday(d, p) {
32070   return pad(utcSunday.count(utcYear(d), d), p, 2);
32071 }
32072
32073 function formatUTCWeekdayNumber(d) {
32074   return d.getUTCDay();
32075 }
32076
32077 function formatUTCWeekNumberMonday(d, p) {
32078   return pad(utcMonday.count(utcYear(d), d), p, 2);
32079 }
32080
32081 function formatUTCYear(d, p) {
32082   return pad(d.getUTCFullYear() % 100, p, 2);
32083 }
32084
32085 function formatUTCFullYear(d, p) {
32086   return pad(d.getUTCFullYear() % 10000, p, 4);
32087 }
32088
32089 function formatUTCZone() {
32090   return "+0000";
32091 }
32092
32093 function formatLiteralPercent() {
32094   return "%";
32095 }
32096
32097 var locale$2;
32098 var timeFormat;
32099 var timeParse;
32100 var utcFormat;
32101 var utcParse;
32102
32103 defaultLocale$1({
32104   dateTime: "%x, %X",
32105   date: "%-m/%-d/%Y",
32106   time: "%-I:%M:%S %p",
32107   periods: ["AM", "PM"],
32108   days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
32109   shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
32110   months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
32111   shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
32112 });
32113
32114 function defaultLocale$1(definition) {
32115   locale$2 = formatLocale$1(definition);
32116   timeFormat = locale$2.format;
32117   timeParse = locale$2.parse;
32118   utcFormat = locale$2.utcFormat;
32119   utcParse = locale$2.utcParse;
32120   return locale$2;
32121 }
32122
32123 var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ";
32124
32125 function formatIsoNative(date) {
32126   return date.toISOString();
32127 }
32128
32129 var formatIso = Date.prototype.toISOString
32130     ? formatIsoNative
32131     : utcFormat(isoSpecifier);
32132
32133 function parseIsoNative(string) {
32134   var date = new Date(string);
32135   return isNaN(date) ? null : date;
32136 }
32137
32138 var parseIso = +new Date("2000-01-01T00:00:00.000Z")
32139     ? parseIsoNative
32140     : utcParse(isoSpecifier);
32141
32142 var durationSecond = 1000;
32143 var durationMinute = durationSecond * 60;
32144 var durationHour = durationMinute * 60;
32145 var durationDay = durationHour * 24;
32146 var durationWeek = durationDay * 7;
32147 var durationMonth = durationDay * 30;
32148 var durationYear = durationDay * 365;
32149
32150 function date$1(t) {
32151   return new Date(t);
32152 }
32153
32154 function number$2(t) {
32155   return t instanceof Date ? +t : +new Date(+t);
32156 }
32157
32158 function calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format) {
32159   var scale = continuous(deinterpolateLinear, reinterpolate),
32160       invert = scale.invert,
32161       domain = scale.domain;
32162
32163   var formatMillisecond = format(".%L"),
32164       formatSecond = format(":%S"),
32165       formatMinute = format("%I:%M"),
32166       formatHour = format("%I %p"),
32167       formatDay = format("%a %d"),
32168       formatWeek = format("%b %d"),
32169       formatMonth = format("%B"),
32170       formatYear = format("%Y");
32171
32172   var tickIntervals = [
32173     [second$$1,  1,      durationSecond],
32174     [second$$1,  5,  5 * durationSecond],
32175     [second$$1, 15, 15 * durationSecond],
32176     [second$$1, 30, 30 * durationSecond],
32177     [minute$$1,  1,      durationMinute],
32178     [minute$$1,  5,  5 * durationMinute],
32179     [minute$$1, 15, 15 * durationMinute],
32180     [minute$$1, 30, 30 * durationMinute],
32181     [  hour$$1,  1,      durationHour  ],
32182     [  hour$$1,  3,  3 * durationHour  ],
32183     [  hour$$1,  6,  6 * durationHour  ],
32184     [  hour$$1, 12, 12 * durationHour  ],
32185     [   day$$1,  1,      durationDay   ],
32186     [   day$$1,  2,  2 * durationDay   ],
32187     [  week,  1,      durationWeek  ],
32188     [ month$$1,  1,      durationMonth ],
32189     [ month$$1,  3,  3 * durationMonth ],
32190     [  year$$1,  1,      durationYear  ]
32191   ];
32192
32193   function tickFormat(date) {
32194     return (second$$1(date) < date ? formatMillisecond
32195         : minute$$1(date) < date ? formatSecond
32196         : hour$$1(date) < date ? formatMinute
32197         : day$$1(date) < date ? formatHour
32198         : month$$1(date) < date ? (week(date) < date ? formatDay : formatWeek)
32199         : year$$1(date) < date ? formatMonth
32200         : formatYear)(date);
32201   }
32202
32203   function tickInterval(interval, start, stop, step) {
32204     if (interval == null) interval = 10;
32205
32206     // If a desired tick count is specified, pick a reasonable tick interval
32207     // based on the extent of the domain and a rough estimate of tick size.
32208     // Otherwise, assume interval is already a time interval and use it.
32209     if (typeof interval === "number") {
32210       var target = Math.abs(stop - start) / interval,
32211           i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
32212       if (i === tickIntervals.length) {
32213         step = tickStep(start / durationYear, stop / durationYear, interval);
32214         interval = year$$1;
32215       } else if (i) {
32216         i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
32217         step = i[1];
32218         interval = i[0];
32219       } else {
32220         step = tickStep(start, stop, interval);
32221         interval = millisecond$$1;
32222       }
32223     }
32224
32225     return step == null ? interval : interval.every(step);
32226   }
32227
32228   scale.invert = function(y) {
32229     return new Date(invert(y));
32230   };
32231
32232   scale.domain = function(_) {
32233     return arguments.length ? domain(map$3.call(_, number$2)) : domain().map(date$1);
32234   };
32235
32236   scale.ticks = function(interval, step) {
32237     var d = domain(),
32238         t0 = d[0],
32239         t1 = d[d.length - 1],
32240         r = t1 < t0,
32241         t;
32242     if (r) t = t0, t0 = t1, t1 = t;
32243     t = tickInterval(interval, t0, t1, step);
32244     t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
32245     return r ? t.reverse() : t;
32246   };
32247
32248   scale.tickFormat = function(count, specifier) {
32249     return specifier == null ? tickFormat : format(specifier);
32250   };
32251
32252   scale.nice = function(interval, step) {
32253     var d = domain();
32254     return (interval = tickInterval(interval, d[0], d[d.length - 1], step))
32255         ? domain(nice(d, interval))
32256         : scale;
32257   };
32258
32259   scale.copy = function() {
32260     return copy(scale, calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format));
32261   };
32262
32263   return scale;
32264 }
32265
32266 var time = function() {
32267   return calendar(year, month, sunday, day, hour, minute, second, millisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
32268 };
32269
32270 var utcTime = function() {
32271   return calendar(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, millisecond, utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]);
32272 };
32273
32274 var colors = function(s) {
32275   return s.match(/.{6}/g).map(function(x) {
32276     return "#" + x;
32277   });
32278 };
32279
32280 var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf");
32281
32282 var category20b = colors("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6");
32283
32284 var category20c = colors("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9");
32285
32286 var category20 = colors("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5");
32287
32288 var cubehelix$3 = cubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0));
32289
32290 var warm = cubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32291
32292 var cool = cubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32293
32294 var rainbow = cubehelix();
32295
32296 var rainbow$1 = function(t) {
32297   if (t < 0 || t > 1) t -= Math.floor(t);
32298   var ts = Math.abs(t - 0.5);
32299   rainbow.h = 360 * t - 100;
32300   rainbow.s = 1.5 - 1.5 * ts;
32301   rainbow.l = 0.8 - 0.9 * ts;
32302   return rainbow + "";
32303 };
32304
32305 function ramp(range) {
32306   var n = range.length;
32307   return function(t) {
32308     return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
32309   };
32310 }
32311
32312 var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
32313
32314 var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
32315
32316 var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
32317
32318 var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
32319
32320 function sequential(interpolator) {
32321   var x0 = 0,
32322       x1 = 1,
32323       clamp = false;
32324
32325   function scale(x) {
32326     var t = (x - x0) / (x1 - x0);
32327     return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);
32328   }
32329
32330   scale.domain = function(_) {
32331     return arguments.length ? (x0 = +_[0], x1 = +_[1], scale) : [x0, x1];
32332   };
32333
32334   scale.clamp = function(_) {
32335     return arguments.length ? (clamp = !!_, scale) : clamp;
32336   };
32337
32338   scale.interpolator = function(_) {
32339     return arguments.length ? (interpolator = _, scale) : interpolator;
32340   };
32341
32342   scale.copy = function() {
32343     return sequential(interpolator).domain([x0, x1]).clamp(clamp);
32344   };
32345
32346   return linearish(scale);
32347 }
32348
32349 var constant$10 = function(x) {
32350   return function constant() {
32351     return x;
32352   };
32353 };
32354
32355 var abs$1 = Math.abs;
32356 var atan2$1 = Math.atan2;
32357 var cos$2 = Math.cos;
32358 var max$2 = Math.max;
32359 var min$1 = Math.min;
32360 var sin$2 = Math.sin;
32361 var sqrt$2 = Math.sqrt;
32362
32363 var epsilon$3 = 1e-12;
32364 var pi$4 = Math.PI;
32365 var halfPi$3 = pi$4 / 2;
32366 var tau$4 = 2 * pi$4;
32367
32368 function acos$1(x) {
32369   return x > 1 ? 0 : x < -1 ? pi$4 : Math.acos(x);
32370 }
32371
32372 function asin$1(x) {
32373   return x >= 1 ? halfPi$3 : x <= -1 ? -halfPi$3 : Math.asin(x);
32374 }
32375
32376 function arcInnerRadius(d) {
32377   return d.innerRadius;
32378 }
32379
32380 function arcOuterRadius(d) {
32381   return d.outerRadius;
32382 }
32383
32384 function arcStartAngle(d) {
32385   return d.startAngle;
32386 }
32387
32388 function arcEndAngle(d) {
32389   return d.endAngle;
32390 }
32391
32392 function arcPadAngle(d) {
32393   return d && d.padAngle; // Note: optional!
32394 }
32395
32396 function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
32397   var x10 = x1 - x0, y10 = y1 - y0,
32398       x32 = x3 - x2, y32 = y3 - y2,
32399       t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10);
32400   return [x0 + t * x10, y0 + t * y10];
32401 }
32402
32403 // Compute perpendicular offset line of length rc.
32404 // http://mathworld.wolfram.com/Circle-LineIntersection.html
32405 function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
32406   var x01 = x0 - x1,
32407       y01 = y0 - y1,
32408       lo = (cw ? rc : -rc) / sqrt$2(x01 * x01 + y01 * y01),
32409       ox = lo * y01,
32410       oy = -lo * x01,
32411       x11 = x0 + ox,
32412       y11 = y0 + oy,
32413       x10 = x1 + ox,
32414       y10 = y1 + oy,
32415       x00 = (x11 + x10) / 2,
32416       y00 = (y11 + y10) / 2,
32417       dx = x10 - x11,
32418       dy = y10 - y11,
32419       d2 = dx * dx + dy * dy,
32420       r = r1 - rc,
32421       D = x11 * y10 - x10 * y11,
32422       d = (dy < 0 ? -1 : 1) * sqrt$2(max$2(0, r * r * d2 - D * D)),
32423       cx0 = (D * dy - dx * d) / d2,
32424       cy0 = (-D * dx - dy * d) / d2,
32425       cx1 = (D * dy + dx * d) / d2,
32426       cy1 = (-D * dx + dy * d) / d2,
32427       dx0 = cx0 - x00,
32428       dy0 = cy0 - y00,
32429       dx1 = cx1 - x00,
32430       dy1 = cy1 - y00;
32431
32432   // Pick the closer of the two intersection points.
32433   // TODO Is there a faster way to determine which intersection to use?
32434   if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
32435
32436   return {
32437     cx: cx0,
32438     cy: cy0,
32439     x01: -ox,
32440     y01: -oy,
32441     x11: cx0 * (r1 / r - 1),
32442     y11: cy0 * (r1 / r - 1)
32443   };
32444 }
32445
32446 var arc = function() {
32447   var innerRadius = arcInnerRadius,
32448       outerRadius = arcOuterRadius,
32449       cornerRadius = constant$10(0),
32450       padRadius = null,
32451       startAngle = arcStartAngle,
32452       endAngle = arcEndAngle,
32453       padAngle = arcPadAngle,
32454       context = null;
32455
32456   function arc() {
32457     var buffer,
32458         r,
32459         r0 = +innerRadius.apply(this, arguments),
32460         r1 = +outerRadius.apply(this, arguments),
32461         a0 = startAngle.apply(this, arguments) - halfPi$3,
32462         a1 = endAngle.apply(this, arguments) - halfPi$3,
32463         da = abs$1(a1 - a0),
32464         cw = a1 > a0;
32465
32466     if (!context) context = buffer = path();
32467
32468     // Ensure that the outer radius is always larger than the inner radius.
32469     if (r1 < r0) r = r1, r1 = r0, r0 = r;
32470
32471     // Is it a point?
32472     if (!(r1 > epsilon$3)) context.moveTo(0, 0);
32473
32474     // Or is it a circle or annulus?
32475     else if (da > tau$4 - epsilon$3) {
32476       context.moveTo(r1 * cos$2(a0), r1 * sin$2(a0));
32477       context.arc(0, 0, r1, a0, a1, !cw);
32478       if (r0 > epsilon$3) {
32479         context.moveTo(r0 * cos$2(a1), r0 * sin$2(a1));
32480         context.arc(0, 0, r0, a1, a0, cw);
32481       }
32482     }
32483
32484     // Or is it a circular or annular sector?
32485     else {
32486       var a01 = a0,
32487           a11 = a1,
32488           a00 = a0,
32489           a10 = a1,
32490           da0 = da,
32491           da1 = da,
32492           ap = padAngle.apply(this, arguments) / 2,
32493           rp = (ap > epsilon$3) && (padRadius ? +padRadius.apply(this, arguments) : sqrt$2(r0 * r0 + r1 * r1)),
32494           rc = min$1(abs$1(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
32495           rc0 = rc,
32496           rc1 = rc,
32497           t0,
32498           t1;
32499
32500       // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
32501       if (rp > epsilon$3) {
32502         var p0 = asin$1(rp / r0 * sin$2(ap)),
32503             p1 = asin$1(rp / r1 * sin$2(ap));
32504         if ((da0 -= p0 * 2) > epsilon$3) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
32505         else da0 = 0, a00 = a10 = (a0 + a1) / 2;
32506         if ((da1 -= p1 * 2) > epsilon$3) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
32507         else da1 = 0, a01 = a11 = (a0 + a1) / 2;
32508       }
32509
32510       var x01 = r1 * cos$2(a01),
32511           y01 = r1 * sin$2(a01),
32512           x10 = r0 * cos$2(a10),
32513           y10 = r0 * sin$2(a10);
32514
32515       // Apply rounded corners?
32516       if (rc > epsilon$3) {
32517         var x11 = r1 * cos$2(a11),
32518             y11 = r1 * sin$2(a11),
32519             x00 = r0 * cos$2(a00),
32520             y00 = r0 * sin$2(a00);
32521
32522         // Restrict the corner radius according to the sector angle.
32523         if (da < pi$4) {
32524           var oc = da0 > epsilon$3 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10],
32525               ax = x01 - oc[0],
32526               ay = y01 - oc[1],
32527               bx = x11 - oc[0],
32528               by = y11 - oc[1],
32529               kc = 1 / sin$2(acos$1((ax * bx + ay * by) / (sqrt$2(ax * ax + ay * ay) * sqrt$2(bx * bx + by * by))) / 2),
32530               lc = sqrt$2(oc[0] * oc[0] + oc[1] * oc[1]);
32531           rc0 = min$1(rc, (r0 - lc) / (kc - 1));
32532           rc1 = min$1(rc, (r1 - lc) / (kc + 1));
32533         }
32534       }
32535
32536       // Is the sector collapsed to a line?
32537       if (!(da1 > epsilon$3)) context.moveTo(x01, y01);
32538
32539       // Does the sector’s outer ring have rounded corners?
32540       else if (rc1 > epsilon$3) {
32541         t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
32542         t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
32543
32544         context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
32545
32546         // Have the corners merged?
32547         if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32548
32549         // Otherwise, draw the two corners and the ring.
32550         else {
32551           context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32552           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);
32553           context.arc(t1.cx, t1.cy, rc1, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32554         }
32555       }
32556
32557       // Or is the outer ring just a circular arc?
32558       else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
32559
32560       // Is there no inner ring, and it’s a circular sector?
32561       // Or perhaps it’s an annular sector collapsed due to padding?
32562       if (!(r0 > epsilon$3) || !(da0 > epsilon$3)) context.lineTo(x10, y10);
32563
32564       // Does the sector’s inner ring (or point) have rounded corners?
32565       else if (rc0 > epsilon$3) {
32566         t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
32567         t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
32568
32569         context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
32570
32571         // Have the corners merged?
32572         if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32573
32574         // Otherwise, draw the two corners and the ring.
32575         else {
32576           context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32577           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);
32578           context.arc(t1.cx, t1.cy, rc0, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32579         }
32580       }
32581
32582       // Or is the inner ring just a circular arc?
32583       else context.arc(0, 0, r0, a10, a00, cw);
32584     }
32585
32586     context.closePath();
32587
32588     if (buffer) return context = null, buffer + "" || null;
32589   }
32590
32591   arc.centroid = function() {
32592     var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
32593         a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi$4 / 2;
32594     return [cos$2(a) * r, sin$2(a) * r];
32595   };
32596
32597   arc.innerRadius = function(_) {
32598     return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : innerRadius;
32599   };
32600
32601   arc.outerRadius = function(_) {
32602     return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : outerRadius;
32603   };
32604
32605   arc.cornerRadius = function(_) {
32606     return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : cornerRadius;
32607   };
32608
32609   arc.padRadius = function(_) {
32610     return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), arc) : padRadius;
32611   };
32612
32613   arc.startAngle = function(_) {
32614     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : startAngle;
32615   };
32616
32617   arc.endAngle = function(_) {
32618     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : endAngle;
32619   };
32620
32621   arc.padAngle = function(_) {
32622     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : padAngle;
32623   };
32624
32625   arc.context = function(_) {
32626     return arguments.length ? ((context = _ == null ? null : _), arc) : context;
32627   };
32628
32629   return arc;
32630 };
32631
32632 function Linear(context) {
32633   this._context = context;
32634 }
32635
32636 Linear.prototype = {
32637   areaStart: function() {
32638     this._line = 0;
32639   },
32640   areaEnd: function() {
32641     this._line = NaN;
32642   },
32643   lineStart: function() {
32644     this._point = 0;
32645   },
32646   lineEnd: function() {
32647     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
32648     this._line = 1 - this._line;
32649   },
32650   point: function(x, y) {
32651     x = +x, y = +y;
32652     switch (this._point) {
32653       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
32654       case 1: this._point = 2; // proceed
32655       default: this._context.lineTo(x, y); break;
32656     }
32657   }
32658 };
32659
32660 var curveLinear = function(context) {
32661   return new Linear(context);
32662 };
32663
32664 function x$3(p) {
32665   return p[0];
32666 }
32667
32668 function y$3(p) {
32669   return p[1];
32670 }
32671
32672 var line = function() {
32673   var x$$1 = x$3,
32674       y$$1 = y$3,
32675       defined = constant$10(true),
32676       context = null,
32677       curve = curveLinear,
32678       output = null;
32679
32680   function line(data) {
32681     var i,
32682         n = data.length,
32683         d,
32684         defined0 = false,
32685         buffer;
32686
32687     if (context == null) output = curve(buffer = path());
32688
32689     for (i = 0; i <= n; ++i) {
32690       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32691         if (defined0 = !defined0) output.lineStart();
32692         else output.lineEnd();
32693       }
32694       if (defined0) output.point(+x$$1(d, i, data), +y$$1(d, i, data));
32695     }
32696
32697     if (buffer) return output = null, buffer + "" || null;
32698   }
32699
32700   line.x = function(_) {
32701     return arguments.length ? (x$$1 = typeof _ === "function" ? _ : constant$10(+_), line) : x$$1;
32702   };
32703
32704   line.y = function(_) {
32705     return arguments.length ? (y$$1 = typeof _ === "function" ? _ : constant$10(+_), line) : y$$1;
32706   };
32707
32708   line.defined = function(_) {
32709     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), line) : defined;
32710   };
32711
32712   line.curve = function(_) {
32713     return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
32714   };
32715
32716   line.context = function(_) {
32717     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
32718   };
32719
32720   return line;
32721 };
32722
32723 var area$1 = function() {
32724   var x0 = x$3,
32725       x1 = null,
32726       y0 = constant$10(0),
32727       y1 = y$3,
32728       defined = constant$10(true),
32729       context = null,
32730       curve = curveLinear,
32731       output = null;
32732
32733   function area(data) {
32734     var i,
32735         j,
32736         k,
32737         n = data.length,
32738         d,
32739         defined0 = false,
32740         buffer,
32741         x0z = new Array(n),
32742         y0z = new Array(n);
32743
32744     if (context == null) output = curve(buffer = path());
32745
32746     for (i = 0; i <= n; ++i) {
32747       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32748         if (defined0 = !defined0) {
32749           j = i;
32750           output.areaStart();
32751           output.lineStart();
32752         } else {
32753           output.lineEnd();
32754           output.lineStart();
32755           for (k = i - 1; k >= j; --k) {
32756             output.point(x0z[k], y0z[k]);
32757           }
32758           output.lineEnd();
32759           output.areaEnd();
32760         }
32761       }
32762       if (defined0) {
32763         x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
32764         output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
32765       }
32766     }
32767
32768     if (buffer) return output = null, buffer + "" || null;
32769   }
32770
32771   function arealine() {
32772     return line().defined(defined).curve(curve).context(context);
32773   }
32774
32775   area.x = function(_) {
32776     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), x1 = null, area) : x0;
32777   };
32778
32779   area.x0 = function(_) {
32780     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), area) : x0;
32781   };
32782
32783   area.x1 = function(_) {
32784     return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : x1;
32785   };
32786
32787   area.y = function(_) {
32788     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), y1 = null, area) : y0;
32789   };
32790
32791   area.y0 = function(_) {
32792     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), area) : y0;
32793   };
32794
32795   area.y1 = function(_) {
32796     return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : y1;
32797   };
32798
32799   area.lineX0 =
32800   area.lineY0 = function() {
32801     return arealine().x(x0).y(y0);
32802   };
32803
32804   area.lineY1 = function() {
32805     return arealine().x(x0).y(y1);
32806   };
32807
32808   area.lineX1 = function() {
32809     return arealine().x(x1).y(y0);
32810   };
32811
32812   area.defined = function(_) {
32813     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), area) : defined;
32814   };
32815
32816   area.curve = function(_) {
32817     return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
32818   };
32819
32820   area.context = function(_) {
32821     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
32822   };
32823
32824   return area;
32825 };
32826
32827 var descending$1 = function(a, b) {
32828   return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
32829 };
32830
32831 var identity$7 = function(d) {
32832   return d;
32833 };
32834
32835 var pie = function() {
32836   var value = identity$7,
32837       sortValues = descending$1,
32838       sort = null,
32839       startAngle = constant$10(0),
32840       endAngle = constant$10(tau$4),
32841       padAngle = constant$10(0);
32842
32843   function pie(data) {
32844     var i,
32845         n = data.length,
32846         j,
32847         k,
32848         sum = 0,
32849         index = new Array(n),
32850         arcs = new Array(n),
32851         a0 = +startAngle.apply(this, arguments),
32852         da = Math.min(tau$4, Math.max(-tau$4, endAngle.apply(this, arguments) - a0)),
32853         a1,
32854         p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
32855         pa = p * (da < 0 ? -1 : 1),
32856         v;
32857
32858     for (i = 0; i < n; ++i) {
32859       if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
32860         sum += v;
32861       }
32862     }
32863
32864     // Optionally sort the arcs by previously-computed values or by data.
32865     if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
32866     else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });
32867
32868     // Compute the arcs! They are stored in the original data's order.
32869     for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
32870       j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
32871         data: data[j],
32872         index: i,
32873         value: v,
32874         startAngle: a0,
32875         endAngle: a1,
32876         padAngle: p
32877       };
32878     }
32879
32880     return arcs;
32881   }
32882
32883   pie.value = function(_) {
32884     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), pie) : value;
32885   };
32886
32887   pie.sortValues = function(_) {
32888     return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
32889   };
32890
32891   pie.sort = function(_) {
32892     return arguments.length ? (sort = _, sortValues = null, pie) : sort;
32893   };
32894
32895   pie.startAngle = function(_) {
32896     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : startAngle;
32897   };
32898
32899   pie.endAngle = function(_) {
32900     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : endAngle;
32901   };
32902
32903   pie.padAngle = function(_) {
32904     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : padAngle;
32905   };
32906
32907   return pie;
32908 };
32909
32910 var curveRadialLinear = curveRadial(curveLinear);
32911
32912 function Radial(curve) {
32913   this._curve = curve;
32914 }
32915
32916 Radial.prototype = {
32917   areaStart: function() {
32918     this._curve.areaStart();
32919   },
32920   areaEnd: function() {
32921     this._curve.areaEnd();
32922   },
32923   lineStart: function() {
32924     this._curve.lineStart();
32925   },
32926   lineEnd: function() {
32927     this._curve.lineEnd();
32928   },
32929   point: function(a, r) {
32930     this._curve.point(r * Math.sin(a), r * -Math.cos(a));
32931   }
32932 };
32933
32934 function curveRadial(curve) {
32935
32936   function radial(context) {
32937     return new Radial(curve(context));
32938   }
32939
32940   radial._curve = curve;
32941
32942   return radial;
32943 }
32944
32945 function radialLine(l) {
32946   var c = l.curve;
32947
32948   l.angle = l.x, delete l.x;
32949   l.radius = l.y, delete l.y;
32950
32951   l.curve = function(_) {
32952     return arguments.length ? c(curveRadial(_)) : c()._curve;
32953   };
32954
32955   return l;
32956 }
32957
32958 var radialLine$1 = function() {
32959   return radialLine(line().curve(curveRadialLinear));
32960 };
32961
32962 var radialArea = function() {
32963   var a = area$1().curve(curveRadialLinear),
32964       c = a.curve,
32965       x0 = a.lineX0,
32966       x1 = a.lineX1,
32967       y0 = a.lineY0,
32968       y1 = a.lineY1;
32969
32970   a.angle = a.x, delete a.x;
32971   a.startAngle = a.x0, delete a.x0;
32972   a.endAngle = a.x1, delete a.x1;
32973   a.radius = a.y, delete a.y;
32974   a.innerRadius = a.y0, delete a.y0;
32975   a.outerRadius = a.y1, delete a.y1;
32976   a.lineStartAngle = function() { return radialLine(x0()); }, delete a.lineX0;
32977   a.lineEndAngle = function() { return radialLine(x1()); }, delete a.lineX1;
32978   a.lineInnerRadius = function() { return radialLine(y0()); }, delete a.lineY0;
32979   a.lineOuterRadius = function() { return radialLine(y1()); }, delete a.lineY1;
32980
32981   a.curve = function(_) {
32982     return arguments.length ? c(curveRadial(_)) : c()._curve;
32983   };
32984
32985   return a;
32986 };
32987
32988 var circle$2 = {
32989   draw: function(context, size) {
32990     var r = Math.sqrt(size / pi$4);
32991     context.moveTo(r, 0);
32992     context.arc(0, 0, r, 0, tau$4);
32993   }
32994 };
32995
32996 var cross$2 = {
32997   draw: function(context, size) {
32998     var r = Math.sqrt(size / 5) / 2;
32999     context.moveTo(-3 * r, -r);
33000     context.lineTo(-r, -r);
33001     context.lineTo(-r, -3 * r);
33002     context.lineTo(r, -3 * r);
33003     context.lineTo(r, -r);
33004     context.lineTo(3 * r, -r);
33005     context.lineTo(3 * r, r);
33006     context.lineTo(r, r);
33007     context.lineTo(r, 3 * r);
33008     context.lineTo(-r, 3 * r);
33009     context.lineTo(-r, r);
33010     context.lineTo(-3 * r, r);
33011     context.closePath();
33012   }
33013 };
33014
33015 var tan30 = Math.sqrt(1 / 3);
33016 var tan30_2 = tan30 * 2;
33017
33018 var diamond = {
33019   draw: function(context, size) {
33020     var y = Math.sqrt(size / tan30_2),
33021         x = y * tan30;
33022     context.moveTo(0, -y);
33023     context.lineTo(x, 0);
33024     context.lineTo(0, y);
33025     context.lineTo(-x, 0);
33026     context.closePath();
33027   }
33028 };
33029
33030 var ka = 0.89081309152928522810;
33031 var kr = Math.sin(pi$4 / 10) / Math.sin(7 * pi$4 / 10);
33032 var kx = Math.sin(tau$4 / 10) * kr;
33033 var ky = -Math.cos(tau$4 / 10) * kr;
33034
33035 var star = {
33036   draw: function(context, size) {
33037     var r = Math.sqrt(size * ka),
33038         x = kx * r,
33039         y = ky * r;
33040     context.moveTo(0, -r);
33041     context.lineTo(x, y);
33042     for (var i = 1; i < 5; ++i) {
33043       var a = tau$4 * i / 5,
33044           c = Math.cos(a),
33045           s = Math.sin(a);
33046       context.lineTo(s * r, -c * r);
33047       context.lineTo(c * x - s * y, s * x + c * y);
33048     }
33049     context.closePath();
33050   }
33051 };
33052
33053 var square = {
33054   draw: function(context, size) {
33055     var w = Math.sqrt(size),
33056         x = -w / 2;
33057     context.rect(x, x, w, w);
33058   }
33059 };
33060
33061 var sqrt3 = Math.sqrt(3);
33062
33063 var triangle = {
33064   draw: function(context, size) {
33065     var y = -Math.sqrt(size / (sqrt3 * 3));
33066     context.moveTo(0, y * 2);
33067     context.lineTo(-sqrt3 * y, -y);
33068     context.lineTo(sqrt3 * y, -y);
33069     context.closePath();
33070   }
33071 };
33072
33073 var c = -0.5;
33074 var s = Math.sqrt(3) / 2;
33075 var k = 1 / Math.sqrt(12);
33076 var a = (k / 2 + 1) * 3;
33077
33078 var wye = {
33079   draw: function(context, size) {
33080     var r = Math.sqrt(size / a),
33081         x0 = r / 2,
33082         y0 = r * k,
33083         x1 = x0,
33084         y1 = r * k + r,
33085         x2 = -x1,
33086         y2 = y1;
33087     context.moveTo(x0, y0);
33088     context.lineTo(x1, y1);
33089     context.lineTo(x2, y2);
33090     context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
33091     context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
33092     context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
33093     context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
33094     context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
33095     context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
33096     context.closePath();
33097   }
33098 };
33099
33100 var symbols = [
33101   circle$2,
33102   cross$2,
33103   diamond,
33104   square,
33105   star,
33106   triangle,
33107   wye
33108 ];
33109
33110 var symbol = function() {
33111   var type = constant$10(circle$2),
33112       size = constant$10(64),
33113       context = null;
33114
33115   function symbol() {
33116     var buffer;
33117     if (!context) context = buffer = path();
33118     type.apply(this, arguments).draw(context, +size.apply(this, arguments));
33119     if (buffer) return context = null, buffer + "" || null;
33120   }
33121
33122   symbol.type = function(_) {
33123     return arguments.length ? (type = typeof _ === "function" ? _ : constant$10(_), symbol) : type;
33124   };
33125
33126   symbol.size = function(_) {
33127     return arguments.length ? (size = typeof _ === "function" ? _ : constant$10(+_), symbol) : size;
33128   };
33129
33130   symbol.context = function(_) {
33131     return arguments.length ? (context = _ == null ? null : _, symbol) : context;
33132   };
33133
33134   return symbol;
33135 };
33136
33137 var noop$2 = function() {};
33138
33139 function point$2(that, x, y) {
33140   that._context.bezierCurveTo(
33141     (2 * that._x0 + that._x1) / 3,
33142     (2 * that._y0 + that._y1) / 3,
33143     (that._x0 + 2 * that._x1) / 3,
33144     (that._y0 + 2 * that._y1) / 3,
33145     (that._x0 + 4 * that._x1 + x) / 6,
33146     (that._y0 + 4 * that._y1 + y) / 6
33147   );
33148 }
33149
33150 function Basis(context) {
33151   this._context = context;
33152 }
33153
33154 Basis.prototype = {
33155   areaStart: function() {
33156     this._line = 0;
33157   },
33158   areaEnd: function() {
33159     this._line = NaN;
33160   },
33161   lineStart: function() {
33162     this._x0 = this._x1 =
33163     this._y0 = this._y1 = NaN;
33164     this._point = 0;
33165   },
33166   lineEnd: function() {
33167     switch (this._point) {
33168       case 3: point$2(this, this._x1, this._y1); // proceed
33169       case 2: this._context.lineTo(this._x1, this._y1); break;
33170     }
33171     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33172     this._line = 1 - this._line;
33173   },
33174   point: function(x, y) {
33175     x = +x, y = +y;
33176     switch (this._point) {
33177       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33178       case 1: this._point = 2; break;
33179       case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
33180       default: point$2(this, x, y); break;
33181     }
33182     this._x0 = this._x1, this._x1 = x;
33183     this._y0 = this._y1, this._y1 = y;
33184   }
33185 };
33186
33187 var basis$2 = function(context) {
33188   return new Basis(context);
33189 };
33190
33191 function BasisClosed(context) {
33192   this._context = context;
33193 }
33194
33195 BasisClosed.prototype = {
33196   areaStart: noop$2,
33197   areaEnd: noop$2,
33198   lineStart: function() {
33199     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
33200     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
33201     this._point = 0;
33202   },
33203   lineEnd: function() {
33204     switch (this._point) {
33205       case 1: {
33206         this._context.moveTo(this._x2, this._y2);
33207         this._context.closePath();
33208         break;
33209       }
33210       case 2: {
33211         this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
33212         this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
33213         this._context.closePath();
33214         break;
33215       }
33216       case 3: {
33217         this.point(this._x2, this._y2);
33218         this.point(this._x3, this._y3);
33219         this.point(this._x4, this._y4);
33220         break;
33221       }
33222     }
33223   },
33224   point: function(x, y) {
33225     x = +x, y = +y;
33226     switch (this._point) {
33227       case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
33228       case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
33229       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;
33230       default: point$2(this, x, y); break;
33231     }
33232     this._x0 = this._x1, this._x1 = x;
33233     this._y0 = this._y1, this._y1 = y;
33234   }
33235 };
33236
33237 var basisClosed$1 = function(context) {
33238   return new BasisClosed(context);
33239 };
33240
33241 function BasisOpen(context) {
33242   this._context = context;
33243 }
33244
33245 BasisOpen.prototype = {
33246   areaStart: function() {
33247     this._line = 0;
33248   },
33249   areaEnd: function() {
33250     this._line = NaN;
33251   },
33252   lineStart: function() {
33253     this._x0 = this._x1 =
33254     this._y0 = this._y1 = NaN;
33255     this._point = 0;
33256   },
33257   lineEnd: function() {
33258     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33259     this._line = 1 - this._line;
33260   },
33261   point: function(x, y) {
33262     x = +x, y = +y;
33263     switch (this._point) {
33264       case 0: this._point = 1; break;
33265       case 1: this._point = 2; break;
33266       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;
33267       case 3: this._point = 4; // proceed
33268       default: point$2(this, x, y); break;
33269     }
33270     this._x0 = this._x1, this._x1 = x;
33271     this._y0 = this._y1, this._y1 = y;
33272   }
33273 };
33274
33275 var basisOpen = function(context) {
33276   return new BasisOpen(context);
33277 };
33278
33279 function Bundle(context, beta) {
33280   this._basis = new Basis(context);
33281   this._beta = beta;
33282 }
33283
33284 Bundle.prototype = {
33285   lineStart: function() {
33286     this._x = [];
33287     this._y = [];
33288     this._basis.lineStart();
33289   },
33290   lineEnd: function() {
33291     var x = this._x,
33292         y = this._y,
33293         j = x.length - 1;
33294
33295     if (j > 0) {
33296       var x0 = x[0],
33297           y0 = y[0],
33298           dx = x[j] - x0,
33299           dy = y[j] - y0,
33300           i = -1,
33301           t;
33302
33303       while (++i <= j) {
33304         t = i / j;
33305         this._basis.point(
33306           this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
33307           this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
33308         );
33309       }
33310     }
33311
33312     this._x = this._y = null;
33313     this._basis.lineEnd();
33314   },
33315   point: function(x, y) {
33316     this._x.push(+x);
33317     this._y.push(+y);
33318   }
33319 };
33320
33321 var bundle = ((function custom(beta) {
33322
33323   function bundle(context) {
33324     return beta === 1 ? new Basis(context) : new Bundle(context, beta);
33325   }
33326
33327   bundle.beta = function(beta) {
33328     return custom(+beta);
33329   };
33330
33331   return bundle;
33332 }))(0.85);
33333
33334 function point$3(that, x, y) {
33335   that._context.bezierCurveTo(
33336     that._x1 + that._k * (that._x2 - that._x0),
33337     that._y1 + that._k * (that._y2 - that._y0),
33338     that._x2 + that._k * (that._x1 - x),
33339     that._y2 + that._k * (that._y1 - y),
33340     that._x2,
33341     that._y2
33342   );
33343 }
33344
33345 function Cardinal(context, tension) {
33346   this._context = context;
33347   this._k = (1 - tension) / 6;
33348 }
33349
33350 Cardinal.prototype = {
33351   areaStart: function() {
33352     this._line = 0;
33353   },
33354   areaEnd: function() {
33355     this._line = NaN;
33356   },
33357   lineStart: function() {
33358     this._x0 = this._x1 = this._x2 =
33359     this._y0 = this._y1 = this._y2 = NaN;
33360     this._point = 0;
33361   },
33362   lineEnd: function() {
33363     switch (this._point) {
33364       case 2: this._context.lineTo(this._x2, this._y2); break;
33365       case 3: point$3(this, this._x1, this._y1); break;
33366     }
33367     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33368     this._line = 1 - this._line;
33369   },
33370   point: function(x, y) {
33371     x = +x, y = +y;
33372     switch (this._point) {
33373       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33374       case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
33375       case 2: this._point = 3; // proceed
33376       default: point$3(this, x, y); break;
33377     }
33378     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33379     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33380   }
33381 };
33382
33383 var cardinal = ((function custom(tension) {
33384
33385   function cardinal(context) {
33386     return new Cardinal(context, tension);
33387   }
33388
33389   cardinal.tension = function(tension) {
33390     return custom(+tension);
33391   };
33392
33393   return cardinal;
33394 }))(0);
33395
33396 function CardinalClosed(context, tension) {
33397   this._context = context;
33398   this._k = (1 - tension) / 6;
33399 }
33400
33401 CardinalClosed.prototype = {
33402   areaStart: noop$2,
33403   areaEnd: noop$2,
33404   lineStart: function() {
33405     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33406     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33407     this._point = 0;
33408   },
33409   lineEnd: function() {
33410     switch (this._point) {
33411       case 1: {
33412         this._context.moveTo(this._x3, this._y3);
33413         this._context.closePath();
33414         break;
33415       }
33416       case 2: {
33417         this._context.lineTo(this._x3, this._y3);
33418         this._context.closePath();
33419         break;
33420       }
33421       case 3: {
33422         this.point(this._x3, this._y3);
33423         this.point(this._x4, this._y4);
33424         this.point(this._x5, this._y5);
33425         break;
33426       }
33427     }
33428   },
33429   point: function(x, y) {
33430     x = +x, y = +y;
33431     switch (this._point) {
33432       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33433       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33434       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33435       default: point$3(this, x, y); break;
33436     }
33437     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33438     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33439   }
33440 };
33441
33442 var cardinalClosed = ((function custom(tension) {
33443
33444   function cardinal(context) {
33445     return new CardinalClosed(context, tension);
33446   }
33447
33448   cardinal.tension = function(tension) {
33449     return custom(+tension);
33450   };
33451
33452   return cardinal;
33453 }))(0);
33454
33455 function CardinalOpen(context, tension) {
33456   this._context = context;
33457   this._k = (1 - tension) / 6;
33458 }
33459
33460 CardinalOpen.prototype = {
33461   areaStart: function() {
33462     this._line = 0;
33463   },
33464   areaEnd: function() {
33465     this._line = NaN;
33466   },
33467   lineStart: function() {
33468     this._x0 = this._x1 = this._x2 =
33469     this._y0 = this._y1 = this._y2 = NaN;
33470     this._point = 0;
33471   },
33472   lineEnd: function() {
33473     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33474     this._line = 1 - this._line;
33475   },
33476   point: function(x, y) {
33477     x = +x, y = +y;
33478     switch (this._point) {
33479       case 0: this._point = 1; break;
33480       case 1: this._point = 2; break;
33481       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33482       case 3: this._point = 4; // proceed
33483       default: point$3(this, x, y); break;
33484     }
33485     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33486     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33487   }
33488 };
33489
33490 var cardinalOpen = ((function custom(tension) {
33491
33492   function cardinal(context) {
33493     return new CardinalOpen(context, tension);
33494   }
33495
33496   cardinal.tension = function(tension) {
33497     return custom(+tension);
33498   };
33499
33500   return cardinal;
33501 }))(0);
33502
33503 function point$4(that, x, y) {
33504   var x1 = that._x1,
33505       y1 = that._y1,
33506       x2 = that._x2,
33507       y2 = that._y2;
33508
33509   if (that._l01_a > epsilon$3) {
33510     var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
33511         n = 3 * that._l01_a * (that._l01_a + that._l12_a);
33512     x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
33513     y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
33514   }
33515
33516   if (that._l23_a > epsilon$3) {
33517     var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
33518         m = 3 * that._l23_a * (that._l23_a + that._l12_a);
33519     x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
33520     y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
33521   }
33522
33523   that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
33524 }
33525
33526 function CatmullRom(context, alpha) {
33527   this._context = context;
33528   this._alpha = alpha;
33529 }
33530
33531 CatmullRom.prototype = {
33532   areaStart: function() {
33533     this._line = 0;
33534   },
33535   areaEnd: function() {
33536     this._line = NaN;
33537   },
33538   lineStart: function() {
33539     this._x0 = this._x1 = this._x2 =
33540     this._y0 = this._y1 = this._y2 = NaN;
33541     this._l01_a = this._l12_a = this._l23_a =
33542     this._l01_2a = this._l12_2a = this._l23_2a =
33543     this._point = 0;
33544   },
33545   lineEnd: function() {
33546     switch (this._point) {
33547       case 2: this._context.lineTo(this._x2, this._y2); break;
33548       case 3: this.point(this._x2, this._y2); break;
33549     }
33550     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33551     this._line = 1 - this._line;
33552   },
33553   point: function(x, y) {
33554     x = +x, y = +y;
33555
33556     if (this._point) {
33557       var x23 = this._x2 - x,
33558           y23 = this._y2 - y;
33559       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33560     }
33561
33562     switch (this._point) {
33563       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33564       case 1: this._point = 2; break;
33565       case 2: this._point = 3; // proceed
33566       default: point$4(this, x, y); break;
33567     }
33568
33569     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33570     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33571     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33572     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33573   }
33574 };
33575
33576 var catmullRom = ((function custom(alpha) {
33577
33578   function catmullRom(context) {
33579     return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);
33580   }
33581
33582   catmullRom.alpha = function(alpha) {
33583     return custom(+alpha);
33584   };
33585
33586   return catmullRom;
33587 }))(0.5);
33588
33589 function CatmullRomClosed(context, alpha) {
33590   this._context = context;
33591   this._alpha = alpha;
33592 }
33593
33594 CatmullRomClosed.prototype = {
33595   areaStart: noop$2,
33596   areaEnd: noop$2,
33597   lineStart: function() {
33598     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33599     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33600     this._l01_a = this._l12_a = this._l23_a =
33601     this._l01_2a = this._l12_2a = this._l23_2a =
33602     this._point = 0;
33603   },
33604   lineEnd: function() {
33605     switch (this._point) {
33606       case 1: {
33607         this._context.moveTo(this._x3, this._y3);
33608         this._context.closePath();
33609         break;
33610       }
33611       case 2: {
33612         this._context.lineTo(this._x3, this._y3);
33613         this._context.closePath();
33614         break;
33615       }
33616       case 3: {
33617         this.point(this._x3, this._y3);
33618         this.point(this._x4, this._y4);
33619         this.point(this._x5, this._y5);
33620         break;
33621       }
33622     }
33623   },
33624   point: function(x, y) {
33625     x = +x, y = +y;
33626
33627     if (this._point) {
33628       var x23 = this._x2 - x,
33629           y23 = this._y2 - y;
33630       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33631     }
33632
33633     switch (this._point) {
33634       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33635       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33636       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33637       default: point$4(this, x, y); break;
33638     }
33639
33640     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33641     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33642     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33643     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33644   }
33645 };
33646
33647 var catmullRomClosed = ((function custom(alpha) {
33648
33649   function catmullRom(context) {
33650     return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);
33651   }
33652
33653   catmullRom.alpha = function(alpha) {
33654     return custom(+alpha);
33655   };
33656
33657   return catmullRom;
33658 }))(0.5);
33659
33660 function CatmullRomOpen(context, alpha) {
33661   this._context = context;
33662   this._alpha = alpha;
33663 }
33664
33665 CatmullRomOpen.prototype = {
33666   areaStart: function() {
33667     this._line = 0;
33668   },
33669   areaEnd: function() {
33670     this._line = NaN;
33671   },
33672   lineStart: function() {
33673     this._x0 = this._x1 = this._x2 =
33674     this._y0 = this._y1 = this._y2 = NaN;
33675     this._l01_a = this._l12_a = this._l23_a =
33676     this._l01_2a = this._l12_2a = this._l23_2a =
33677     this._point = 0;
33678   },
33679   lineEnd: function() {
33680     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33681     this._line = 1 - this._line;
33682   },
33683   point: function(x, y) {
33684     x = +x, y = +y;
33685
33686     if (this._point) {
33687       var x23 = this._x2 - x,
33688           y23 = this._y2 - y;
33689       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33690     }
33691
33692     switch (this._point) {
33693       case 0: this._point = 1; break;
33694       case 1: this._point = 2; break;
33695       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33696       case 3: this._point = 4; // proceed
33697       default: point$4(this, x, y); break;
33698     }
33699
33700     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33701     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33702     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33703     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33704   }
33705 };
33706
33707 var catmullRomOpen = ((function custom(alpha) {
33708
33709   function catmullRom(context) {
33710     return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);
33711   }
33712
33713   catmullRom.alpha = function(alpha) {
33714     return custom(+alpha);
33715   };
33716
33717   return catmullRom;
33718 }))(0.5);
33719
33720 function LinearClosed(context) {
33721   this._context = context;
33722 }
33723
33724 LinearClosed.prototype = {
33725   areaStart: noop$2,
33726   areaEnd: noop$2,
33727   lineStart: function() {
33728     this._point = 0;
33729   },
33730   lineEnd: function() {
33731     if (this._point) this._context.closePath();
33732   },
33733   point: function(x, y) {
33734     x = +x, y = +y;
33735     if (this._point) this._context.lineTo(x, y);
33736     else this._point = 1, this._context.moveTo(x, y);
33737   }
33738 };
33739
33740 var linearClosed = function(context) {
33741   return new LinearClosed(context);
33742 };
33743
33744 function sign$1(x) {
33745   return x < 0 ? -1 : 1;
33746 }
33747
33748 // Calculate the slopes of the tangents (Hermite-type interpolation) based on
33749 // the following paper: Steffen, M. 1990. A Simple Method for Monotonic
33750 // Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
33751 // NOV(II), P. 443, 1990.
33752 function slope3(that, x2, y2) {
33753   var h0 = that._x1 - that._x0,
33754       h1 = x2 - that._x1,
33755       s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
33756       s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
33757       p = (s0 * h1 + s1 * h0) / (h0 + h1);
33758   return (sign$1(s0) + sign$1(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
33759 }
33760
33761 // Calculate a one-sided slope.
33762 function slope2(that, t) {
33763   var h = that._x1 - that._x0;
33764   return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
33765 }
33766
33767 // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
33768 // "you can express cubic Hermite interpolation in terms of cubic Bézier curves
33769 // with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
33770 function point$5(that, t0, t1) {
33771   var x0 = that._x0,
33772       y0 = that._y0,
33773       x1 = that._x1,
33774       y1 = that._y1,
33775       dx = (x1 - x0) / 3;
33776   that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
33777 }
33778
33779 function MonotoneX(context) {
33780   this._context = context;
33781 }
33782
33783 MonotoneX.prototype = {
33784   areaStart: function() {
33785     this._line = 0;
33786   },
33787   areaEnd: function() {
33788     this._line = NaN;
33789   },
33790   lineStart: function() {
33791     this._x0 = this._x1 =
33792     this._y0 = this._y1 =
33793     this._t0 = NaN;
33794     this._point = 0;
33795   },
33796   lineEnd: function() {
33797     switch (this._point) {
33798       case 2: this._context.lineTo(this._x1, this._y1); break;
33799       case 3: point$5(this, this._t0, slope2(this, this._t0)); break;
33800     }
33801     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33802     this._line = 1 - this._line;
33803   },
33804   point: function(x, y) {
33805     var t1 = NaN;
33806
33807     x = +x, y = +y;
33808     if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
33809     switch (this._point) {
33810       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33811       case 1: this._point = 2; break;
33812       case 2: this._point = 3; point$5(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
33813       default: point$5(this, this._t0, t1 = slope3(this, x, y)); break;
33814     }
33815
33816     this._x0 = this._x1, this._x1 = x;
33817     this._y0 = this._y1, this._y1 = y;
33818     this._t0 = t1;
33819   }
33820 };
33821
33822 function MonotoneY(context) {
33823   this._context = new ReflectContext(context);
33824 }
33825
33826 (MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {
33827   MonotoneX.prototype.point.call(this, y, x);
33828 };
33829
33830 function ReflectContext(context) {
33831   this._context = context;
33832 }
33833
33834 ReflectContext.prototype = {
33835   moveTo: function(x, y) { this._context.moveTo(y, x); },
33836   closePath: function() { this._context.closePath(); },
33837   lineTo: function(x, y) { this._context.lineTo(y, x); },
33838   bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }
33839 };
33840
33841 function monotoneX(context) {
33842   return new MonotoneX(context);
33843 }
33844
33845 function monotoneY(context) {
33846   return new MonotoneY(context);
33847 }
33848
33849 function Natural(context) {
33850   this._context = context;
33851 }
33852
33853 Natural.prototype = {
33854   areaStart: function() {
33855     this._line = 0;
33856   },
33857   areaEnd: function() {
33858     this._line = NaN;
33859   },
33860   lineStart: function() {
33861     this._x = [];
33862     this._y = [];
33863   },
33864   lineEnd: function() {
33865     var x = this._x,
33866         y = this._y,
33867         n = x.length;
33868
33869     if (n) {
33870       this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
33871       if (n === 2) {
33872         this._context.lineTo(x[1], y[1]);
33873       } else {
33874         var px = controlPoints(x),
33875             py = controlPoints(y);
33876         for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
33877           this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
33878         }
33879       }
33880     }
33881
33882     if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
33883     this._line = 1 - this._line;
33884     this._x = this._y = null;
33885   },
33886   point: function(x, y) {
33887     this._x.push(+x);
33888     this._y.push(+y);
33889   }
33890 };
33891
33892 // See https://www.particleincell.com/2012/bezier-splines/ for derivation.
33893 function controlPoints(x) {
33894   var i,
33895       n = x.length - 1,
33896       m,
33897       a = new Array(n),
33898       b = new Array(n),
33899       r = new Array(n);
33900   a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
33901   for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
33902   a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
33903   for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
33904   a[n - 1] = r[n - 1] / b[n - 1];
33905   for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
33906   b[n - 1] = (x[n] + a[n - 1]) / 2;
33907   for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
33908   return [a, b];
33909 }
33910
33911 var natural = function(context) {
33912   return new Natural(context);
33913 };
33914
33915 function Step(context, t) {
33916   this._context = context;
33917   this._t = t;
33918 }
33919
33920 Step.prototype = {
33921   areaStart: function() {
33922     this._line = 0;
33923   },
33924   areaEnd: function() {
33925     this._line = NaN;
33926   },
33927   lineStart: function() {
33928     this._x = this._y = NaN;
33929     this._point = 0;
33930   },
33931   lineEnd: function() {
33932     if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
33933     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33934     if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
33935   },
33936   point: function(x, y) {
33937     x = +x, y = +y;
33938     switch (this._point) {
33939       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33940       case 1: this._point = 2; // proceed
33941       default: {
33942         if (this._t <= 0) {
33943           this._context.lineTo(this._x, y);
33944           this._context.lineTo(x, y);
33945         } else {
33946           var x1 = this._x * (1 - this._t) + x * this._t;
33947           this._context.lineTo(x1, this._y);
33948           this._context.lineTo(x1, y);
33949         }
33950         break;
33951       }
33952     }
33953     this._x = x, this._y = y;
33954   }
33955 };
33956
33957 var step = function(context) {
33958   return new Step(context, 0.5);
33959 };
33960
33961 function stepBefore(context) {
33962   return new Step(context, 0);
33963 }
33964
33965 function stepAfter(context) {
33966   return new Step(context, 1);
33967 }
33968
33969 var slice$5 = Array.prototype.slice;
33970
33971 var none$1 = function(series, order) {
33972   if (!((n = series.length) > 1)) return;
33973   for (var i = 1, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
33974     s0 = s1, s1 = series[order[i]];
33975     for (var j = 0; j < m; ++j) {
33976       s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
33977     }
33978   }
33979 };
33980
33981 var none$2 = function(series) {
33982   var n = series.length, o = new Array(n);
33983   while (--n >= 0) o[n] = n;
33984   return o;
33985 };
33986
33987 function stackValue(d, key) {
33988   return d[key];
33989 }
33990
33991 var stack = function() {
33992   var keys = constant$10([]),
33993       order = none$2,
33994       offset = none$1,
33995       value = stackValue;
33996
33997   function stack(data) {
33998     var kz = keys.apply(this, arguments),
33999         i,
34000         m = data.length,
34001         n = kz.length,
34002         sz = new Array(n),
34003         oz;
34004
34005     for (i = 0; i < n; ++i) {
34006       for (var ki = kz[i], si = sz[i] = new Array(m), j = 0, sij; j < m; ++j) {
34007         si[j] = sij = [0, +value(data[j], ki, j, data)];
34008         sij.data = data[j];
34009       }
34010       si.key = ki;
34011     }
34012
34013     for (i = 0, oz = order(sz); i < n; ++i) {
34014       sz[oz[i]].index = i;
34015     }
34016
34017     offset(sz, oz);
34018     return sz;
34019   }
34020
34021   stack.keys = function(_) {
34022     return arguments.length ? (keys = typeof _ === "function" ? _ : constant$10(slice$5.call(_)), stack) : keys;
34023   };
34024
34025   stack.value = function(_) {
34026     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), stack) : value;
34027   };
34028
34029   stack.order = function(_) {
34030     return arguments.length ? (order = _ == null ? none$2 : typeof _ === "function" ? _ : constant$10(slice$5.call(_)), stack) : order;
34031   };
34032
34033   stack.offset = function(_) {
34034     return arguments.length ? (offset = _ == null ? none$1 : _, stack) : offset;
34035   };
34036
34037   return stack;
34038 };
34039
34040 var expand = function(series, order) {
34041   if (!((n = series.length) > 0)) return;
34042   for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {
34043     for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;
34044     if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;
34045   }
34046   none$1(series, order);
34047 };
34048
34049 var silhouette = function(series, order) {
34050   if (!((n = series.length) > 0)) return;
34051   for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
34052     for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;
34053     s0[j][1] += s0[j][0] = -y / 2;
34054   }
34055   none$1(series, order);
34056 };
34057
34058 var wiggle = function(series, order) {
34059   if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;
34060   for (var y = 0, j = 1, s0, m, n; j < m; ++j) {
34061     for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {
34062       var si = series[order[i]],
34063           sij0 = si[j][1] || 0,
34064           sij1 = si[j - 1][1] || 0,
34065           s3 = (sij0 - sij1) / 2;
34066       for (var k = 0; k < i; ++k) {
34067         var sk = series[order[k]],
34068             skj0 = sk[j][1] || 0,
34069             skj1 = sk[j - 1][1] || 0;
34070         s3 += skj0 - skj1;
34071       }
34072       s1 += sij0, s2 += s3 * sij0;
34073     }
34074     s0[j - 1][1] += s0[j - 1][0] = y;
34075     if (s1) y -= s2 / s1;
34076   }
34077   s0[j - 1][1] += s0[j - 1][0] = y;
34078   none$1(series, order);
34079 };
34080
34081 var ascending$2 = function(series) {
34082   var sums = series.map(sum$2);
34083   return none$2(series).sort(function(a, b) { return sums[a] - sums[b]; });
34084 };
34085
34086 function sum$2(series) {
34087   var s = 0, i = -1, n = series.length, v;
34088   while (++i < n) if (v = +series[i][1]) s += v;
34089   return s;
34090 }
34091
34092 var descending$2 = function(series) {
34093   return ascending$2(series).reverse();
34094 };
34095
34096 var insideOut = function(series) {
34097   var n = series.length,
34098       i,
34099       j,
34100       sums = series.map(sum$2),
34101       order = none$2(series).sort(function(a, b) { return sums[b] - sums[a]; }),
34102       top = 0,
34103       bottom = 0,
34104       tops = [],
34105       bottoms = [];
34106
34107   for (i = 0; i < n; ++i) {
34108     j = order[i];
34109     if (top < bottom) {
34110       top += sums[j];
34111       tops.push(j);
34112     } else {
34113       bottom += sums[j];
34114       bottoms.push(j);
34115     }
34116   }
34117
34118   return bottoms.reverse().concat(tops);
34119 };
34120
34121 var reverse = function(series) {
34122   return none$2(series).reverse();
34123 };
34124
34125 var constant$11 = function(x) {
34126   return function() {
34127     return x;
34128   };
34129 };
34130
34131 function x$4(d) {
34132   return d[0];
34133 }
34134
34135 function y$4(d) {
34136   return d[1];
34137 }
34138
34139 function RedBlackTree() {
34140   this._ = null; // root node
34141 }
34142
34143 function RedBlackNode(node) {
34144   node.U = // parent node
34145   node.C = // color - true for red, false for black
34146   node.L = // left node
34147   node.R = // right node
34148   node.P = // previous node
34149   node.N = null; // next node
34150 }
34151
34152 RedBlackTree.prototype = {
34153   constructor: RedBlackTree,
34154
34155   insert: function(after, node) {
34156     var parent, grandpa, uncle;
34157
34158     if (after) {
34159       node.P = after;
34160       node.N = after.N;
34161       if (after.N) after.N.P = node;
34162       after.N = node;
34163       if (after.R) {
34164         after = after.R;
34165         while (after.L) after = after.L;
34166         after.L = node;
34167       } else {
34168         after.R = node;
34169       }
34170       parent = after;
34171     } else if (this._) {
34172       after = RedBlackFirst(this._);
34173       node.P = null;
34174       node.N = after;
34175       after.P = after.L = node;
34176       parent = after;
34177     } else {
34178       node.P = node.N = null;
34179       this._ = node;
34180       parent = null;
34181     }
34182     node.L = node.R = null;
34183     node.U = parent;
34184     node.C = true;
34185
34186     after = node;
34187     while (parent && parent.C) {
34188       grandpa = parent.U;
34189       if (parent === grandpa.L) {
34190         uncle = grandpa.R;
34191         if (uncle && uncle.C) {
34192           parent.C = uncle.C = false;
34193           grandpa.C = true;
34194           after = grandpa;
34195         } else {
34196           if (after === parent.R) {
34197             RedBlackRotateLeft(this, parent);
34198             after = parent;
34199             parent = after.U;
34200           }
34201           parent.C = false;
34202           grandpa.C = true;
34203           RedBlackRotateRight(this, grandpa);
34204         }
34205       } else {
34206         uncle = grandpa.L;
34207         if (uncle && uncle.C) {
34208           parent.C = uncle.C = false;
34209           grandpa.C = true;
34210           after = grandpa;
34211         } else {
34212           if (after === parent.L) {
34213             RedBlackRotateRight(this, parent);
34214             after = parent;
34215             parent = after.U;
34216           }
34217           parent.C = false;
34218           grandpa.C = true;
34219           RedBlackRotateLeft(this, grandpa);
34220         }
34221       }
34222       parent = after.U;
34223     }
34224     this._.C = false;
34225   },
34226
34227   remove: function(node) {
34228     if (node.N) node.N.P = node.P;
34229     if (node.P) node.P.N = node.N;
34230     node.N = node.P = null;
34231
34232     var parent = node.U,
34233         sibling,
34234         left = node.L,
34235         right = node.R,
34236         next,
34237         red;
34238
34239     if (!left) next = right;
34240     else if (!right) next = left;
34241     else next = RedBlackFirst(right);
34242
34243     if (parent) {
34244       if (parent.L === node) parent.L = next;
34245       else parent.R = next;
34246     } else {
34247       this._ = next;
34248     }
34249
34250     if (left && right) {
34251       red = next.C;
34252       next.C = node.C;
34253       next.L = left;
34254       left.U = next;
34255       if (next !== right) {
34256         parent = next.U;
34257         next.U = node.U;
34258         node = next.R;
34259         parent.L = node;
34260         next.R = right;
34261         right.U = next;
34262       } else {
34263         next.U = parent;
34264         parent = next;
34265         node = next.R;
34266       }
34267     } else {
34268       red = node.C;
34269       node = next;
34270     }
34271
34272     if (node) node.U = parent;
34273     if (red) return;
34274     if (node && node.C) { node.C = false; return; }
34275
34276     do {
34277       if (node === this._) break;
34278       if (node === parent.L) {
34279         sibling = parent.R;
34280         if (sibling.C) {
34281           sibling.C = false;
34282           parent.C = true;
34283           RedBlackRotateLeft(this, parent);
34284           sibling = parent.R;
34285         }
34286         if ((sibling.L && sibling.L.C)
34287             || (sibling.R && sibling.R.C)) {
34288           if (!sibling.R || !sibling.R.C) {
34289             sibling.L.C = false;
34290             sibling.C = true;
34291             RedBlackRotateRight(this, sibling);
34292             sibling = parent.R;
34293           }
34294           sibling.C = parent.C;
34295           parent.C = sibling.R.C = false;
34296           RedBlackRotateLeft(this, parent);
34297           node = this._;
34298           break;
34299         }
34300       } else {
34301         sibling = parent.L;
34302         if (sibling.C) {
34303           sibling.C = false;
34304           parent.C = true;
34305           RedBlackRotateRight(this, parent);
34306           sibling = parent.L;
34307         }
34308         if ((sibling.L && sibling.L.C)
34309           || (sibling.R && sibling.R.C)) {
34310           if (!sibling.L || !sibling.L.C) {
34311             sibling.R.C = false;
34312             sibling.C = true;
34313             RedBlackRotateLeft(this, sibling);
34314             sibling = parent.L;
34315           }
34316           sibling.C = parent.C;
34317           parent.C = sibling.L.C = false;
34318           RedBlackRotateRight(this, parent);
34319           node = this._;
34320           break;
34321         }
34322       }
34323       sibling.C = true;
34324       node = parent;
34325       parent = parent.U;
34326     } while (!node.C);
34327
34328     if (node) node.C = false;
34329   }
34330 };
34331
34332 function RedBlackRotateLeft(tree, node) {
34333   var p = node,
34334       q = node.R,
34335       parent = p.U;
34336
34337   if (parent) {
34338     if (parent.L === p) parent.L = q;
34339     else parent.R = q;
34340   } else {
34341     tree._ = q;
34342   }
34343
34344   q.U = parent;
34345   p.U = q;
34346   p.R = q.L;
34347   if (p.R) p.R.U = p;
34348   q.L = p;
34349 }
34350
34351 function RedBlackRotateRight(tree, node) {
34352   var p = node,
34353       q = node.L,
34354       parent = p.U;
34355
34356   if (parent) {
34357     if (parent.L === p) parent.L = q;
34358     else parent.R = q;
34359   } else {
34360     tree._ = q;
34361   }
34362
34363   q.U = parent;
34364   p.U = q;
34365   p.L = q.R;
34366   if (p.L) p.L.U = p;
34367   q.R = p;
34368 }
34369
34370 function RedBlackFirst(node) {
34371   while (node.L) node = node.L;
34372   return node;
34373 }
34374
34375 function createEdge(left, right, v0, v1) {
34376   var edge = [null, null],
34377       index = edges.push(edge) - 1;
34378   edge.left = left;
34379   edge.right = right;
34380   if (v0) setEdgeEnd(edge, left, right, v0);
34381   if (v1) setEdgeEnd(edge, right, left, v1);
34382   cells[left.index].halfedges.push(index);
34383   cells[right.index].halfedges.push(index);
34384   return edge;
34385 }
34386
34387 function createBorderEdge(left, v0, v1) {
34388   var edge = [v0, v1];
34389   edge.left = left;
34390   return edge;
34391 }
34392
34393 function setEdgeEnd(edge, left, right, vertex) {
34394   if (!edge[0] && !edge[1]) {
34395     edge[0] = vertex;
34396     edge.left = left;
34397     edge.right = right;
34398   } else if (edge.left === right) {
34399     edge[1] = vertex;
34400   } else {
34401     edge[0] = vertex;
34402   }
34403 }
34404
34405 // Liang–Barsky line clipping.
34406 function clipEdge(edge, x0, y0, x1, y1) {
34407   var a = edge[0],
34408       b = edge[1],
34409       ax = a[0],
34410       ay = a[1],
34411       bx = b[0],
34412       by = b[1],
34413       t0 = 0,
34414       t1 = 1,
34415       dx = bx - ax,
34416       dy = by - ay,
34417       r;
34418
34419   r = x0 - ax;
34420   if (!dx && r > 0) return;
34421   r /= dx;
34422   if (dx < 0) {
34423     if (r < t0) return;
34424     if (r < t1) t1 = r;
34425   } else if (dx > 0) {
34426     if (r > t1) return;
34427     if (r > t0) t0 = r;
34428   }
34429
34430   r = x1 - ax;
34431   if (!dx && r < 0) return;
34432   r /= dx;
34433   if (dx < 0) {
34434     if (r > t1) return;
34435     if (r > t0) t0 = r;
34436   } else if (dx > 0) {
34437     if (r < t0) return;
34438     if (r < t1) t1 = r;
34439   }
34440
34441   r = y0 - ay;
34442   if (!dy && r > 0) return;
34443   r /= dy;
34444   if (dy < 0) {
34445     if (r < t0) return;
34446     if (r < t1) t1 = r;
34447   } else if (dy > 0) {
34448     if (r > t1) return;
34449     if (r > t0) t0 = r;
34450   }
34451
34452   r = y1 - ay;
34453   if (!dy && r < 0) return;
34454   r /= dy;
34455   if (dy < 0) {
34456     if (r > t1) return;
34457     if (r > t0) t0 = r;
34458   } else if (dy > 0) {
34459     if (r < t0) return;
34460     if (r < t1) t1 = r;
34461   }
34462
34463   if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check?
34464
34465   if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy];
34466   if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy];
34467   return true;
34468 }
34469
34470 function connectEdge(edge, x0, y0, x1, y1) {
34471   var v1 = edge[1];
34472   if (v1) return true;
34473
34474   var v0 = edge[0],
34475       left = edge.left,
34476       right = edge.right,
34477       lx = left[0],
34478       ly = left[1],
34479       rx = right[0],
34480       ry = right[1],
34481       fx = (lx + rx) / 2,
34482       fy = (ly + ry) / 2,
34483       fm,
34484       fb;
34485
34486   if (ry === ly) {
34487     if (fx < x0 || fx >= x1) return;
34488     if (lx > rx) {
34489       if (!v0) v0 = [fx, y0];
34490       else if (v0[1] >= y1) return;
34491       v1 = [fx, y1];
34492     } else {
34493       if (!v0) v0 = [fx, y1];
34494       else if (v0[1] < y0) return;
34495       v1 = [fx, y0];
34496     }
34497   } else {
34498     fm = (lx - rx) / (ry - ly);
34499     fb = fy - fm * fx;
34500     if (fm < -1 || fm > 1) {
34501       if (lx > rx) {
34502         if (!v0) v0 = [(y0 - fb) / fm, y0];
34503         else if (v0[1] >= y1) return;
34504         v1 = [(y1 - fb) / fm, y1];
34505       } else {
34506         if (!v0) v0 = [(y1 - fb) / fm, y1];
34507         else if (v0[1] < y0) return;
34508         v1 = [(y0 - fb) / fm, y0];
34509       }
34510     } else {
34511       if (ly < ry) {
34512         if (!v0) v0 = [x0, fm * x0 + fb];
34513         else if (v0[0] >= x1) return;
34514         v1 = [x1, fm * x1 + fb];
34515       } else {
34516         if (!v0) v0 = [x1, fm * x1 + fb];
34517         else if (v0[0] < x0) return;
34518         v1 = [x0, fm * x0 + fb];
34519       }
34520     }
34521   }
34522
34523   edge[0] = v0;
34524   edge[1] = v1;
34525   return true;
34526 }
34527
34528 function clipEdges(x0, y0, x1, y1) {
34529   var i = edges.length,
34530       edge;
34531
34532   while (i--) {
34533     if (!connectEdge(edge = edges[i], x0, y0, x1, y1)
34534         || !clipEdge(edge, x0, y0, x1, y1)
34535         || !(Math.abs(edge[0][0] - edge[1][0]) > epsilon$4
34536             || Math.abs(edge[0][1] - edge[1][1]) > epsilon$4)) {
34537       delete edges[i];
34538     }
34539   }
34540 }
34541
34542 function createCell(site) {
34543   return cells[site.index] = {
34544     site: site,
34545     halfedges: []
34546   };
34547 }
34548
34549 function cellHalfedgeAngle(cell, edge) {
34550   var site = cell.site,
34551       va = edge.left,
34552       vb = edge.right;
34553   if (site === vb) vb = va, va = site;
34554   if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]);
34555   if (site === va) va = edge[1], vb = edge[0];
34556   else va = edge[0], vb = edge[1];
34557   return Math.atan2(va[0] - vb[0], vb[1] - va[1]);
34558 }
34559
34560 function cellHalfedgeStart(cell, edge) {
34561   return edge[+(edge.left !== cell.site)];
34562 }
34563
34564 function cellHalfedgeEnd(cell, edge) {
34565   return edge[+(edge.left === cell.site)];
34566 }
34567
34568 function sortCellHalfedges() {
34569   for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) {
34570     if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) {
34571       var index = new Array(m),
34572           array = new Array(m);
34573       for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]);
34574       index.sort(function(i, j) { return array[j] - array[i]; });
34575       for (j = 0; j < m; ++j) array[j] = halfedges[index[j]];
34576       for (j = 0; j < m; ++j) halfedges[j] = array[j];
34577     }
34578   }
34579 }
34580
34581 function clipCells(x0, y0, x1, y1) {
34582   var nCells = cells.length,
34583       iCell,
34584       cell,
34585       site,
34586       iHalfedge,
34587       halfedges,
34588       nHalfedges,
34589       start,
34590       startX,
34591       startY,
34592       end,
34593       endX,
34594       endY,
34595       cover = true;
34596
34597   for (iCell = 0; iCell < nCells; ++iCell) {
34598     if (cell = cells[iCell]) {
34599       site = cell.site;
34600       halfedges = cell.halfedges;
34601       iHalfedge = halfedges.length;
34602
34603       // Remove any dangling clipped edges.
34604       while (iHalfedge--) {
34605         if (!edges[halfedges[iHalfedge]]) {
34606           halfedges.splice(iHalfedge, 1);
34607         }
34608       }
34609
34610       // Insert any border edges as necessary.
34611       iHalfedge = 0, nHalfedges = halfedges.length;
34612       while (iHalfedge < nHalfedges) {
34613         end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1];
34614         start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1];
34615         if (Math.abs(endX - startX) > epsilon$4 || Math.abs(endY - startY) > epsilon$4) {
34616           halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end,
34617               Math.abs(endX - x0) < epsilon$4 && y1 - endY > epsilon$4 ? [x0, Math.abs(startX - x0) < epsilon$4 ? startY : y1]
34618               : Math.abs(endY - y1) < epsilon$4 && x1 - endX > epsilon$4 ? [Math.abs(startY - y1) < epsilon$4 ? startX : x1, y1]
34619               : Math.abs(endX - x1) < epsilon$4 && endY - y0 > epsilon$4 ? [x1, Math.abs(startX - x1) < epsilon$4 ? startY : y0]
34620               : Math.abs(endY - y0) < epsilon$4 && endX - x0 > epsilon$4 ? [Math.abs(startY - y0) < epsilon$4 ? startX : x0, y0]
34621               : null)) - 1);
34622           ++nHalfedges;
34623         }
34624       }
34625
34626       if (nHalfedges) cover = false;
34627     }
34628   }
34629
34630   // If there weren’t any edges, have the closest site cover the extent.
34631   // It doesn’t matter which corner of the extent we measure!
34632   if (cover) {
34633     var dx, dy, d2, dc = Infinity;
34634
34635     for (iCell = 0, cover = null; iCell < nCells; ++iCell) {
34636       if (cell = cells[iCell]) {
34637         site = cell.site;
34638         dx = site[0] - x0;
34639         dy = site[1] - y0;
34640         d2 = dx * dx + dy * dy;
34641         if (d2 < dc) dc = d2, cover = cell;
34642       }
34643     }
34644
34645     if (cover) {
34646       var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0];
34647       cover.halfedges.push(
34648         edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1,
34649         edges.push(createBorderEdge(site, v01, v11)) - 1,
34650         edges.push(createBorderEdge(site, v11, v10)) - 1,
34651         edges.push(createBorderEdge(site, v10, v00)) - 1
34652       );
34653     }
34654   }
34655
34656   // Lastly delete any cells with no edges; these were entirely clipped.
34657   for (iCell = 0; iCell < nCells; ++iCell) {
34658     if (cell = cells[iCell]) {
34659       if (!cell.halfedges.length) {
34660         delete cells[iCell];
34661       }
34662     }
34663   }
34664 }
34665
34666 var circlePool = [];
34667
34668 var firstCircle;
34669
34670 function Circle() {
34671   RedBlackNode(this);
34672   this.x =
34673   this.y =
34674   this.arc =
34675   this.site =
34676   this.cy = null;
34677 }
34678
34679 function attachCircle(arc) {
34680   var lArc = arc.P,
34681       rArc = arc.N;
34682
34683   if (!lArc || !rArc) return;
34684
34685   var lSite = lArc.site,
34686       cSite = arc.site,
34687       rSite = rArc.site;
34688
34689   if (lSite === rSite) return;
34690
34691   var bx = cSite[0],
34692       by = cSite[1],
34693       ax = lSite[0] - bx,
34694       ay = lSite[1] - by,
34695       cx = rSite[0] - bx,
34696       cy = rSite[1] - by;
34697
34698   var d = 2 * (ax * cy - ay * cx);
34699   if (d >= -epsilon2$2) return;
34700
34701   var ha = ax * ax + ay * ay,
34702       hc = cx * cx + cy * cy,
34703       x = (cy * ha - ay * hc) / d,
34704       y = (ax * hc - cx * ha) / d;
34705
34706   var circle = circlePool.pop() || new Circle;
34707   circle.arc = arc;
34708   circle.site = cSite;
34709   circle.x = x + bx;
34710   circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom
34711
34712   arc.circle = circle;
34713
34714   var before = null,
34715       node = circles._;
34716
34717   while (node) {
34718     if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) {
34719       if (node.L) node = node.L;
34720       else { before = node.P; break; }
34721     } else {
34722       if (node.R) node = node.R;
34723       else { before = node; break; }
34724     }
34725   }
34726
34727   circles.insert(before, circle);
34728   if (!before) firstCircle = circle;
34729 }
34730
34731 function detachCircle(arc) {
34732   var circle = arc.circle;
34733   if (circle) {
34734     if (!circle.P) firstCircle = circle.N;
34735     circles.remove(circle);
34736     circlePool.push(circle);
34737     RedBlackNode(circle);
34738     arc.circle = null;
34739   }
34740 }
34741
34742 var beachPool = [];
34743
34744 function Beach() {
34745   RedBlackNode(this);
34746   this.edge =
34747   this.site =
34748   this.circle = null;
34749 }
34750
34751 function createBeach(site) {
34752   var beach = beachPool.pop() || new Beach;
34753   beach.site = site;
34754   return beach;
34755 }
34756
34757 function detachBeach(beach) {
34758   detachCircle(beach);
34759   beaches.remove(beach);
34760   beachPool.push(beach);
34761   RedBlackNode(beach);
34762 }
34763
34764 function removeBeach(beach) {
34765   var circle = beach.circle,
34766       x = circle.x,
34767       y = circle.cy,
34768       vertex = [x, y],
34769       previous = beach.P,
34770       next = beach.N,
34771       disappearing = [beach];
34772
34773   detachBeach(beach);
34774
34775   var lArc = previous;
34776   while (lArc.circle
34777       && Math.abs(x - lArc.circle.x) < epsilon$4
34778       && Math.abs(y - lArc.circle.cy) < epsilon$4) {
34779     previous = lArc.P;
34780     disappearing.unshift(lArc);
34781     detachBeach(lArc);
34782     lArc = previous;
34783   }
34784
34785   disappearing.unshift(lArc);
34786   detachCircle(lArc);
34787
34788   var rArc = next;
34789   while (rArc.circle
34790       && Math.abs(x - rArc.circle.x) < epsilon$4
34791       && Math.abs(y - rArc.circle.cy) < epsilon$4) {
34792     next = rArc.N;
34793     disappearing.push(rArc);
34794     detachBeach(rArc);
34795     rArc = next;
34796   }
34797
34798   disappearing.push(rArc);
34799   detachCircle(rArc);
34800
34801   var nArcs = disappearing.length,
34802       iArc;
34803   for (iArc = 1; iArc < nArcs; ++iArc) {
34804     rArc = disappearing[iArc];
34805     lArc = disappearing[iArc - 1];
34806     setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
34807   }
34808
34809   lArc = disappearing[0];
34810   rArc = disappearing[nArcs - 1];
34811   rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
34812
34813   attachCircle(lArc);
34814   attachCircle(rArc);
34815 }
34816
34817 function addBeach(site) {
34818   var x = site[0],
34819       directrix = site[1],
34820       lArc,
34821       rArc,
34822       dxl,
34823       dxr,
34824       node = beaches._;
34825
34826   while (node) {
34827     dxl = leftBreakPoint(node, directrix) - x;
34828     if (dxl > epsilon$4) node = node.L; else {
34829       dxr = x - rightBreakPoint(node, directrix);
34830       if (dxr > epsilon$4) {
34831         if (!node.R) {
34832           lArc = node;
34833           break;
34834         }
34835         node = node.R;
34836       } else {
34837         if (dxl > -epsilon$4) {
34838           lArc = node.P;
34839           rArc = node;
34840         } else if (dxr > -epsilon$4) {
34841           lArc = node;
34842           rArc = node.N;
34843         } else {
34844           lArc = rArc = node;
34845         }
34846         break;
34847       }
34848     }
34849   }
34850
34851   createCell(site);
34852   var newArc = createBeach(site);
34853   beaches.insert(lArc, newArc);
34854
34855   if (!lArc && !rArc) return;
34856
34857   if (lArc === rArc) {
34858     detachCircle(lArc);
34859     rArc = createBeach(lArc.site);
34860     beaches.insert(newArc, rArc);
34861     newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
34862     attachCircle(lArc);
34863     attachCircle(rArc);
34864     return;
34865   }
34866
34867   if (!rArc) { // && lArc
34868     newArc.edge = createEdge(lArc.site, newArc.site);
34869     return;
34870   }
34871
34872   // else lArc !== rArc
34873   detachCircle(lArc);
34874   detachCircle(rArc);
34875
34876   var lSite = lArc.site,
34877       ax = lSite[0],
34878       ay = lSite[1],
34879       bx = site[0] - ax,
34880       by = site[1] - ay,
34881       rSite = rArc.site,
34882       cx = rSite[0] - ax,
34883       cy = rSite[1] - ay,
34884       d = 2 * (bx * cy - by * cx),
34885       hb = bx * bx + by * by,
34886       hc = cx * cx + cy * cy,
34887       vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
34888
34889   setEdgeEnd(rArc.edge, lSite, rSite, vertex);
34890   newArc.edge = createEdge(lSite, site, null, vertex);
34891   rArc.edge = createEdge(site, rSite, null, vertex);
34892   attachCircle(lArc);
34893   attachCircle(rArc);
34894 }
34895
34896 function leftBreakPoint(arc, directrix) {
34897   var site = arc.site,
34898       rfocx = site[0],
34899       rfocy = site[1],
34900       pby2 = rfocy - directrix;
34901
34902   if (!pby2) return rfocx;
34903
34904   var lArc = arc.P;
34905   if (!lArc) return -Infinity;
34906
34907   site = lArc.site;
34908   var lfocx = site[0],
34909       lfocy = site[1],
34910       plby2 = lfocy - directrix;
34911
34912   if (!plby2) return lfocx;
34913
34914   var hl = lfocx - rfocx,
34915       aby2 = 1 / pby2 - 1 / plby2,
34916       b = hl / plby2;
34917
34918   if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
34919
34920   return (rfocx + lfocx) / 2;
34921 }
34922
34923 function rightBreakPoint(arc, directrix) {
34924   var rArc = arc.N;
34925   if (rArc) return leftBreakPoint(rArc, directrix);
34926   var site = arc.site;
34927   return site[1] === directrix ? site[0] : Infinity;
34928 }
34929
34930 var epsilon$4 = 1e-6;
34931 var epsilon2$2 = 1e-12;
34932 var beaches;
34933 var cells;
34934 var circles;
34935 var edges;
34936
34937 function triangleArea(a, b, c) {
34938   return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
34939 }
34940
34941 function lexicographic(a, b) {
34942   return b[1] - a[1]
34943       || b[0] - a[0];
34944 }
34945
34946 function Diagram(sites, extent) {
34947   var site = sites.sort(lexicographic).pop(),
34948       x,
34949       y,
34950       circle;
34951
34952   edges = [];
34953   cells = new Array(sites.length);
34954   beaches = new RedBlackTree;
34955   circles = new RedBlackTree;
34956
34957   while (true) {
34958     circle = firstCircle;
34959     if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
34960       if (site[0] !== x || site[1] !== y) {
34961         addBeach(site);
34962         x = site[0], y = site[1];
34963       }
34964       site = sites.pop();
34965     } else if (circle) {
34966       removeBeach(circle.arc);
34967     } else {
34968       break;
34969     }
34970   }
34971
34972   sortCellHalfedges();
34973
34974   if (extent) {
34975     var x0 = +extent[0][0],
34976         y0 = +extent[0][1],
34977         x1 = +extent[1][0],
34978         y1 = +extent[1][1];
34979     clipEdges(x0, y0, x1, y1);
34980     clipCells(x0, y0, x1, y1);
34981   }
34982
34983   this.edges = edges;
34984   this.cells = cells;
34985
34986   beaches =
34987   circles =
34988   edges =
34989   cells = null;
34990 }
34991
34992 Diagram.prototype = {
34993   constructor: Diagram,
34994
34995   polygons: function() {
34996     var edges = this.edges;
34997
34998     return this.cells.map(function(cell) {
34999       var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
35000       polygon.data = cell.site.data;
35001       return polygon;
35002     });
35003   },
35004
35005   triangles: function() {
35006     var triangles = [],
35007         edges = this.edges;
35008
35009     this.cells.forEach(function(cell, i) {
35010       if (!(m = (halfedges = cell.halfedges).length)) return;
35011       var site = cell.site,
35012           halfedges,
35013           j = -1,
35014           m,
35015           s0,
35016           e1 = edges[halfedges[m - 1]],
35017           s1 = e1.left === site ? e1.right : e1.left;
35018
35019       while (++j < m) {
35020         s0 = s1;
35021         e1 = edges[halfedges[j]];
35022         s1 = e1.left === site ? e1.right : e1.left;
35023         if (s0 && s1 && i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
35024           triangles.push([site.data, s0.data, s1.data]);
35025         }
35026       }
35027     });
35028
35029     return triangles;
35030   },
35031
35032   links: function() {
35033     return this.edges.filter(function(edge) {
35034       return edge.right;
35035     }).map(function(edge) {
35036       return {
35037         source: edge.left.data,
35038         target: edge.right.data
35039       };
35040     });
35041   },
35042
35043   find: function(x, y, radius) {
35044     var that = this, i0, i1 = that._found || 0, n = that.cells.length, cell;
35045
35046     // Use the previously-found cell, or start with an arbitrary one.
35047     while (!(cell = that.cells[i1])) if (++i1 >= n) return null;
35048     var dx = x - cell.site[0], dy = y - cell.site[1], d2 = dx * dx + dy * dy;
35049
35050     // Traverse the half-edges to find a closer cell, if any.
35051     do {
35052       cell = that.cells[i0 = i1], i1 = null;
35053       cell.halfedges.forEach(function(e) {
35054         var edge = that.edges[e], v = edge.left;
35055         if ((v === cell.site || !v) && !(v = edge.right)) return;
35056         var vx = x - v[0], vy = y - v[1], v2 = vx * vx + vy * vy;
35057         if (v2 < d2) d2 = v2, i1 = v.index;
35058       });
35059     } while (i1 !== null);
35060
35061     that._found = i0;
35062
35063     return radius == null || d2 <= radius * radius ? cell.site : null;
35064   }
35065 };
35066
35067 var voronoi = function() {
35068   var x$$1 = x$4,
35069       y$$1 = y$4,
35070       extent = null;
35071
35072   function voronoi(data) {
35073     return new Diagram(data.map(function(d, i) {
35074       var s = [Math.round(x$$1(d, i, data) / epsilon$4) * epsilon$4, Math.round(y$$1(d, i, data) / epsilon$4) * epsilon$4];
35075       s.index = i;
35076       s.data = d;
35077       return s;
35078     }), extent);
35079   }
35080
35081   voronoi.polygons = function(data) {
35082     return voronoi(data).polygons();
35083   };
35084
35085   voronoi.links = function(data) {
35086     return voronoi(data).links();
35087   };
35088
35089   voronoi.triangles = function(data) {
35090     return voronoi(data).triangles();
35091   };
35092
35093   voronoi.x = function(_) {
35094     return arguments.length ? (x$$1 = typeof _ === "function" ? _ : constant$11(+_), voronoi) : x$$1;
35095   };
35096
35097   voronoi.y = function(_) {
35098     return arguments.length ? (y$$1 = typeof _ === "function" ? _ : constant$11(+_), voronoi) : y$$1;
35099   };
35100
35101   voronoi.extent = function(_) {
35102     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]]];
35103   };
35104
35105   voronoi.size = function(_) {
35106     return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0] - extent[0][0], extent[1][1] - extent[0][1]];
35107   };
35108
35109   return voronoi;
35110 };
35111
35112 var constant$12 = function(x) {
35113   return function() {
35114     return x;
35115   };
35116 };
35117
35118 function ZoomEvent(target, type, transform) {
35119   this.target = target;
35120   this.type = type;
35121   this.transform = transform;
35122 }
35123
35124 function Transform(k, x, y) {
35125   this.k = k;
35126   this.x = x;
35127   this.y = y;
35128 }
35129
35130 Transform.prototype = {
35131   constructor: Transform,
35132   scale: function(k) {
35133     return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
35134   },
35135   translate: function(x, y) {
35136     return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
35137   },
35138   apply: function(point) {
35139     return [point[0] * this.k + this.x, point[1] * this.k + this.y];
35140   },
35141   applyX: function(x) {
35142     return x * this.k + this.x;
35143   },
35144   applyY: function(y) {
35145     return y * this.k + this.y;
35146   },
35147   invert: function(location) {
35148     return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
35149   },
35150   invertX: function(x) {
35151     return (x - this.x) / this.k;
35152   },
35153   invertY: function(y) {
35154     return (y - this.y) / this.k;
35155   },
35156   rescaleX: function(x) {
35157     return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
35158   },
35159   rescaleY: function(y) {
35160     return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
35161   },
35162   toString: function() {
35163     return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
35164   }
35165 };
35166
35167 var identity$8 = new Transform(1, 0, 0);
35168
35169 transform$1.prototype = Transform.prototype;
35170
35171 function transform$1(node) {
35172   return node.__zoom || identity$8;
35173 }
35174
35175 function nopropagation$2() {
35176   event.stopImmediatePropagation();
35177 }
35178
35179 var noevent$2 = function() {
35180   event.preventDefault();
35181   event.stopImmediatePropagation();
35182 };
35183
35184 // Ignore right-click, since that should open the context menu.
35185 function defaultFilter$2() {
35186   return !event.button;
35187 }
35188
35189 function defaultExtent$1() {
35190   var e = this, w, h;
35191   if (e instanceof SVGElement) {
35192     e = e.ownerSVGElement || e;
35193     w = e.width.baseVal.value;
35194     h = e.height.baseVal.value;
35195   } else {
35196     w = e.clientWidth;
35197     h = e.clientHeight;
35198   }
35199   return [[0, 0], [w, h]];
35200 }
35201
35202 function defaultTransform() {
35203   return this.__zoom || identity$8;
35204 }
35205
35206 var zoom = function() {
35207   var filter = defaultFilter$2,
35208       extent = defaultExtent$1,
35209       k0 = 0,
35210       k1 = Infinity,
35211       x0 = -k1,
35212       x1 = k1,
35213       y0 = x0,
35214       y1 = x1,
35215       duration = 250,
35216       interpolate$$1 = interpolateZoom,
35217       gestures = [],
35218       listeners = dispatch("start", "zoom", "end"),
35219       touchstarting,
35220       touchending,
35221       touchDelay = 500,
35222       wheelDelay = 150;
35223
35224   function zoom(selection$$1) {
35225     selection$$1
35226         .on("wheel.zoom", wheeled)
35227         .on("mousedown.zoom", mousedowned)
35228         .on("dblclick.zoom", dblclicked)
35229         .on("touchstart.zoom", touchstarted)
35230         .on("touchmove.zoom", touchmoved)
35231         .on("touchend.zoom touchcancel.zoom", touchended)
35232         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
35233         .property("__zoom", defaultTransform);
35234   }
35235
35236   zoom.transform = function(collection, transform) {
35237     var selection$$1 = collection.selection ? collection.selection() : collection;
35238     selection$$1.property("__zoom", defaultTransform);
35239     if (collection !== selection$$1) {
35240       schedule(collection, transform);
35241     } else {
35242       selection$$1.interrupt().each(function() {
35243         gesture(this, arguments)
35244             .start()
35245             .zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform)
35246             .end();
35247       });
35248     }
35249   };
35250
35251   zoom.scaleBy = function(selection$$1, k) {
35252     zoom.scaleTo(selection$$1, function() {
35253       var k0 = this.__zoom.k,
35254           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35255       return k0 * k1;
35256     });
35257   };
35258
35259   zoom.scaleTo = function(selection$$1, k) {
35260     zoom.transform(selection$$1, function() {
35261       var e = extent.apply(this, arguments),
35262           t0 = this.__zoom,
35263           p0 = centroid(e),
35264           p1 = t0.invert(p0),
35265           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35266       return constrain(translate(scale(t0, k1), p0, p1), e);
35267     });
35268   };
35269
35270   zoom.translateBy = function(selection$$1, x, y) {
35271     zoom.transform(selection$$1, function() {
35272       return constrain(this.__zoom.translate(
35273         typeof x === "function" ? x.apply(this, arguments) : x,
35274         typeof y === "function" ? y.apply(this, arguments) : y
35275       ), extent.apply(this, arguments));
35276     });
35277   };
35278
35279   function scale(transform, k) {
35280     k = Math.max(k0, Math.min(k1, k));
35281     return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
35282   }
35283
35284   function translate(transform, p0, p1) {
35285     var x = p0[0] - p1[0] * transform.k, y = p0[1] - p1[1] * transform.k;
35286     return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
35287   }
35288
35289   function constrain(transform, extent) {
35290     var dx0 = transform.invertX(extent[0][0]) - x0,
35291         dx1 = transform.invertX(extent[1][0]) - x1,
35292         dy0 = transform.invertY(extent[0][1]) - y0,
35293         dy1 = transform.invertY(extent[1][1]) - y1;
35294     return transform.translate(
35295       dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
35296       dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
35297     );
35298   }
35299
35300   function centroid(extent) {
35301     return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
35302   }
35303
35304   function schedule(transition$$1, transform, center) {
35305     transition$$1
35306         .on("start.zoom", function() { gesture(this, arguments).start(); })
35307         .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).end(); })
35308         .tween("zoom", function() {
35309           var that = this,
35310               args = arguments,
35311               g = gesture(that, args),
35312               e = extent.apply(that, args),
35313               p = center || centroid(e),
35314               w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
35315               a = that.__zoom,
35316               b = typeof transform === "function" ? transform.apply(that, args) : transform,
35317               i = interpolate$$1(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
35318           return function(t) {
35319             if (t === 1) t = b; // Avoid rounding error on end.
35320             else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); }
35321             g.zoom(null, t);
35322           };
35323         });
35324   }
35325
35326   function gesture(that, args) {
35327     for (var i = 0, n = gestures.length, g; i < n; ++i) {
35328       if ((g = gestures[i]).that === that) {
35329         return g;
35330       }
35331     }
35332     return new Gesture(that, args);
35333   }
35334
35335   function Gesture(that, args) {
35336     this.that = that;
35337     this.args = args;
35338     this.index = -1;
35339     this.active = 0;
35340     this.extent = extent.apply(that, args);
35341   }
35342
35343   Gesture.prototype = {
35344     start: function() {
35345       if (++this.active === 1) {
35346         this.index = gestures.push(this) - 1;
35347         this.emit("start");
35348       }
35349       return this;
35350     },
35351     zoom: function(key, transform) {
35352       if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
35353       if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
35354       if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
35355       this.that.__zoom = transform;
35356       this.emit("zoom");
35357       return this;
35358     },
35359     end: function() {
35360       if (--this.active === 0) {
35361         gestures.splice(this.index, 1);
35362         this.index = -1;
35363         this.emit("end");
35364       }
35365       return this;
35366     },
35367     emit: function(type) {
35368       customEvent(new ZoomEvent(zoom, type, this.that.__zoom), listeners.apply, listeners, [type, this.that, this.args]);
35369     }
35370   };
35371
35372   function wheeled() {
35373     if (!filter.apply(this, arguments)) return;
35374     var g = gesture(this, arguments),
35375         t = this.__zoom,
35376         k = Math.max(k0, Math.min(k1, t.k * Math.pow(2, -event.deltaY * (event.deltaMode ? 120 : 1) / 500))),
35377         p = mouse(this);
35378
35379     // If the mouse is in the same location as before, reuse it.
35380     // If there were recent wheel events, reset the wheel idle timeout.
35381     if (g.wheel) {
35382       if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
35383         g.mouse[1] = t.invert(g.mouse[0] = p);
35384       }
35385       clearTimeout(g.wheel);
35386     }
35387
35388     // If this wheel event won’t trigger a transform change, ignore it.
35389     else if (t.k === k) return;
35390
35391     // Otherwise, capture the mouse point and location at the start.
35392     else {
35393       g.mouse = [p, t.invert(p)];
35394       interrupt(this);
35395       g.start();
35396     }
35397
35398     noevent$2();
35399     g.wheel = setTimeout(wheelidled, wheelDelay);
35400     g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent));
35401
35402     function wheelidled() {
35403       g.wheel = null;
35404       g.end();
35405     }
35406   }
35407
35408   function mousedowned() {
35409     if (touchending || !filter.apply(this, arguments)) return;
35410     var g = gesture(this, arguments),
35411         v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
35412         p = mouse(this);
35413
35414     dragDisable(event.view);
35415     nopropagation$2();
35416     g.mouse = [p, this.__zoom.invert(p)];
35417     interrupt(this);
35418     g.start();
35419
35420     function mousemoved() {
35421       noevent$2();
35422       g.moved = true;
35423       g.zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = mouse(g.that), g.mouse[1]), g.extent));
35424     }
35425
35426     function mouseupped() {
35427       v.on("mousemove.zoom mouseup.zoom", null);
35428       yesdrag(event.view, g.moved);
35429       noevent$2();
35430       g.end();
35431     }
35432   }
35433
35434   function dblclicked() {
35435     if (!filter.apply(this, arguments)) return;
35436     var t0 = this.__zoom,
35437         p0 = mouse(this),
35438         p1 = t0.invert(p0),
35439         k1 = t0.k * (event.shiftKey ? 0.5 : 2),
35440         t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, arguments));
35441
35442     noevent$2();
35443     if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0);
35444     else select(this).call(zoom.transform, t1);
35445   }
35446
35447   function touchstarted() {
35448     if (!filter.apply(this, arguments)) return;
35449     var g = gesture(this, arguments),
35450         touches$$1 = event.changedTouches,
35451         started,
35452         n = touches$$1.length, i, t, p;
35453
35454     nopropagation$2();
35455     for (i = 0; i < n; ++i) {
35456       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35457       p = [p, this.__zoom.invert(p), t.identifier];
35458       if (!g.touch0) g.touch0 = p, started = true;
35459       else if (!g.touch1) g.touch1 = p;
35460     }
35461
35462     // If this is a dbltap, reroute to the (optional) dblclick.zoom handler.
35463     if (touchstarting) {
35464       touchstarting = clearTimeout(touchstarting);
35465       if (!g.touch1) {
35466         g.end();
35467         p = select(this).on("dblclick.zoom");
35468         if (p) p.apply(this, arguments);
35469         return;
35470       }
35471     }
35472
35473     if (started) {
35474       touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);
35475       interrupt(this);
35476       g.start();
35477     }
35478   }
35479
35480   function touchmoved() {
35481     var g = gesture(this, arguments),
35482         touches$$1 = event.changedTouches,
35483         n = touches$$1.length, i, t, p, l;
35484
35485     noevent$2();
35486     if (touchstarting) touchstarting = clearTimeout(touchstarting);
35487     for (i = 0; i < n; ++i) {
35488       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35489       if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;
35490       else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
35491     }
35492     t = g.that.__zoom;
35493     if (g.touch1) {
35494       var p0 = g.touch0[0], l0 = g.touch0[1],
35495           p1 = g.touch1[0], l1 = g.touch1[1],
35496           dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
35497           dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
35498       t = scale(t, Math.sqrt(dp / dl));
35499       p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
35500       l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
35501     }
35502     else if (g.touch0) p = g.touch0[0], l = g.touch0[1];
35503     else return;
35504     g.zoom("touch", constrain(translate(t, p, l), g.extent));
35505   }
35506
35507   function touchended() {
35508     var g = gesture(this, arguments),
35509         touches$$1 = event.changedTouches,
35510         n = touches$$1.length, i, t;
35511
35512     nopropagation$2();
35513     if (touchending) clearTimeout(touchending);
35514     touchending = setTimeout(function() { touchending = null; }, touchDelay);
35515     for (i = 0; i < n; ++i) {
35516       t = touches$$1[i];
35517       if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;
35518       else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
35519     }
35520     if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
35521     if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);
35522     else g.end();
35523   }
35524
35525   zoom.filter = function(_) {
35526     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$12(!!_), zoom) : filter;
35527   };
35528
35529   zoom.extent = function(_) {
35530     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$12([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
35531   };
35532
35533   zoom.scaleExtent = function(_) {
35534     return arguments.length ? (k0 = +_[0], k1 = +_[1], zoom) : [k0, k1];
35535   };
35536
35537   zoom.translateExtent = function(_) {
35538     return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], zoom) : [[x0, y0], [x1, y1]];
35539   };
35540
35541   zoom.duration = function(_) {
35542     return arguments.length ? (duration = +_, zoom) : duration;
35543   };
35544
35545   zoom.interpolate = function(_) {
35546     return arguments.length ? (interpolate$$1 = _, zoom) : interpolate$$1;
35547   };
35548
35549   zoom.on = function() {
35550     var value = listeners.on.apply(listeners, arguments);
35551     return value === listeners ? zoom : value;
35552   };
35553
35554   return zoom;
35555 };
35556
35557
35558
35559 var index$2 = Object.freeze({
35560         version: version,
35561         bisect: bisectRight,
35562         bisectRight: bisectRight,
35563         bisectLeft: bisectLeft,
35564         ascending: ascending,
35565         bisector: bisector,
35566         cross: cross,
35567         descending: descending,
35568         deviation: deviation,
35569         extent: extent,
35570         histogram: histogram,
35571         thresholdFreedmanDiaconis: freedmanDiaconis,
35572         thresholdScott: scott,
35573         thresholdSturges: sturges,
35574         max: max,
35575         mean: mean,
35576         median: median,
35577         merge: merge,
35578         min: min,
35579         pairs: pairs,
35580         permute: permute,
35581         quantile: threshold,
35582         range: sequence,
35583         scan: scan,
35584         shuffle: shuffle,
35585         sum: sum,
35586         ticks: ticks,
35587         tickIncrement: tickIncrement,
35588         tickStep: tickStep,
35589         transpose: transpose,
35590         variance: variance,
35591         zip: zip,
35592         axisTop: axisTop,
35593         axisRight: axisRight,
35594         axisBottom: axisBottom,
35595         axisLeft: axisLeft,
35596         brush: brush,
35597         brushX: brushX,
35598         brushY: brushY,
35599         brushSelection: brushSelection,
35600         chord: chord,
35601         ribbon: ribbon,
35602         nest: nest,
35603         set: set$2,
35604         map: map$1,
35605         keys: keys,
35606         values: values,
35607         entries: entries,
35608         color: color,
35609         rgb: rgb,
35610         hsl: hsl,
35611         lab: lab,
35612         hcl: hcl,
35613         cubehelix: cubehelix,
35614         dispatch: dispatch,
35615         drag: drag,
35616         dragDisable: dragDisable,
35617         dragEnable: yesdrag,
35618         dsvFormat: dsv,
35619         csvParse: csvParse,
35620         csvParseRows: csvParseRows,
35621         csvFormat: csvFormat,
35622         csvFormatRows: csvFormatRows,
35623         tsvParse: tsvParse,
35624         tsvParseRows: tsvParseRows,
35625         tsvFormat: tsvFormat,
35626         tsvFormatRows: tsvFormatRows,
35627         easeLinear: linear$1,
35628         easeQuad: quadInOut,
35629         easeQuadIn: quadIn,
35630         easeQuadOut: quadOut,
35631         easeQuadInOut: quadInOut,
35632         easeCubic: cubicInOut,
35633         easeCubicIn: cubicIn,
35634         easeCubicOut: cubicOut,
35635         easeCubicInOut: cubicInOut,
35636         easePoly: polyInOut,
35637         easePolyIn: polyIn,
35638         easePolyOut: polyOut,
35639         easePolyInOut: polyInOut,
35640         easeSin: sinInOut,
35641         easeSinIn: sinIn,
35642         easeSinOut: sinOut,
35643         easeSinInOut: sinInOut,
35644         easeExp: expInOut,
35645         easeExpIn: expIn,
35646         easeExpOut: expOut,
35647         easeExpInOut: expInOut,
35648         easeCircle: circleInOut,
35649         easeCircleIn: circleIn,
35650         easeCircleOut: circleOut,
35651         easeCircleInOut: circleInOut,
35652         easeBounce: bounceOut,
35653         easeBounceIn: bounceIn,
35654         easeBounceOut: bounceOut,
35655         easeBounceInOut: bounceInOut,
35656         easeBack: backInOut,
35657         easeBackIn: backIn,
35658         easeBackOut: backOut,
35659         easeBackInOut: backInOut,
35660         easeElastic: elasticOut,
35661         easeElasticIn: elasticIn,
35662         easeElasticOut: elasticOut,
35663         easeElasticInOut: elasticInOut,
35664         forceCenter: center$1,
35665         forceCollide: collide,
35666         forceLink: link,
35667         forceManyBody: manyBody,
35668         forceSimulation: simulation,
35669         forceX: x$2,
35670         forceY: y$2,
35671         formatDefaultLocale: defaultLocale,
35672         get format () { return format; },
35673         get formatPrefix () { return formatPrefix; },
35674         formatLocale: formatLocale,
35675         formatSpecifier: formatSpecifier,
35676         precisionFixed: precisionFixed,
35677         precisionPrefix: precisionPrefix,
35678         precisionRound: precisionRound,
35679         geoArea: area,
35680         geoBounds: bounds,
35681         geoCentroid: d3GeoCentroid,
35682         geoCircle: circle,
35683         geoClipExtent: extent$1,
35684         geoContains: contains,
35685         geoDistance: distance,
35686         geoGraticule: graticule,
35687         geoGraticule10: graticule10,
35688         geoInterpolate: interpolate$1,
35689         geoLength: d3GeoLength,
35690         geoPath: index$4,
35691         geoAlbers: albers,
35692         geoAlbersUsa: albersUsa,
35693         geoAzimuthalEqualArea: azimuthalEqualArea,
35694         geoAzimuthalEqualAreaRaw: azimuthalEqualAreaRaw,
35695         geoAzimuthalEquidistant: azimuthalEquidistant,
35696         geoAzimuthalEquidistantRaw: azimuthalEquidistantRaw,
35697         geoConicConformal: conicConformal,
35698         geoConicConformalRaw: conicConformalRaw,
35699         geoConicEqualArea: conicEqualArea,
35700         geoConicEqualAreaRaw: conicEqualAreaRaw,
35701         geoConicEquidistant: conicEquidistant,
35702         geoConicEquidistantRaw: conicEquidistantRaw,
35703         geoEquirectangular: equirectangular,
35704         geoEquirectangularRaw: equirectangularRaw,
35705         geoGnomonic: gnomonic,
35706         geoGnomonicRaw: gnomonicRaw,
35707         geoIdentity: identity$5,
35708         geoProjection: projection,
35709         geoProjectionMutator: projectionMutator,
35710         geoMercator: mercator,
35711         geoMercatorRaw: mercatorRaw,
35712         geoOrthographic: orthographic,
35713         geoOrthographicRaw: orthographicRaw,
35714         geoStereographic: stereographic,
35715         geoStereographicRaw: stereographicRaw,
35716         geoTransverseMercator: transverseMercator,
35717         geoTransverseMercatorRaw: transverseMercatorRaw,
35718         geoRotation: rotation,
35719         geoStream: geoStream,
35720         geoTransform: transform,
35721         cluster: cluster,
35722         hierarchy: hierarchy,
35723         pack: index$5,
35724         packSiblings: siblings,
35725         packEnclose: enclose,
35726         partition: partition,
35727         stratify: stratify,
35728         tree: tree,
35729         treemap: index$6,
35730         treemapBinary: binary,
35731         treemapDice: treemapDice,
35732         treemapSlice: treemapSlice,
35733         treemapSliceDice: sliceDice,
35734         treemapSquarify: squarify,
35735         treemapResquarify: resquarify,
35736         interpolate: interpolateValue,
35737         interpolateArray: array$1,
35738         interpolateBasis: basis$1,
35739         interpolateBasisClosed: basisClosed,
35740         interpolateDate: date,
35741         interpolateNumber: reinterpolate,
35742         interpolateObject: object,
35743         interpolateRound: interpolateRound,
35744         interpolateString: interpolateString,
35745         interpolateTransformCss: interpolateTransformCss,
35746         interpolateTransformSvg: interpolateTransformSvg,
35747         interpolateZoom: interpolateZoom,
35748         interpolateRgb: interpolateRgb,
35749         interpolateRgbBasis: rgbBasis,
35750         interpolateRgbBasisClosed: rgbBasisClosed,
35751         interpolateHsl: hsl$2,
35752         interpolateHslLong: hslLong,
35753         interpolateLab: lab$1,
35754         interpolateHcl: hcl$2,
35755         interpolateHclLong: hclLong,
35756         interpolateCubehelix: cubehelix$2,
35757         interpolateCubehelixLong: cubehelixLong,
35758         quantize: quantize,
35759         path: path,
35760         polygonArea: d3polygonArea,
35761         polygonCentroid: d3polygonCentroid,
35762         polygonHull: d3polygonHull,
35763         polygonContains: contains$1,
35764         polygonLength: length$1,
35765         quadtree: quadtree,
35766         queue: queue,
35767         randomUniform: uniform,
35768         randomNormal: normal,
35769         randomLogNormal: logNormal,
35770         randomBates: bates,
35771         randomIrwinHall: irwinHall,
35772         randomExponential: exponential$1,
35773         request: request,
35774         html: html,
35775         json: json,
35776         text: text,
35777         xml: xml,
35778         csv: csv$1,
35779         tsv: tsv$1,
35780         scaleBand: band,
35781         scalePoint: point$1,
35782         scaleIdentity: identity$6,
35783         scaleLinear: linear$2,
35784         scaleLog: log$1,
35785         scaleOrdinal: ordinal,
35786         scaleImplicit: implicit,
35787         scalePow: pow$1,
35788         scaleSqrt: sqrt$1,
35789         scaleQuantile: quantile$$1,
35790         scaleQuantize: quantize$1,
35791         scaleThreshold: threshold$1,
35792         scaleTime: time,
35793         scaleUtc: utcTime,
35794         schemeCategory10: category10,
35795         schemeCategory20b: category20b,
35796         schemeCategory20c: category20c,
35797         schemeCategory20: category20,
35798         interpolateCubehelixDefault: cubehelix$3,
35799         interpolateRainbow: rainbow$1,
35800         interpolateWarm: warm,
35801         interpolateCool: cool,
35802         interpolateViridis: viridis,
35803         interpolateMagma: magma,
35804         interpolateInferno: inferno,
35805         interpolatePlasma: plasma,
35806         scaleSequential: sequential,
35807         creator: creator,
35808         local: local$1,
35809         matcher: matcher$1,
35810         mouse: mouse,
35811         namespace: namespace,
35812         namespaces: namespaces,
35813         select: select,
35814         selectAll: selectAll,
35815         selection: selection,
35816         selector: selector,
35817         selectorAll: selectorAll,
35818         touch: touch,
35819         touches: touches,
35820         window: window$1,
35821         get event () { return event; },
35822         customEvent: customEvent,
35823         arc: arc,
35824         area: area$1,
35825         line: line,
35826         pie: pie,
35827         radialArea: radialArea,
35828         radialLine: radialLine$1,
35829         symbol: symbol,
35830         symbols: symbols,
35831         symbolCircle: circle$2,
35832         symbolCross: cross$2,
35833         symbolDiamond: diamond,
35834         symbolSquare: square,
35835         symbolStar: star,
35836         symbolTriangle: triangle,
35837         symbolWye: wye,
35838         curveBasisClosed: basisClosed$1,
35839         curveBasisOpen: basisOpen,
35840         curveBasis: basis$2,
35841         curveBundle: bundle,
35842         curveCardinalClosed: cardinalClosed,
35843         curveCardinalOpen: cardinalOpen,
35844         curveCardinal: cardinal,
35845         curveCatmullRomClosed: catmullRomClosed,
35846         curveCatmullRomOpen: catmullRomOpen,
35847         curveCatmullRom: catmullRom,
35848         curveLinearClosed: linearClosed,
35849         curveLinear: curveLinear,
35850         curveMonotoneX: monotoneX,
35851         curveMonotoneY: monotoneY,
35852         curveNatural: natural,
35853         curveStep: step,
35854         curveStepAfter: stepAfter,
35855         curveStepBefore: stepBefore,
35856         stack: stack,
35857         stackOffsetExpand: expand,
35858         stackOffsetNone: none$1,
35859         stackOffsetSilhouette: silhouette,
35860         stackOffsetWiggle: wiggle,
35861         stackOrderAscending: ascending$2,
35862         stackOrderDescending: descending$2,
35863         stackOrderInsideOut: insideOut,
35864         stackOrderNone: none$2,
35865         stackOrderReverse: reverse,
35866         timeInterval: newInterval,
35867         timeMillisecond: millisecond,
35868         timeMilliseconds: milliseconds,
35869         utcMillisecond: millisecond,
35870         utcMilliseconds: milliseconds,
35871         timeSecond: second,
35872         timeSeconds: seconds,
35873         utcSecond: second,
35874         utcSeconds: seconds,
35875         timeMinute: minute,
35876         timeMinutes: minutes,
35877         timeHour: hour,
35878         timeHours: hours,
35879         timeDay: day,
35880         timeDays: days,
35881         timeWeek: sunday,
35882         timeWeeks: sundays,
35883         timeSunday: sunday,
35884         timeSundays: sundays,
35885         timeMonday: monday,
35886         timeMondays: mondays,
35887         timeTuesday: tuesday,
35888         timeTuesdays: tuesdays,
35889         timeWednesday: wednesday,
35890         timeWednesdays: wednesdays,
35891         timeThursday: thursday,
35892         timeThursdays: thursdays,
35893         timeFriday: friday,
35894         timeFridays: fridays,
35895         timeSaturday: saturday,
35896         timeSaturdays: saturdays,
35897         timeMonth: month,
35898         timeMonths: months,
35899         timeYear: year,
35900         timeYears: years,
35901         utcMinute: utcMinute,
35902         utcMinutes: utcMinutes,
35903         utcHour: utcHour,
35904         utcHours: utcHours,
35905         utcDay: utcDay,
35906         utcDays: utcDays,
35907         utcWeek: utcSunday,
35908         utcWeeks: utcSundays,
35909         utcSunday: utcSunday,
35910         utcSundays: utcSundays,
35911         utcMonday: utcMonday,
35912         utcMondays: utcMondays,
35913         utcTuesday: utcTuesday,
35914         utcTuesdays: utcTuesdays,
35915         utcWednesday: utcWednesday,
35916         utcWednesdays: utcWednesdays,
35917         utcThursday: utcThursday,
35918         utcThursdays: utcThursdays,
35919         utcFriday: utcFriday,
35920         utcFridays: utcFridays,
35921         utcSaturday: utcSaturday,
35922         utcSaturdays: utcSaturdays,
35923         utcMonth: utcMonth,
35924         utcMonths: utcMonths,
35925         utcYear: utcYear,
35926         utcYears: utcYears,
35927         timeFormatDefaultLocale: defaultLocale$1,
35928         get timeFormat () { return timeFormat; },
35929         get timeParse () { return timeParse; },
35930         get utcFormat () { return utcFormat; },
35931         get utcParse () { return utcParse; },
35932         timeFormatLocale: formatLocale$1,
35933         isoFormat: formatIso,
35934         isoParse: parseIso,
35935         now: now,
35936         timer: timer,
35937         timerFlush: timerFlush,
35938         timeout: timeout$1,
35939         interval: interval$1,
35940         transition: transition,
35941         active: active,
35942         interrupt: interrupt,
35943         voronoi: voronoi,
35944         zoom: zoom,
35945         zoomTransform: transform$1,
35946         zoomIdentity: identity$8
35947 });
35948
35949 /*
35950     Bypasses features of D3's default projection stream pipeline that are unnecessary:
35951     * Antimeridian clipping
35952     * Spherical rotation
35953     * Resampling
35954 */
35955 function geoRawMercator() {
35956     var project = mercatorRaw,
35957         k = 512 / Math.PI, // scale
35958         x = 0, y = 0, // translate
35959         clipExtent = [[0, 0], [0, 0]];
35960
35961
35962     function projection(point) {
35963         point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
35964         return [point[0] * k + x, y - point[1] * k];
35965     }
35966
35967
35968     projection.invert = function(point) {
35969         point = project.invert((point[0] - x) / k, (y - point[1]) / k);
35970         return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
35971     };
35972
35973
35974     projection.scale = function(_) {
35975         if (!arguments.length) return k;
35976         k = +_;
35977         return projection;
35978     };
35979
35980
35981     projection.translate = function(_) {
35982         if (!arguments.length) return [x, y];
35983         x = +_[0];
35984         y = +_[1];
35985         return projection;
35986     };
35987
35988
35989     projection.clipExtent = function(_) {
35990         if (!arguments.length) return clipExtent;
35991         clipExtent = _;
35992         return projection;
35993     };
35994
35995
35996     projection.transform = function(_) {
35997         if (!arguments.length) return identity$8.translate(x, y).scale(k);
35998         x = +_.x;
35999         y = +_.y;
36000         k = +_.k;
36001         return projection;
36002     };
36003
36004
36005     projection.stream = transform({
36006         point: function(x, y) {
36007             x = projection([x, y]);
36008             this.stream.point(x[0], x[1]);
36009         }
36010     }).stream;
36011
36012
36013     return projection;
36014 }
36015
36016 function osmChangeset() {
36017     if (!(this instanceof osmChangeset)) {
36018         return (new osmChangeset()).initialize(arguments);
36019     } else if (arguments.length) {
36020         this.initialize(arguments);
36021     }
36022 }
36023
36024
36025 osmEntity$$1.changeset = osmChangeset;
36026
36027 osmChangeset.prototype = Object.create(osmEntity$$1.prototype);
36028
36029 lodash.extend(osmChangeset.prototype, {
36030
36031     type: 'changeset',
36032
36033
36034     extent: function() {
36035         return new geoExtent$$1();
36036     },
36037
36038
36039     geometry: function() {
36040         return 'changeset';
36041     },
36042
36043
36044     asJXON: function() {
36045         return {
36046             osm: {
36047                 changeset: {
36048                     tag: lodash.map(this.tags, function(value, key) {
36049                         return { '@k': key, '@v': value };
36050                     }),
36051                     '@version': 0.6,
36052                     '@generator': 'iD'
36053                 }
36054             }
36055         };
36056     },
36057
36058
36059     // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
36060     // XML. Returns a string.
36061     osmChangeJXON: function(changes) {
36062         var changeset_id = this.id;
36063
36064         function nest(x, order) {
36065             var groups = {};
36066             for (var i = 0; i < x.length; i++) {
36067                 var tagName = Object.keys(x[i])[0];
36068                 if (!groups[tagName]) groups[tagName] = [];
36069                 groups[tagName].push(x[i][tagName]);
36070             }
36071             var ordered = {};
36072             order.forEach(function(o) {
36073                 if (groups[o]) ordered[o] = groups[o];
36074             });
36075             return ordered;
36076         }
36077
36078
36079         // sort relations in a changeset by dependencies
36080         function sort(changes) {
36081
36082             // find a referenced relation in the current changeset
36083             function resolve(item) {
36084                 return lodash.find(relations, function(relation) {
36085                     return item.keyAttributes.type === 'relation'
36086                         && item.keyAttributes.ref === relation['@id'];
36087                 });
36088             }
36089
36090             // a new item is an item that has not been already processed
36091             function isNew(item) {
36092                 return !sorted[ item['@id'] ] && !lodash.find(processing, function(proc) {
36093                     return proc['@id'] === item['@id'];
36094                 });
36095             }
36096
36097             var processing = [],
36098                 sorted = {},
36099                 relations = changes.relation;
36100
36101             if (!relations) return changes;
36102
36103             for (var i = 0; i < relations.length; i++) {
36104                 var relation = relations[i];
36105
36106                 // skip relation if already sorted
36107                 if (!sorted[relation['@id']]) {
36108                     processing.push(relation);
36109                 }
36110
36111                 while (processing.length > 0) {
36112                     var next = processing[0],
36113                     deps = lodash.filter(lodash.compact(next.member.map(resolve)), isNew);
36114                     if (deps.length === 0) {
36115                         sorted[next['@id']] = next;
36116                         processing.shift();
36117                     } else {
36118                         processing = deps.concat(processing);
36119                     }
36120                 }
36121             }
36122
36123             changes.relation = lodash.values(sorted);
36124             return changes;
36125         }
36126
36127         function rep(entity) {
36128             return entity.asJXON(changeset_id);
36129         }
36130
36131         return {
36132             osmChange: {
36133                 '@version': 0.6,
36134                 '@generator': 'iD',
36135                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
36136                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
36137                 'delete': lodash.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), { '@if-unused': true })
36138             }
36139         };
36140     },
36141
36142
36143     asGeoJSON: function() {
36144         return {};
36145     }
36146
36147 });
36148
36149 function osmNode() {
36150     if (!(this instanceof osmNode)) {
36151         return (new osmNode()).initialize(arguments);
36152     } else if (arguments.length) {
36153         this.initialize(arguments);
36154     }
36155 }
36156
36157 osmEntity$$1.node = osmNode;
36158
36159 osmNode.prototype = Object.create(osmEntity$$1.prototype);
36160
36161 lodash.extend(osmNode.prototype, {
36162
36163     type: 'node',
36164
36165
36166     extent: function() {
36167         return new geoExtent$$1(this.loc);
36168     },
36169
36170
36171     geometry: function(graph) {
36172         return graph.transient(this, 'geometry', function() {
36173             return graph.isPoi(this) ? 'point' : 'vertex';
36174         });
36175     },
36176
36177
36178     move: function(loc) {
36179         return this.update({loc: loc});
36180     },
36181
36182
36183     isDegenerate: function() {
36184         return !(
36185             Array.isArray(this.loc) && this.loc.length === 2 &&
36186             this.loc[0] >= -180 && this.loc[0] <= 180 &&
36187             this.loc[1] >= -90 && this.loc[1] <= 90
36188         );
36189     },
36190
36191
36192     isEndpoint: function(resolver) {
36193         return resolver.transient(this, 'isEndpoint', function() {
36194             var id = this.id;
36195             return resolver.parentWays(this).filter(function(parent) {
36196                 return !parent.isClosed() && !!parent.affix(id);
36197             }).length > 0;
36198         });
36199     },
36200
36201
36202     isConnected: function(resolver) {
36203         return resolver.transient(this, 'isConnected', function() {
36204             var parents = resolver.parentWays(this);
36205
36206             function isLine(entity) {
36207                 return entity.geometry(resolver) === 'line' &&
36208                     entity.hasInterestingTags();
36209             }
36210
36211             // vertex is connected to multiple parent lines
36212             if (parents.length > 1 && lodash.some(parents, isLine)) {
36213                 return true;
36214
36215             } else if (parents.length === 1) {
36216                 var way = parents[0],
36217                     nodes = way.nodes.slice();
36218                 if (way.isClosed()) { nodes.pop(); }  // ignore connecting node if closed
36219
36220                 // return true if vertex appears multiple times (way is self intersecting)
36221                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
36222             }
36223
36224             return false;
36225         });
36226     },
36227
36228
36229     isIntersection: function(resolver) {
36230         return resolver.transient(this, 'isIntersection', function() {
36231             return resolver.parentWays(this).filter(function(parent) {
36232                 return (parent.tags.highway ||
36233                     parent.tags.waterway ||
36234                     parent.tags.railway ||
36235                     parent.tags.aeroway) &&
36236                     parent.geometry(resolver) === 'line';
36237             }).length > 1;
36238         });
36239     },
36240
36241
36242     isHighwayIntersection: function(resolver) {
36243         return resolver.transient(this, 'isHighwayIntersection', function() {
36244             return resolver.parentWays(this).filter(function(parent) {
36245                 return parent.tags.highway && parent.geometry(resolver) === 'line';
36246             }).length > 1;
36247         });
36248     },
36249
36250
36251     isOnAddressLine: function(resolver) {
36252         return resolver.transient(this, 'isOnAddressLine', function() {
36253             return resolver.parentWays(this).filter(function(parent) {
36254                 return parent.tags.hasOwnProperty('addr:interpolation') &&
36255                     parent.geometry(resolver) === 'line';
36256             }).length > 0;
36257         });
36258     },
36259
36260
36261     asJXON: function(changeset_id) {
36262         var r = {
36263             node: {
36264                 '@id': this.osmId(),
36265                 '@lon': this.loc[0],
36266                 '@lat': this.loc[1],
36267                 '@version': (this.version || 0),
36268                 tag: lodash.map(this.tags, function(v, k) {
36269                     return { keyAttributes: { k: k, v: v } };
36270                 })
36271             }
36272         };
36273         if (changeset_id) r.node['@changeset'] = changeset_id;
36274         return r;
36275     },
36276
36277
36278     asGeoJSON: function() {
36279         return {
36280             type: 'Point',
36281             coordinates: this.loc
36282         };
36283     }
36284 });
36285
36286 /*
36287   Order the nodes of a way in reverse order and reverse any direction dependent tags
36288   other than `oneway`. (We assume that correcting a backwards oneway is the primary
36289   reason for reversing a way.)
36290
36291   The following transforms are performed:
36292
36293     Keys:
36294           *:right=* ⟺ *:left=*
36295         *:forward=* ⟺ *:backward=*
36296        direction=up ⟺ direction=down
36297          incline=up ⟺ incline=down
36298             *=right ⟺ *=left
36299
36300     Relation members:
36301        role=forward ⟺ role=backward
36302          role=north ⟺ role=south
36303           role=east ⟺ role=west
36304
36305    In addition, numeric-valued `incline` tags are negated.
36306
36307    The JOSM implementation was used as a guide, but transformations that were of unclear benefit
36308    or adjusted tags that don't seem to be used in practice were omitted.
36309
36310    Also, each node on the way is examined for its own tags and the following transformations are performed
36311    in order to ensure associated nodes (eg a Stop Sign) is also reversed
36312
36313     Node Keys:
36314         direction=forward ⟺ direction=backward
36315         direction=left ⟺ direction=right
36316         *:forward=* ⟺ *:backward=*
36317         *:left=* ⟺ *:right=*
36318
36319    References:
36320       http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
36321       http://wiki.openstreetmap.org/wiki/Key:direction#Steps
36322       http://wiki.openstreetmap.org/wiki/Key:incline
36323       http://wiki.openstreetmap.org/wiki/Route#Members
36324       http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
36325       http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
36326       http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
36327  */
36328 function actionReverse(wayId, options) {
36329     var replacements = [
36330             [/:right$/, ':left'], [/:left$/, ':right'],
36331             [/:forward$/, ':backward'], [/:backward$/, ':forward']
36332         ],
36333         numeric = /^([+\-]?)(?=[\d.])/,
36334         roleReversals = {
36335             forward: 'backward',
36336             backward: 'forward',
36337             north: 'south',
36338             south: 'north',
36339             east: 'west',
36340             west: 'east'
36341         };
36342
36343
36344     function reverseKey(key) {
36345         for (var i = 0; i < replacements.length; ++i) {
36346             var replacement = replacements[i];
36347             if (replacement[0].test(key)) {
36348                 return key.replace(replacement[0], replacement[1]);
36349             }
36350         }
36351         return key;
36352     }
36353
36354
36355     function reverseValue(key, value) {
36356         if (key === 'incline' && numeric.test(value)) {
36357             return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
36358         } else if (key === 'incline' || key === 'direction') {
36359             return {up: 'down', down: 'up'}[value] || value;
36360         } else if (options && options.reverseOneway && key === 'oneway') {
36361             return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
36362         } else {
36363             return {left: 'right', right: 'left'}[value] || value;
36364         }
36365     }
36366
36367
36368     function reverseDirectionTags(node) {
36369         // Update the direction based tags as appropriate then return an updated node
36370         return node.update({tags: lodash.transform(node.tags, function(acc, tagValue, tagKey) {
36371             // See if this is a direction tag and reverse (or use existing value if not recognised)
36372             if (tagKey === 'direction') {
36373                 acc[tagKey] = {forward: 'backward', backward: 'forward', left: 'right', right: 'left'}[tagValue] || tagValue;
36374             } else {
36375                 // Use the reverseKey method to cater for situations such as traffic_sign:forward=stop
36376                 // This will pass through other tags unchanged
36377                 acc[reverseKey(tagKey)] = tagValue;
36378             }
36379             return acc;
36380         }, {})});
36381     }
36382
36383
36384     function reverseTagsOnNodes(graph, nodeIds) {
36385         // Reverse the direction of appropriate tags attached to the nodes (#3076)
36386         return lodash(nodeIds)
36387             // Get each node from the graph
36388             .map(function(nodeId) { return graph.entity(nodeId);})
36389             // Check tags on the node, if there aren't any, we can skip
36390             .filter(function(existingNode) { return existingNode.tags !== undefined;})
36391             // Get a new version of each node with the appropriate tags reversed
36392             .map(function(existingNode) { return reverseDirectionTags(existingNode);})
36393             // Chain together consecutive updates to the graph for each updated node and return
36394             .reduce(function (accGraph, value) { return accGraph.replace(value); }, graph);
36395     }
36396
36397
36398     return function(graph) {
36399         var way = graph.entity(wayId),
36400             nodes = way.nodes.slice().reverse(),
36401             tags = {}, key, role;
36402
36403         for (key in way.tags) {
36404             tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
36405         }
36406
36407         graph.parentRelations(way).forEach(function(relation) {
36408             relation.members.forEach(function(member, index) {
36409                 if (member.id === way.id && (role = roleReversals[member.role])) {
36410                     relation = relation.updateMember({role: role}, index);
36411                     graph = graph.replace(relation);
36412                 }
36413             });
36414         });
36415
36416         // Reverse any associated directions on nodes on the way and then replace
36417         // the way itself with the reversed node ids and updated way tags
36418         return reverseTagsOnNodes(graph, nodes).replace(way.update({nodes: nodes, tags: tags}));
36419     };
36420 }
36421
36422 // For fixing up rendering of multipolygons with tags on the outer member.
36423 // https://github.com/openstreetmap/iD/issues/613
36424 function osmIsSimpleMultipolygonOuterMember(entity, graph) {
36425     if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0)
36426         return false;
36427
36428     var parents = graph.parentRelations(entity);
36429     if (parents.length !== 1)
36430         return false;
36431
36432     var parent = parents[0];
36433     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36434         return false;
36435
36436     var members = parent.members, member;
36437     for (var i = 0; i < members.length; i++) {
36438         member = members[i];
36439         if (member.id === entity.id && member.role && member.role !== 'outer')
36440             return false; // Not outer member
36441         if (member.id !== entity.id && (!member.role || member.role === 'outer'))
36442             return false; // Not a simple multipolygon
36443     }
36444
36445     return parent;
36446 }
36447
36448
36449 function osmSimpleMultipolygonOuterMember(entity, graph) {
36450     if (entity.type !== 'way')
36451         return false;
36452
36453     var parents = graph.parentRelations(entity);
36454     if (parents.length !== 1)
36455         return false;
36456
36457     var parent = parents[0];
36458     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36459         return false;
36460
36461     var members = parent.members, member, outerMember;
36462     for (var i = 0; i < members.length; i++) {
36463         member = members[i];
36464         if (!member.role || member.role === 'outer') {
36465             if (outerMember)
36466                 return false; // Not a simple multipolygon
36467             outerMember = member;
36468         }
36469     }
36470
36471     if (!outerMember)
36472         return false;
36473
36474     var outerEntity = graph.hasEntity(outerMember.id);
36475     if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length)
36476         return false;
36477
36478     return outerEntity;
36479 }
36480
36481
36482 // Join `array` into sequences of connecting ways.
36483 //
36484 // Segments which share identical start/end nodes will, as much as possible,
36485 // be connected with each other.
36486 //
36487 // The return value is a nested array. Each constituent array contains elements
36488 // of `array` which have been determined to connect. Each consitituent array
36489 // also has a `nodes` property whose value is an ordered array of member nodes,
36490 // with appropriate order reversal and start/end coordinate de-duplication.
36491 //
36492 // Members of `array` must have, at minimum, `type` and `id` properties.
36493 // Thus either an array of `osmWay`s or a relation member array may be
36494 // used.
36495 //
36496 // If an member has a `tags` property, its tags will be reversed via
36497 // `actionReverse` in the output.
36498 //
36499 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
36500 // false) and non-way members are ignored.
36501 //
36502 function osmJoinWays(array, graph) {
36503     var joined = [], member, current, nodes, first, last, i, how, what;
36504
36505     array = array.filter(function(member) {
36506         return member.type === 'way' && graph.hasEntity(member.id);
36507     });
36508
36509     function resolve(member) {
36510         return graph.childNodes(graph.entity(member.id));
36511     }
36512
36513     function reverse(member) {
36514         return member.tags ? actionReverse(member.id, { reverseOneway: true })(graph).entity(member.id) : member;
36515     }
36516
36517     while (array.length) {
36518         member = array.shift();
36519         current = [member];
36520         current.nodes = nodes = resolve(member).slice();
36521         joined.push(current);
36522
36523         while (array.length && lodash.first(nodes) !== lodash.last(nodes)) {
36524             first = lodash.first(nodes);
36525             last  = lodash.last(nodes);
36526
36527             for (i = 0; i < array.length; i++) {
36528                 member = array[i];
36529                 what = resolve(member);
36530
36531                 if (last === lodash.first(what)) {
36532                     how  = nodes.push;
36533                     what = what.slice(1);
36534                     break;
36535                 } else if (last === lodash.last(what)) {
36536                     how  = nodes.push;
36537                     what = what.slice(0, -1).reverse();
36538                     member = reverse(member);
36539                     break;
36540                 } else if (first === lodash.last(what)) {
36541                     how  = nodes.unshift;
36542                     what = what.slice(0, -1);
36543                     break;
36544                 } else if (first === lodash.first(what)) {
36545                     how  = nodes.unshift;
36546                     what = what.slice(1).reverse();
36547                     member = reverse(member);
36548                     break;
36549                 } else {
36550                     what = how = null;
36551                 }
36552             }
36553
36554             if (!what)
36555                 break; // No more joinable ways.
36556
36557             how.apply(current, [member]);
36558             how.apply(nodes, what);
36559
36560             array.splice(i, 1);
36561         }
36562     }
36563
36564     return joined;
36565 }
36566
36567 function osmRelation() {
36568     if (!(this instanceof osmRelation)) {
36569         return (new osmRelation()).initialize(arguments);
36570     } else if (arguments.length) {
36571         this.initialize(arguments);
36572     }
36573 }
36574
36575
36576 osmEntity$$1.relation = osmRelation;
36577
36578 osmRelation.prototype = Object.create(osmEntity$$1.prototype);
36579
36580
36581 osmRelation.creationOrder = function(a, b) {
36582     var aId = parseInt(osmEntity$$1.id.toOSM(a.id), 10);
36583     var bId = parseInt(osmEntity$$1.id.toOSM(b.id), 10);
36584
36585     if (aId < 0 || bId < 0) return aId - bId;
36586     return bId - aId;
36587 };
36588
36589
36590 lodash.extend(osmRelation.prototype, {
36591     type: 'relation',
36592     members: [],
36593
36594
36595     copy: function(resolver, copies) {
36596         if (copies[this.id])
36597             return copies[this.id];
36598
36599         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
36600
36601         var members = this.members.map(function(member) {
36602             return lodash.extend({}, member, { id: resolver.entity(member.id).copy(resolver, copies).id });
36603         });
36604
36605         copy = copy.update({members: members});
36606         copies[this.id] = copy;
36607
36608         return copy;
36609     },
36610
36611
36612     extent: function(resolver, memo) {
36613         return resolver.transient(this, 'extent', function() {
36614             if (memo && memo[this.id]) return geoExtent$$1();
36615             memo = memo || {};
36616             memo[this.id] = true;
36617
36618             var extent$$1 = geoExtent$$1();
36619             for (var i = 0; i < this.members.length; i++) {
36620                 var member = resolver.hasEntity(this.members[i].id);
36621                 if (member) {
36622                     extent$$1._extend(member.extent(resolver, memo));
36623                 }
36624             }
36625             return extent$$1;
36626         });
36627     },
36628
36629
36630     geometry: function(graph) {
36631         return graph.transient(this, 'geometry', function() {
36632             return this.isMultipolygon() ? 'area' : 'relation';
36633         });
36634     },
36635
36636
36637     isDegenerate: function() {
36638         return this.members.length === 0;
36639     },
36640
36641
36642     // Return an array of members, each extended with an 'index' property whose value
36643     // is the member index.
36644     indexedMembers: function() {
36645         var result = new Array(this.members.length);
36646         for (var i = 0; i < this.members.length; i++) {
36647             result[i] = lodash.extend({}, this.members[i], {index: i});
36648         }
36649         return result;
36650     },
36651
36652
36653     // Return the first member with the given role. A copy of the member object
36654     // is returned, extended with an 'index' property whose value is the member index.
36655     memberByRole: function(role) {
36656         for (var i = 0; i < this.members.length; i++) {
36657             if (this.members[i].role === role) {
36658                 return lodash.extend({}, this.members[i], {index: i});
36659             }
36660         }
36661     },
36662
36663
36664     // Return the first member with the given id. A copy of the member object
36665     // is returned, extended with an 'index' property whose value is the member index.
36666     memberById: function(id) {
36667         for (var i = 0; i < this.members.length; i++) {
36668             if (this.members[i].id === id) {
36669                 return lodash.extend({}, this.members[i], {index: i});
36670             }
36671         }
36672     },
36673
36674
36675     // Return the first member with the given id and role. A copy of the member object
36676     // is returned, extended with an 'index' property whose value is the member index.
36677     memberByIdAndRole: function(id, role) {
36678         for (var i = 0; i < this.members.length; i++) {
36679             if (this.members[i].id === id && this.members[i].role === role) {
36680                 return lodash.extend({}, this.members[i], {index: i});
36681             }
36682         }
36683     },
36684
36685
36686     addMember: function(member, index) {
36687         var members = this.members.slice();
36688         members.splice(index === undefined ? members.length : index, 0, member);
36689         return this.update({members: members});
36690     },
36691
36692
36693     updateMember: function(member, index) {
36694         var members = this.members.slice();
36695         members.splice(index, 1, lodash.extend({}, members[index], member));
36696         return this.update({members: members});
36697     },
36698
36699
36700     removeMember: function(index) {
36701         var members = this.members.slice();
36702         members.splice(index, 1);
36703         return this.update({members: members});
36704     },
36705
36706
36707     removeMembersWithID: function(id) {
36708         var members = lodash.reject(this.members, function(m) { return m.id === id; });
36709         return this.update({members: members});
36710     },
36711
36712
36713     // Wherever a member appears with id `needle.id`, replace it with a member
36714     // with id `replacement.id`, type `replacement.type`, and the original role,
36715     // unless a member already exists with that id and role. Return an updated
36716     // relation.
36717     replaceMember: function(needle, replacement) {
36718         if (!this.memberById(needle.id))
36719             return this;
36720
36721         var members = [];
36722
36723         for (var i = 0; i < this.members.length; i++) {
36724             var member = this.members[i];
36725             if (member.id !== needle.id) {
36726                 members.push(member);
36727             } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
36728                 members.push({id: replacement.id, type: replacement.type, role: member.role});
36729             }
36730         }
36731
36732         return this.update({members: members});
36733     },
36734
36735
36736     asJXON: function(changeset_id) {
36737         var r = {
36738             relation: {
36739                 '@id': this.osmId(),
36740                 '@version': this.version || 0,
36741                 member: lodash.map(this.members, function(member) {
36742                     return {
36743                         keyAttributes: {
36744                             type: member.type,
36745                             role: member.role,
36746                             ref: osmEntity$$1.id.toOSM(member.id)
36747                         }
36748                     };
36749                 }),
36750                 tag: lodash.map(this.tags, function(v, k) {
36751                     return { keyAttributes: { k: k, v: v } };
36752                 })
36753             }
36754         };
36755         if (changeset_id) r.relation['@changeset'] = changeset_id;
36756         return r;
36757     },
36758
36759
36760     asGeoJSON: function(resolver) {
36761         return resolver.transient(this, 'GeoJSON', function () {
36762             if (this.isMultipolygon()) {
36763                 return {
36764                     type: 'MultiPolygon',
36765                     coordinates: this.multipolygon(resolver)
36766                 };
36767             } else {
36768                 return {
36769                     type: 'FeatureCollection',
36770                     properties: this.tags,
36771                     features: this.members.map(function (member) {
36772                         return lodash.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
36773                     })
36774                 };
36775             }
36776         });
36777     },
36778
36779
36780     area: function(resolver) {
36781         return resolver.transient(this, 'area', function() {
36782             return area(this.asGeoJSON(resolver));
36783         });
36784     },
36785
36786
36787     isMultipolygon: function() {
36788         return this.tags.type === 'multipolygon';
36789     },
36790
36791
36792     isComplete: function(resolver) {
36793         for (var i = 0; i < this.members.length; i++) {
36794             if (!resolver.hasEntity(this.members[i].id)) {
36795                 return false;
36796             }
36797         }
36798         return true;
36799     },
36800
36801
36802     isRestriction: function() {
36803         return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
36804     },
36805
36806
36807     // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
36808     // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
36809     //
36810     // This corresponds to the structure needed for rendering a multipolygon path using a
36811     // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
36812     //
36813     // In the case of invalid geometries, this function will still return a result which
36814     // includes the nodes of all way members, but some Nds may be unclosed and some inner
36815     // rings not matched with the intended outer ring.
36816     //
36817     multipolygon: function(resolver) {
36818         var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
36819             inners = this.members.filter(function(m) { return 'inner' === m.role; });
36820
36821         outers = osmJoinWays(outers, resolver);
36822         inners = osmJoinWays(inners, resolver);
36823
36824         outers = outers.map(function(outer) { return lodash.map(outer.nodes, 'loc'); });
36825         inners = inners.map(function(inner) { return lodash.map(inner.nodes, 'loc'); });
36826
36827         var result = outers.map(function(o) {
36828             // Heuristic for detecting counterclockwise winding order. Assumes
36829             // that OpenStreetMap polygons are not hemisphere-spanning.
36830             return [area({ type: 'Polygon', coordinates: [o] }) > 2 * Math.PI ? o.reverse() : o];
36831         });
36832
36833         function findOuter(inner) {
36834             var o, outer;
36835
36836             for (o = 0; o < outers.length; o++) {
36837                 outer = outers[o];
36838                 if (geoPolygonContainsPolygon(outer, inner))
36839                     return o;
36840             }
36841
36842             for (o = 0; o < outers.length; o++) {
36843                 outer = outers[o];
36844                 if (geoPolygonIntersectsPolygon(outer, inner, false))
36845                     return o;
36846             }
36847         }
36848
36849         for (var i = 0; i < inners.length; i++) {
36850             var inner = inners[i];
36851
36852             if (area({ type: 'Polygon', coordinates: [inner] }) < 2 * Math.PI) {
36853                 inner = inner.reverse();
36854             }
36855
36856             var o = findOuter(inners[i]);
36857             if (o !== undefined)
36858                 result[o].push(inners[i]);
36859             else
36860                 result.push([inners[i]]); // Invalid geometry
36861         }
36862
36863         return result;
36864     }
36865 });
36866
36867 function osmLanes(entity) {
36868     if (entity.type !== 'way') return null;
36869     if (!entity.tags.highway) return null;
36870
36871     var tags = entity.tags;
36872     var isOneWay = entity.isOneWay();
36873     var laneCount = getLaneCount(tags, isOneWay);
36874     var maxspeed = parseMaxspeed(tags);
36875
36876     var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
36877     var forward = laneDirections.forward;
36878     var backward = laneDirections.backward;
36879     var bothways = laneDirections.bothways;
36880
36881     // parse the piped string 'x|y|z' format
36882     var turnLanes = {};
36883     turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
36884     turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
36885     turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
36886
36887     var maxspeedLanes = {};
36888     maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
36889     maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
36890     maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
36891
36892     var psvLanes = {};
36893     psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
36894     psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
36895     psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
36896
36897     var busLanes = {};
36898     busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
36899     busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
36900     busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
36901
36902     var taxiLanes = {};
36903     taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
36904     taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
36905     taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
36906
36907     var hovLanes = {};
36908     hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
36909     hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
36910     hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
36911
36912     var hgvLanes = {};
36913     hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
36914     hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
36915     hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
36916
36917     var bicyclewayLanes = {};
36918     bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
36919     bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
36920     bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
36921
36922     var lanesObj = {
36923         forward: [],
36924         backward: [],
36925         unspecified: []
36926     };
36927
36928     // map forward/backward/unspecified of each lane type to lanesObj
36929     mapToLanesObj(lanesObj, turnLanes, 'turnLane');
36930     mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
36931     mapToLanesObj(lanesObj, psvLanes, 'psv');
36932     mapToLanesObj(lanesObj, busLanes, 'bus');
36933     mapToLanesObj(lanesObj, taxiLanes, 'taxi');
36934     mapToLanesObj(lanesObj, hovLanes, 'hov');
36935     mapToLanesObj(lanesObj, hgvLanes, 'hgv');
36936     mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
36937
36938     return {
36939         metadata: {
36940             count: laneCount,
36941             oneway: isOneWay,
36942             forward: forward,
36943             backward: backward,
36944             bothways: bothways,
36945             turnLanes: turnLanes,
36946             maxspeed: maxspeed,
36947             maxspeedLanes: maxspeedLanes,
36948             psvLanes: psvLanes,
36949             busLanes: busLanes,
36950             taxiLanes: taxiLanes,
36951             hovLanes: hovLanes,
36952             hgvLanes: hgvLanes,
36953             bicyclewayLanes: bicyclewayLanes
36954         },
36955         lanes: lanesObj
36956     };
36957 }
36958
36959
36960 function getLaneCount(tags, isOneWay) {
36961     var count;
36962     if (tags.lanes) {
36963         count = parseInt(tags.lanes, 10);
36964         if (count > 0) {
36965             return count;
36966         }
36967     }
36968
36969
36970     switch (tags.highway) {
36971         case 'trunk':
36972         case 'motorway':
36973             count = isOneWay ? 2 : 4;
36974             break;
36975         default:
36976             count = isOneWay ? 1 : 2;
36977             break;
36978     }
36979
36980     return count;
36981 }
36982
36983
36984 function parseMaxspeed(tags) {
36985     var maxspeed = tags.maxspeed;
36986     if (lodash.isNumber(maxspeed)) return maxspeed;
36987     if (lodash.isString(maxspeed)) {
36988         maxspeed = maxspeed.match(/^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/g);
36989         if (!maxspeed) return;
36990         return parseInt(maxspeed, 10);
36991     }
36992 }
36993
36994
36995 function parseLaneDirections(tags, isOneWay, laneCount) {
36996     var forward = parseInt(tags['lanes:forward'], 10);
36997     var backward = parseInt(tags['lanes:backward'], 10);
36998     var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
36999
37000     if (parseInt(tags.oneway, 10) === -1) {
37001         forward = 0;
37002         bothways = 0;
37003         backward = laneCount;
37004     }
37005     else if (isOneWay) {
37006         forward = laneCount;
37007         bothways = 0;
37008         backward = 0;
37009     }
37010     else if (lodash.isNaN(forward) && lodash.isNaN(backward)) {
37011         backward = Math.floor((laneCount - bothways) / 2);
37012         forward = laneCount - bothways - backward;
37013     }
37014     else if (lodash.isNaN(forward)) {
37015         if (backward > laneCount - bothways) {
37016             backward = laneCount - bothways;
37017         }
37018         forward = laneCount - bothways - backward;
37019     }
37020     else if (lodash.isNaN(backward)) {
37021         if (forward > laneCount - bothways) {
37022             forward = laneCount - bothways;
37023         }
37024         backward = laneCount - bothways - forward;
37025     }
37026     return {
37027         forward: forward,
37028         backward: backward,
37029         bothways: bothways
37030     };
37031 }
37032
37033
37034 function parseTurnLanes(tag){
37035     if (!tag) return;
37036
37037     var validValues = [
37038         'left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right',
37039         'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'
37040     ];
37041
37042     return tag.split('|')
37043         .map(function (s) {
37044             if (s === '') s = 'none';
37045             return s.split(';')
37046                 .map(function (d) {
37047                     return validValues.indexOf(d) === -1 ? 'unknown': d;
37048                 });
37049         });
37050 }
37051
37052
37053 function parseMaxspeedLanes(tag, maxspeed) {
37054     if (!tag) return;
37055
37056     return tag.split('|')
37057         .map(function (s) {
37058             if (s === 'none') return s;
37059             var m = parseInt(s, 10);
37060             if (s === '' || m === maxspeed) return null;
37061             return lodash.isNaN(m) ? 'unknown': m;
37062         });
37063 }
37064
37065
37066 function parseMiscLanes(tag) {
37067     if (!tag) return;
37068
37069     var validValues = [
37070         'yes', 'no', 'designated'
37071     ];
37072
37073     return tag.split('|')
37074         .map(function (s) {
37075             if (s === '') s = 'no';
37076             return validValues.indexOf(s) === -1 ? 'unknown': s;
37077         });
37078 }
37079
37080
37081 function parseBicycleWay(tag) {
37082     if (!tag) return;
37083
37084     var validValues = [
37085         'yes', 'no', 'designated', 'lane'
37086     ];
37087
37088     return tag.split('|')
37089         .map(function (s) {
37090             if (s === '') s = 'no';
37091             return validValues.indexOf(s) === -1 ? 'unknown': s;
37092         });
37093 }
37094
37095
37096 function mapToLanesObj(lanesObj, data, key) {
37097     if (data.forward) data.forward.forEach(function(l, i) {
37098         if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
37099         lanesObj.forward[i][key] = l;
37100     });
37101     if (data.backward) data.backward.forEach(function(l, i) {
37102         if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
37103         lanesObj.backward[i][key] = l;
37104     });
37105     if (data.unspecified) data.unspecified.forEach(function(l, i) {
37106         if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
37107         lanesObj.unspecified[i][key] = l;
37108     });
37109 }
37110
37111 var translations = Object.create(null);
37112
37113 var currentLocale = 'en';
37114 var textDirection = 'ltr';
37115
37116 function setLocale(_) {
37117     if (translations[_] !== undefined) {
37118         currentLocale = _;
37119     } else if (translations[_.split('-')[0]]) {
37120         currentLocale = _.split('-')[0];
37121     }
37122 }
37123
37124 function addTranslation(id, value) {
37125     translations[id] = value;
37126 }
37127
37128 /**
37129  * Given a string identifier, try to find that string in the current
37130  * language, and return it.
37131  *
37132  * @param {string} s string identifier
37133  * @returns {string?} locale string
37134  */
37135 function t(s, o, loc) {
37136     loc = loc || currentLocale;
37137
37138     var path = s.split('.').reverse();
37139     var rep = translations[loc];
37140
37141     while (rep !== undefined && path.length) rep = rep[path.pop()];
37142
37143     if (rep !== undefined) {
37144         if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
37145         return rep;
37146     }
37147
37148     if (loc !== 'en') {
37149         return t(s, o, 'en');
37150     }
37151
37152     if (o && 'default' in o) {
37153         return o.default;
37154     }
37155
37156     var missing = 'Missing ' + loc + ' translation: ' + s;
37157     if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
37158
37159     return missing;
37160 }
37161
37162 /**
37163  * Given string 'ltr' or 'rtl', save that setting
37164  *
37165  * @param {string} s ltr or rtl
37166  */
37167
37168 function setTextDirection(dir) {
37169     textDirection = dir;
37170 }
37171
37172 var detected;
37173
37174 function utilDetect(force) {
37175     if (detected && !force) return detected;
37176     detected = {};
37177
37178     var ua = navigator.userAgent,
37179         m = null;
37180
37181     m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i);   // Edge
37182     if (m !== null) {
37183         detected.browser = m[1];
37184         detected.version = m[2];
37185     }
37186     if (!detected.browser) {
37187         m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i);   // IE11
37188         if (m !== null) {
37189             detected.browser = 'msie';
37190             detected.version = m[1];
37191         }
37192     }
37193     if (!detected.browser) {
37194         m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);   // Opera 15+
37195         if (m !== null) {
37196             detected.browser = 'Opera';
37197             detected.version = m[2];
37198         }
37199     }
37200     if (!detected.browser) {
37201         m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
37202         if (m !== null) {
37203             detected.browser = m[1];
37204             detected.version = m[2];
37205             m = ua.match(/version\/([\.\d]+)/i);
37206             if (m !== null) detected.version = m[1];
37207         }
37208     }
37209     if (!detected.browser) {
37210         detected.browser = navigator.appName;
37211         detected.version = navigator.appVersion;
37212     }
37213
37214     // keep major.minor version only..
37215     detected.version = detected.version.split(/\W/).slice(0,2).join('.');
37216
37217     if (detected.browser.toLowerCase() === 'msie') {
37218         detected.ie = true;
37219         detected.browser = 'Internet Explorer';
37220         detected.support = parseFloat(detected.version) >= 11;
37221     } else {
37222         detected.ie = false;
37223         detected.support = true;
37224     }
37225
37226     // Added due to incomplete svg style support. See #715
37227     detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
37228
37229     detected.locale = (navigator.language || navigator.userLanguage || 'en-US');
37230     detected.language = detected.locale.split('-')[0];
37231
37232     // Search `navigator.languages` for a better locale.. Prefer the first language,
37233     // unless the second language is a culture-specific version of the first one, see #3842
37234     if (navigator.languages && navigator.languages.length > 0) {
37235         var code0 = navigator.languages[0],
37236             parts0 = code0.split('-');
37237
37238         detected.locale = code0;
37239         detected.language = parts0[0];
37240
37241         if (navigator.languages.length > 1 && parts0.length === 1) {
37242             var code1 = navigator.languages[1],
37243                 parts1 = code1.split('-');
37244
37245             if (parts1[0] === parts0[0]) {
37246                 detected.locale = code1;
37247             }
37248         }
37249     }
37250
37251     // Loaded locale is stored in currentLocale
37252     // return that instead (except in the situation where 'en' might override 'en-US')
37253     var loadedLocale = currentLocale || 'en';
37254     if (loadedLocale !== 'en') {
37255         detected.locale = loadedLocale;
37256         detected.language = detected.locale.split('-')[0];
37257     }
37258
37259     // detect text direction
37260     var q = utilStringQs(window.location.hash.substring(1));
37261     var lang = dataLocales[detected.locale];
37262     if ((lang && lang.rtl) || q.hasOwnProperty('rtl')) {
37263         detected.textDirection = 'rtl';
37264     } else {
37265         detected.textDirection = 'ltr';
37266     }
37267     setTextDirection(detected.textDirection);
37268
37269     // detect host
37270     var loc = window.top.location;
37271     var origin = loc.origin;
37272     if (!origin) {  // for unpatched IE11
37273         origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port: '');
37274     }
37275
37276     detected.host = origin + loc.pathname;
37277
37278     detected.filedrop = (window.FileReader && 'ondrop' in window);
37279
37280     function nav(x) {
37281         return navigator.userAgent.indexOf(x) !== -1;
37282     }
37283
37284     if (nav('Win')) {
37285         detected.os = 'win';
37286         detected.platform = 'Windows';
37287     }
37288     else if (nav('Mac')) {
37289         detected.os = 'mac';
37290         detected.platform = 'Macintosh';
37291     }
37292     else if (nav('X11') || nav('Linux')) {
37293         detected.os = 'linux';
37294         detected.platform = 'Linux';
37295     }
37296     else {
37297         detected.os = 'win';
37298         detected.platform = 'Unknown';
37299     }
37300
37301     return detected;
37302 }
37303
37304 var remove$1 = removeDiacritics;
37305
37306 var replacementList = [
37307   {
37308     base: ' ',
37309     chars: "\u00A0",
37310   }, {
37311     base: '0',
37312     chars: "\u07C0",
37313   }, {
37314     base: 'A',
37315     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",
37316   }, {
37317     base: 'AA',
37318     chars: "\uA732",
37319   }, {
37320     base: 'AE',
37321     chars: "\u00C6\u01FC\u01E2",
37322   }, {
37323     base: 'AO',
37324     chars: "\uA734",
37325   }, {
37326     base: 'AU',
37327     chars: "\uA736",
37328   }, {
37329     base: 'AV',
37330     chars: "\uA738\uA73A",
37331   }, {
37332     base: 'AY',
37333     chars: "\uA73C",
37334   }, {
37335     base: 'B',
37336     chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181",
37337   }, {
37338     base: 'C',
37339     chars: "\u24b8\uff23\uA73E\u1E08\u0106\u0043\u0108\u010A\u010C\u00C7\u0187\u023B",
37340   }, {
37341     base: 'D',
37342     chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779",
37343   }, {
37344     base: 'Dh',
37345     chars: "\u00D0",
37346   }, {
37347     base: 'DZ',
37348     chars: "\u01F1\u01C4",
37349   }, {
37350     base: 'Dz',
37351     chars: "\u01F2\u01C5",
37352   }, {
37353     base: 'E',
37354     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",
37355   }, {
37356     base: 'F',
37357     chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B",
37358   }, {
37359     base: 'G',
37360     chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262",
37361   }, {
37362     base: 'H',
37363     chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D",
37364   }, {
37365     base: 'I',
37366     chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197",
37367   }, {
37368     base: 'J',
37369     chars: "\u24BF\uFF2A\u0134\u0248\u0237",
37370   }, {
37371     base: 'K',
37372     chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2",
37373   }, {
37374     base: 'L',
37375     chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780",
37376   }, {
37377     base: 'LJ',
37378     chars: "\u01C7",
37379   }, {
37380     base: 'Lj',
37381     chars: "\u01C8",
37382   }, {
37383     base: 'M',
37384     chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB",
37385   }, {
37386     base: 'N',
37387     chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E",
37388   }, {
37389     base: 'NJ',
37390     chars: "\u01CA",
37391   }, {
37392     base: 'Nj',
37393     chars: "\u01CB",
37394   }, {
37395     base: 'O',
37396     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",
37397   }, {
37398     base: 'OE',
37399     chars: "\u0152",
37400   }, {
37401     base: 'OI',
37402     chars: "\u01A2",
37403   }, {
37404     base: 'OO',
37405     chars: "\uA74E",
37406   }, {
37407     base: 'OU',
37408     chars: "\u0222",
37409   }, {
37410     base: 'P',
37411     chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754",
37412   }, {
37413     base: 'Q',
37414     chars: "\u24C6\uFF31\uA756\uA758\u024A",
37415   }, {
37416     base: 'R',
37417     chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782",
37418   }, {
37419     base: 'S',
37420     chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784",
37421   }, {
37422     base: 'T',
37423     chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786",
37424   }, {
37425     base: 'Th',
37426     chars: "\u00DE",
37427   }, {
37428     base: 'TZ',
37429     chars: "\uA728",
37430   }, {
37431     base: 'U',
37432     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",
37433   }, {
37434     base: 'V',
37435     chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245",
37436   }, {
37437     base: 'VY',
37438     chars: "\uA760",
37439   }, {
37440     base: 'W',
37441     chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72",
37442   }, {
37443     base: 'X',
37444     chars: "\u24CD\uFF38\u1E8A\u1E8C",
37445   }, {
37446     base: 'Y',
37447     chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE",
37448   }, {
37449     base: 'Z',
37450     chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762",
37451   }, {
37452     base: 'a',
37453     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",
37454   }, {
37455     base: 'aa',
37456     chars: "\uA733",
37457   }, {
37458     base: 'ae',
37459     chars: "\u00E6\u01FD\u01E3",
37460   }, {
37461     base: 'ao',
37462     chars: "\uA735",
37463   }, {
37464     base: 'au',
37465     chars: "\uA737",
37466   }, {
37467     base: 'av',
37468     chars: "\uA739\uA73B",
37469   }, {
37470     base: 'ay',
37471     chars: "\uA73D",
37472   }, {
37473     base: 'b',
37474     chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182",
37475   }, {
37476     base: 'c',
37477     chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184",
37478   }, {
37479     base: 'd',
37480     chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA",
37481   }, {
37482     base: 'dh',
37483     chars: "\u00F0",
37484   }, {
37485     base: 'dz',
37486     chars: "\u01F3\u01C6",
37487   }, {
37488     base: 'e',
37489     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",
37490   }, {
37491     base: 'f',
37492     chars: "\u24D5\uFF46\u1E1F\u0192",
37493   }, {
37494     base: 'ff',
37495     chars: "\uFB00",
37496   }, {
37497     base: 'fi',
37498     chars: "\uFB01",
37499   }, {
37500     base: 'fl',
37501     chars: "\uFB02",
37502   }, {
37503     base: 'ffi',
37504     chars: "\uFB03",
37505   }, {
37506     base: 'ffl',
37507     chars: "\uFB04",
37508   }, {
37509     base: 'g',
37510     chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79",
37511   }, {
37512     base: 'h',
37513     chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265",
37514   }, {
37515     base: 'hv',
37516     chars: "\u0195",
37517   }, {
37518     base: 'i',
37519     chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131",
37520   }, {
37521     base: 'j',
37522     chars: "\u24D9\uFF4A\u0135\u01F0\u0249",
37523   }, {
37524     base: 'k',
37525     chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3",
37526   }, {
37527     base: 'l',
37528     chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D",
37529   }, {
37530     base: 'lj',
37531     chars: "\u01C9",
37532   }, {
37533     base: 'm',
37534     chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F",
37535   }, {
37536     base: 'n',
37537     chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509",
37538   }, {
37539     base: 'nj',
37540     chars: "\u01CC",
37541   }, {
37542     base: 'o',
37543     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",
37544   }, {
37545     base: 'oe',
37546     chars: "\u0153",
37547   }, {
37548     base: 'oi',
37549     chars: "\u01A3",
37550   }, {
37551     base: 'oo',
37552     chars: "\uA74F",
37553   }, {
37554     base: 'ou',
37555     chars: "\u0223",
37556   }, {
37557     base: 'p',
37558     chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1",
37559   }, {
37560     base: 'q',
37561     chars: "\u24E0\uFF51\u024B\uA757\uA759",
37562   }, {
37563     base: 'r',
37564     chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783",
37565   }, {
37566     base: 's',
37567     chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282",
37568   }, {
37569     base: 'ss',
37570     chars: "\xDF",
37571   }, {
37572     base: 't',
37573     chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787",
37574   }, {
37575     base: 'th',
37576     chars: "\u00FE",
37577   }, {
37578     base: 'tz',
37579     chars: "\uA729",
37580   }, {
37581     base: 'u',
37582     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",
37583   }, {
37584     base: 'v',
37585     chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C",
37586   }, {
37587     base: 'vy',
37588     chars: "\uA761",
37589   }, {
37590     base: 'w',
37591     chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73",
37592   }, {
37593     base: 'x',
37594     chars: "\u24E7\uFF58\u1E8B\u1E8D",
37595   }, {
37596     base: 'y',
37597     chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF",
37598   }, {
37599     base: 'z',
37600     chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763",
37601   }
37602 ];
37603
37604 var diacriticsMap = {};
37605 for (var i = 0; i < replacementList.length; i += 1) {
37606   var chars = replacementList[i].chars;
37607   for (var j = 0; j < chars.length; j += 1) {
37608     diacriticsMap[chars[j]] = replacementList[i].base;
37609   }
37610 }
37611
37612 function removeDiacritics(str) {
37613   return str.replace(/[^\u0000-\u007e]/g, function(c) {
37614     return diacriticsMap[c] || c;
37615   });
37616 }
37617
37618 // see https://github.com/openstreetmap/iD/pull/3707
37619 // https://gist.github.com/mapmeld/556b09ddec07a2044c76e1ef45f01c60
37620
37621 var chars$1 = {
37622     // madda above alef
37623     1570: { initial: 'آ‎', isolated: 'ﺁ', medial: 'ﺁ', final: 'ﺂ' },
37624
37625     // hamza above and below alef
37626     1571: { initial: 'أ', isolated: 'ﺃ', medial: '', final: 'ﺄ' },
37627     // 1572 is ؤ
37628     1573: { initial: 'إ', isolated: 'ﺇ', medial: '', final: 'ﺈ' },
37629     // 1574 is ئ
37630     1575: { initial: 'ا', isolated: 'ا', medial: '', final: 'ﺎ' },
37631     1576: { initial: 'ﺑ', isolated: 'ﺏ', medial: 'ﺒ', final: 'ﺐ' },
37632
37633     // 1577 ة
37634     1577: { initial: '', isolated: 'ة', medial: '', final: 'ﺔ' },
37635
37636     1578: { initial: 'ﺗ', isolated: 'ﺕ', medial: 'ﺘ', final: 'ﺖ' },
37637     1579: { initial: 'ﺛ', isolated: 'ﺙ', medial: 'ﺜ', final: 'ﺚ' },
37638     1580: { initial: 'ﺟ', isolated: 'ﺝ', medial: 'ﺠ', final: 'ﺞ' },
37639     1581: { initial: 'ﺣ', isolated: 'ﺡ', medial: 'ﺤ', final: 'ﺢ' },
37640     1582: { initial: 'ﺧ', isolated: 'ﺥ', medial: 'ﺨ', final: 'ﺦ' },
37641     1583: { initial: 'ﺩ', isolated: 'ﺩ', medial: '', final: 'ﺪ' },
37642     1584: { initial: 'ﺫ', isolated: 'ﺫ', medial: '', final: 'ﺬ' },
37643     1585: { initial: 'ﺭ', isolated: 'ﺭ', medial: '', final: 'ﺮ' },
37644     1586: { initial: 'ﺯ', isolated: 'ﺯ', medial: '', final: 'ﺰ' },
37645     1688: { initial: 'ﮊ', isolated: 'ﮊ', medial: '', final: 'ﮋ' },
37646     1587: { initial: 'ﺳ', isolated: 'ﺱ', medial: 'ﺴ', final: 'ﺲ' },
37647     1588: { initial: 'ﺷ', isolated: 'ﺵ', medial: 'ﺸ', final: 'ﺶ' },
37648     1589: { initial: 'ﺻ', isolated: 'ﺹ', medial: 'ﺼ', final: 'ﺺ' },
37649     1590: { initial: 'ﺿ', isolated: 'ﺽ', medial: 'ﻀ', final: 'ﺾ' },
37650     1591: { initial: 'ﻃ', isolated: 'ﻁ', medial: 'ﻄ', final: 'ﻂ' },
37651     1592: { initial: 'ﻇ', isolated: 'ﻅ', medial: 'ﻈ', final: 'ﻆ' },
37652     1593: { initial: 'ﻋ', isolated: 'ﻉ', medial: 'ﻌ', final: 'ﻊ' },
37653     1594: { initial: 'ﻏ', isolated: 'ﻍ', medial: 'ﻐ', final: 'ﻎ' },
37654
37655     // 1595 ػ - may be very rare
37656
37657     1601: { initial: 'ﻓ', isolated: 'ﻑ', medial: 'ﻔ', final: 'ﻒ' },
37658     1602: { initial: 'ﻗ', isolated: 'ﻕ', medial: 'ﻘ', final: 'ﻖ' },
37659     1604: { initial: 'ﻟ', isolated: 'ﻝ', medial: 'ﻠ', final: 'ﻞ' },
37660     1605: { initial: 'ﻣ', isolated: 'ﻡ', medial: 'ﻤ', final: 'ﻢ' },
37661     1606: { initial: 'ﻧ', isolated: 'ﻥ', medial: 'ﻨ', final: 'ﻦ' },
37662     1607: { initial: 'ﻫ', isolated: 'ﻩ', medial: 'ﻬ', final: 'ﻪ' },
37663     1608: { initial: 'ﻭ', isolated: 'ﻭ', medial: '', final: 'ﻮ' },
37664
37665     // 1609 ى
37666     1609: { initial: 'ﯨ', isolated: 'ﻯ', medial: 'ﯩ', final: 'ﻰ' },
37667     // 1610 ي
37668     1610: { initial: 'ﻳ', isolated: 'ﻱ', medial: 'ﻴ', final: 'ﻲ' },
37669
37670     // short vowel sounds / tashkil markings
37671
37672     1662: { initial: 'ﭘ', isolated: 'ﭖ', medial: 'ﭙ', final: 'ﭗ' },
37673
37674     1670: { initial: 'ﭼ', isolated: 'ﭺ', medial: 'ﭽ', final: 'ﭻ' },
37675     1603: { initial: 'ﻛ', isolated: 'ﻙ', medial: 'ﻜ', final: 'ﻚ' },
37676     1705: { initial: 'ﻛ', isolated: 'ﮎ', medial: 'ﻜ', final: 'ﮏ' },
37677     1711: { initial: 'ﮔ', isolated: 'ﮒ', medial: 'ﮕ', final: 'ﮓ' },
37678     1740: { initial: 'ﻳ', isolated: 'ﻯ', medial: 'ﻴ', final: 'ﻰ' },
37679     5000: { initial: 'ﻻ', isolated: 'ﻻ', medial: '', final: 'ﻼ' }
37680 };
37681
37682 var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0780-\u07BF]/;
37683
37684 function fixRTLTextForSvg(inputText) {
37685     var context = true;
37686     var ret = '';
37687     var rtlBuffer = [];
37688     var arabicRegex = /[\u0600-\u06FF]/g;
37689     var arabicTashkil = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED]/;
37690     var thaanaVowel = /[\u07A6-\u07B0]/;
37691     var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/;
37692
37693     if (!arabicRegex.test(inputText)) {
37694         // Hebrew or Thaana RTL script
37695         for (var n = 0; n < inputText.length; n++) {
37696             var c = inputText[n];
37697             if ((thaanaVowel.test(c) || hebrewSign.test(c)) && rtlBuffer.length) {
37698                 rtlBuffer[rtlBuffer.length - 1] += c;
37699             } else if (rtlRegex.test(c)) {
37700                 rtlBuffer.push(c);
37701             } else if (c === ' ' && rtlBuffer.length) {
37702                 // whitespace within RTL text
37703                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37704             } else {
37705                 // non-RTL character
37706                 ret += rtlBuffer.reverse().join('') + c;
37707                 rtlBuffer = [];
37708             }
37709         }
37710     } else {
37711         for (var i = 0, l = inputText.length; i < l; i++) {
37712             var code = inputText[i].charCodeAt(0);
37713             var nextCode = inputText[i + 1] ? inputText[i + 1].charCodeAt(0) : 0;
37714
37715             if (!chars$1[code]) {
37716                 if (code === 32 && rtlBuffer.length) {
37717                     // whitespace
37718                     rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37719                 } else if (arabicTashkil.test(inputText[i]) && rtlBuffer.length) {
37720                     // tashkil mark
37721                     rtlBuffer[rtlBuffer.length - 1] += inputText[i];
37722                 } else {
37723                     // non-RTL character
37724                     ret += rtlBuffer.reverse().join('') + inputText[i];
37725                     rtlBuffer = [];
37726                 }
37727                 continue;
37728             }
37729             if (context) {
37730                 if (i === l - 1 || nextCode === 32) {
37731                     rtlBuffer.push(chars$1[code].isolated);
37732                 } else {
37733                     // special case for لا
37734                     if (code === 1604 && nextCode === 1575) {
37735                         rtlBuffer.push(chars$1[5000].initial);
37736                         i++;
37737                         context = true;
37738                         continue;
37739                     }
37740                     rtlBuffer.push(chars$1[code].initial);
37741                 }
37742             } else {
37743                 if (i === l - 1 || nextCode === 32){
37744                     rtlBuffer.push(chars$1[code].final);
37745                 } else {
37746                     // special case for ﻼ
37747                     if (code === 1604 && nextCode === 1575){
37748                         rtlBuffer.push(chars$1[5000].final);
37749                         i++;
37750                         context = true;
37751                         continue;
37752                     }
37753                     if (chars$1[code].medial === ''){
37754                         rtlBuffer.push(chars$1[code].final);
37755                     } else {
37756                         rtlBuffer.push(chars$1[code].medial);
37757                     }
37758                 }
37759             }
37760             context = (chars$1[code].medial === '') || nextCode === 32;
37761         }
37762     }
37763     ret += rtlBuffer.reverse().join('');
37764     return ret;
37765 }
37766
37767 function utilTagText(entity) {
37768     return entries(entity.tags).map(function(e) {
37769         return e.key + '=' + e.value;
37770     }).join(', ');
37771 }
37772
37773
37774 function utilEntitySelector(ids) {
37775     return ids.length ? '.' + ids.join(',.') : 'nothing';
37776 }
37777
37778
37779 function utilEntityOrMemberSelector(ids, graph) {
37780     var s = utilEntitySelector(ids);
37781
37782     ids.forEach(function(id) {
37783         var entity = graph.hasEntity(id);
37784         if (entity && entity.type === 'relation') {
37785             entity.members.forEach(function(member) {
37786                 s += ',.' + member.id;
37787             });
37788         }
37789     });
37790
37791     return s;
37792 }
37793
37794
37795 function utilGetAllNodes(ids, graph) {
37796     var seen = {};
37797     var nodes = [];
37798     ids.forEach(getNodes);
37799     return nodes;
37800
37801     function getNodes(id) {
37802         if (seen[id]) return;
37803         seen[id] = true;
37804
37805         var entity = graph.hasEntity(id);
37806         if (!entity) return;
37807
37808         if (entity.type === 'node') {
37809             nodes.push(entity);
37810         } else if (entity.type === 'way') {
37811             entity.nodes.forEach(getNodes);
37812         } else {
37813             entity.members.map(function(member) { return member.id; }).forEach(getNodes);
37814         }
37815     }
37816 }
37817
37818
37819 function utilDisplayName(entity) {
37820     var localizedNameKey = 'name:' + utilDetect().locale.toLowerCase().split('-')[0],
37821         name = entity.tags[localizedNameKey] || entity.tags.name || '',
37822         network = entity.tags.cycle_network || entity.tags.network;
37823
37824     if (!name && entity.tags.ref) {
37825         name = entity.tags.ref;
37826         if (network) {
37827             name = network + ' ' + name;
37828         }
37829     }
37830
37831     return name;
37832 }
37833
37834
37835 function utilDisplayNameForPath(entity) {
37836     var name = utilDisplayName(entity);
37837     var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
37838
37839     if (!isFirefox && name && rtlRegex.test(name)) {
37840         name = fixRTLTextForSvg(name);
37841     }
37842
37843     return name;
37844 }
37845
37846
37847 function utilDisplayType(id) {
37848     return {
37849         n: t('inspector.node'),
37850         w: t('inspector.way'),
37851         r: t('inspector.relation')
37852     }[id.charAt(0)];
37853 }
37854
37855
37856 function utilStringQs(str) {
37857     return str.split('&').reduce(function(obj, pair){
37858         var parts = pair.split('=');
37859         if (parts.length === 2) {
37860             obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
37861         }
37862         return obj;
37863     }, {});
37864 }
37865
37866
37867 function utilQsString(obj, noencode) {
37868     function softEncode(s) {
37869       // encode everything except special characters used in certain hash parameters:
37870       // "/" in map states, ":", ",", {" and "}" in background
37871       return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
37872     }
37873     return Object.keys(obj).sort().map(function(key) {
37874         return encodeURIComponent(key) + '=' + (
37875             noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
37876     }).join('&');
37877 }
37878
37879
37880 function utilPrefixDOMProperty(property) {
37881     var prefixes = ['webkit', 'ms', 'moz', 'o'],
37882         i = -1,
37883         n = prefixes.length,
37884         s = document.body;
37885
37886     if (property in s)
37887         return property;
37888
37889     property = property.substr(0, 1).toUpperCase() + property.substr(1);
37890
37891     while (++i < n)
37892         if (prefixes[i] + property in s)
37893             return prefixes[i] + property;
37894
37895     return false;
37896 }
37897
37898
37899 function utilPrefixCSSProperty(property) {
37900     var prefixes = ['webkit', 'ms', 'Moz', 'O'],
37901         i = -1,
37902         n = prefixes.length,
37903         s = document.body.style;
37904
37905     if (property.toLowerCase() in s)
37906         return property.toLowerCase();
37907
37908     while (++i < n)
37909         if (prefixes[i] + property in s)
37910             return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
37911
37912     return false;
37913 }
37914
37915
37916 var transformProperty;
37917 function utilSetTransform(el, x, y, scale) {
37918     var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform'),
37919         translate = utilDetect().opera ?
37920             'translate('   + x + 'px,' + y + 'px)' :
37921             'translate3d(' + x + 'px,' + y + 'px,0)';
37922     return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
37923 }
37924
37925
37926 // Calculates Levenshtein distance between two strings
37927 // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
37928 // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
37929 function utilEditDistance(a, b) {
37930     a = remove$1(a.toLowerCase());
37931     b = remove$1(b.toLowerCase());
37932     if (a.length === 0) return b.length;
37933     if (b.length === 0) return a.length;
37934     var matrix = [];
37935     for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
37936     for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
37937     for (i = 1; i <= b.length; i++) {
37938         for (j = 1; j <= a.length; j++) {
37939             if (b.charAt(i-1) === a.charAt(j-1)) {
37940                 matrix[i][j] = matrix[i-1][j-1];
37941             } else {
37942                 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
37943                     Math.min(matrix[i][j-1] + 1, // insertion
37944                     matrix[i-1][j] + 1)); // deletion
37945             }
37946         }
37947     }
37948     return matrix[b.length][a.length];
37949 }
37950
37951
37952 // a d3.mouse-alike which
37953 // 1. Only works on HTML elements, not SVG
37954 // 2. Does not cause style recalculation
37955 function utilFastMouse(container) {
37956     var rect = container.getBoundingClientRect(),
37957         rectLeft = rect.left,
37958         rectTop = rect.top,
37959         clientLeft = +container.clientLeft,
37960         clientTop = +container.clientTop;
37961     if (textDirection === 'rtl') {
37962         rectLeft = 0;
37963     }
37964     return function(e) {
37965         return [
37966             e.clientX - rectLeft - clientLeft,
37967             e.clientY - rectTop - clientTop];
37968     };
37969 }
37970
37971
37972 /* eslint-disable no-proto */
37973 var utilGetPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
37974 /* eslint-enable no-proto */
37975
37976
37977 function utilAsyncMap(inputs, func, callback) {
37978     var remaining = inputs.length,
37979         results = [],
37980         errors = [];
37981
37982     inputs.forEach(function(d, i) {
37983         func(d, function done(err, data) {
37984             errors[i] = err;
37985             results[i] = data;
37986             remaining--;
37987             if (!remaining) callback(errors, results);
37988         });
37989     });
37990 }
37991
37992
37993 // wraps an index to an interval [0..length-1]
37994 function utilWrap(index, length) {
37995     if (index < 0)
37996         index += Math.ceil(-index/length)*length;
37997     return index % length;
37998 }
37999
38000
38001 /**
38002  * a replacement for functor
38003  *
38004  * @param {*} value any value
38005  * @returns {Function} a function that returns that value or the value if it's a function
38006  */
38007 function utilFunctor(value) {
38008     if (typeof value === 'function') return value;
38009     return function() {
38010         return value;
38011     };
38012 }
38013
38014
38015 function utilNoAuto(selection$$1) {
38016     return selection$$1
38017         .attr('autocomplete', 'off')
38018         .attr('autocorrect', 'off')
38019         .attr('autocapitalize', 'off')
38020         .attr('spellcheck', 'false');
38021 }
38022
38023 // Like selection.property('value', ...), but avoids no-op value sets,
38024 // which can result in layout/repaint thrashing in some situations.
38025 function utilGetSetValue(selection, value) {
38026     function d3_selection_value(value) {
38027         function valueNull() {
38028             delete this.value;
38029         }
38030
38031         function valueConstant() {
38032             if (this.value !== value) {
38033                 this.value = value;
38034             }
38035         }
38036
38037         function valueFunction() {
38038             var x = value.apply(this, arguments);
38039             if (x == null) {
38040                 delete this.value;
38041             } else if (this.value !== x) {
38042                 this.value = x;
38043             }
38044         }
38045
38046         return value == null
38047             ? valueNull : (typeof value === 'function'
38048             ? valueFunction : valueConstant);
38049     }
38050
38051     if (arguments.length === 1) {
38052         return selection.property('value');
38053     }
38054
38055     return selection.each(d3_selection_value(value));
38056 }
38057
38058 // Copies a variable number of methods from source to target.
38059 function utilRebind(target, source) {
38060     var i = 1, n = arguments.length, method;
38061     while (++i < n) {
38062         target[method = arguments[i]] = d3_rebind(target, source, source[method]);
38063     }
38064     return target;
38065 }
38066
38067 // Method is assumed to be a standard D3 getter-setter:
38068 // If passed with no arguments, gets the value.
38069 // If passed with arguments, sets the value and returns the target.
38070 function d3_rebind(target, source, method) {
38071     return function() {
38072         var value = method.apply(source, arguments);
38073         return value === source ? target : value;
38074     };
38075 }
38076
38077 // A per-domain session mutex backed by a cookie and dead man's
38078 // switch. If the session crashes, the mutex will auto-release
38079 // after 5 seconds.
38080
38081 function utilSessionMutex(name) {
38082     var mutex = {},
38083         intervalID;
38084
38085     function renew() {
38086         var expires = new Date();
38087         expires.setSeconds(expires.getSeconds() + 5);
38088         document.cookie = name + '=1; expires=' + expires.toUTCString();
38089     }
38090
38091     mutex.lock = function() {
38092         if (intervalID) return true;
38093         var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
38094         if (cookie) return false;
38095         renew();
38096         intervalID = window.setInterval(renew, 4000);
38097         return true;
38098     };
38099
38100     mutex.unlock = function() {
38101         if (!intervalID) return;
38102         document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
38103         clearInterval(intervalID);
38104         intervalID = null;
38105     };
38106
38107     mutex.locked = function() {
38108         return !!intervalID;
38109     };
38110
38111     return mutex;
38112 }
38113
38114 function utilSuggestNames(preset, suggestions) {
38115     preset = preset.id.split('/', 2);
38116     var k = preset[0],
38117         v = preset[1];
38118
38119     return function(value, callback) {
38120         var result = [];
38121         if (value && value.length > 2) {
38122             if (suggestions[k] && suggestions[k][v]) {
38123                 for (var sugg in suggestions[k][v]) {
38124                     var dist = utilEditDistance(value, sugg.substring(0, value.length));
38125                     if (dist < 3) {
38126                         result.push({
38127                             title: sugg,
38128                             value: sugg,
38129                             dist: dist
38130                         });
38131                     }
38132                 }
38133             }
38134             result.sort(function(a, b) {
38135                 return a.dist - b.dist;
38136             });
38137         }
38138         result = result.slice(0,3);
38139         callback(result);
38140     };
38141 }
38142
38143 function utilTriggerEvent(target, type) {
38144     target.each(function() {
38145         var evt = document.createEvent('HTMLEvents');
38146         evt.initEvent(type, true, true);
38147         this.dispatchEvent(evt);
38148     });
38149 }
38150
38151 function validationDeprecatedTag() {
38152
38153     var validation = function(changes) {
38154         var warnings = [];
38155         for (var i = 0; i < changes.created.length; i++) {
38156             var change = changes.created[i],
38157                 deprecatedTags = change.deprecatedTags();
38158
38159             if (!lodash.isEmpty(deprecatedTags)) {
38160                 var tags = utilTagText({ tags: deprecatedTags });
38161                 warnings.push({
38162                     id: 'deprecated_tags',
38163                     message: t('validations.deprecated_tags', { tags: tags }),
38164                     entity: change
38165                 });
38166             }
38167         }
38168
38169         return warnings;
38170     };
38171
38172
38173     return validation;
38174 }
38175
38176 function validationDisconnectedHighway() {
38177
38178
38179     function isDisconnectedHighway(entity, graph) {
38180         if (!entity.tags.highway) return false;
38181         if (entity.geometry(graph) !== 'line') return false;
38182
38183         return graph.childNodes(entity)
38184             .every(function(vertex) {
38185                 var parents = graph.parentWays(vertex);
38186                 if (parents.length === 1) {  // standalone vertex
38187                     return true;
38188                 } else {                     // shared vertex
38189                     return !vertex.tags.entrance &&
38190                         parents.filter(function(parent) {
38191                             return parent.tags.highway && parent !== entity;
38192                         }).length === 0;
38193                 }
38194             });
38195     }
38196
38197
38198     var validation = function(changes, graph) {
38199         var warnings = [];
38200         for (var i = 0; i < changes.created.length; i++) {
38201             var entity = changes.created[i];
38202
38203             if (isDisconnectedHighway(entity, graph)) {
38204                 warnings.push({
38205                     id: 'disconnected_highway',
38206                     message: t('validations.disconnected_highway'),
38207                     tooltip: t('validations.disconnected_highway_tooltip'),
38208                     entity: entity
38209                 });
38210             }
38211         }
38212
38213         return warnings;
38214     };
38215
38216
38217     return validation;
38218 }
38219
38220 function validationManyDeletions() {
38221     var threshold = 100;
38222
38223     var validation = function(changes) {
38224         var warnings = [];
38225         if (changes.deleted.length > threshold) {
38226             warnings.push({
38227                 id: 'many_deletions',
38228                 message: t('validations.many_deletions', { n: changes.deleted.length })
38229             });
38230         }
38231
38232         return warnings;
38233     };
38234
38235
38236     return validation;
38237 }
38238
38239 function validationMissingTag() {
38240
38241     // Slightly stricter check than Entity#isUsed (#3091)
38242     function hasTags(entity, graph) {
38243         return lodash.without(Object.keys(entity.tags), 'area', 'name').length > 0 ||
38244             graph.parentRelations(entity).length > 0;
38245     }
38246
38247     var validation = function(changes, graph) {
38248         var types = ['point', 'line', 'area', 'relation'],
38249             warnings = [];
38250
38251         for (var i = 0; i < changes.created.length; i++) {
38252             var change = changes.created[i],
38253                 geometry = change.geometry(graph);
38254
38255             if (types.indexOf(geometry) !== -1 && !hasTags(change, graph)) {
38256                 warnings.push({
38257                     id: 'missing_tag',
38258                     message: t('validations.untagged_' + geometry),
38259                     tooltip: t('validations.untagged_' + geometry + '_tooltip'),
38260                     entity: change
38261                 });
38262             }
38263         }
38264
38265         return warnings;
38266     };
38267
38268
38269     return validation;
38270 }
38271
38272 function validationOldMultipolygon() {
38273
38274
38275     return function validation(changes, graph) {
38276         var warnings = [];
38277         for (var i = 0; i < changes.created.length; i++) {
38278             var entity = changes.created[i];
38279             var parent = osmIsSimpleMultipolygonOuterMember(entity, graph);
38280             if (parent) {
38281                 warnings.push({
38282                     id: 'old_multipolygon',
38283                     message: t('validations.old_multipolygon'),
38284                     tooltip: t('validations.old_multipolygon_tooltip'),
38285                     entity: parent
38286                 });
38287             }
38288         }
38289         return warnings;
38290     };
38291 }
38292
38293 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
38294 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
38295 function validationTagSuggestsArea() {
38296
38297     function tagSuggestsArea(tags) {
38298         if (lodash.isEmpty(tags)) return false;
38299
38300         var presence = ['landuse', 'amenities', 'tourism', 'shop'];
38301         for (var i = 0; i < presence.length; i++) {
38302             if (tags[presence[i]] !== undefined) {
38303                 return presence[i] + '=' + tags[presence[i]];
38304             }
38305         }
38306
38307         if (tags.building && tags.building === 'yes') return 'building=yes';
38308     }
38309
38310
38311     var validation = function(changes, graph) {
38312         var warnings = [];
38313         for (var i = 0; i < changes.created.length; i++) {
38314             var change = changes.created[i],
38315                 geometry = change.geometry(graph),
38316                 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
38317
38318             if (suggestion) {
38319                 warnings.push({
38320                     id: 'tag_suggests_area',
38321                     message: t('validations.tag_suggests_area', { tag: suggestion }),
38322                     entity: change
38323                 });
38324             }
38325         }
38326
38327         return warnings;
38328     };
38329
38330
38331     return validation;
38332 }
38333
38334
38335
38336 var Validations = Object.freeze({
38337         validationDeprecatedTag: validationDeprecatedTag,
38338         validationDisconnectedHighway: validationDisconnectedHighway,
38339         validationManyDeletions: validationManyDeletions,
38340         validationMissingTag: validationMissingTag,
38341         validationOldMultipolygon: validationOldMultipolygon,
38342         validationTagSuggestsArea: validationTagSuggestsArea
38343 });
38344
38345 /*
38346     iD.Difference represents the difference between two graphs.
38347     It knows how to calculate the set of entities that were
38348     created, modified, or deleted, and also contains the logic
38349     for recursively extending a difference to the complete set
38350     of entities that will require a redraw, taking into account
38351     child and parent relationships.
38352  */
38353 function coreDifference(base, head) {
38354     var changes = {},
38355         difference = {},
38356         length = 0;
38357
38358
38359     function changed(h, b) {
38360         return h !== b && !lodash.isEqual(lodash.omit(h, 'v'), lodash.omit(b, 'v'));
38361     }
38362
38363
38364     lodash.each(head.entities, function(h, id) {
38365         var b = base.entities[id];
38366         if (changed(h, b)) {
38367             changes[id] = {base: b, head: h};
38368             length++;
38369         }
38370     });
38371
38372
38373     lodash.each(base.entities, function(b, id) {
38374         var h = head.entities[id];
38375         if (!changes[id] && changed(h, b)) {
38376             changes[id] = {base: b, head: h};
38377             length++;
38378         }
38379     });
38380
38381
38382     function addParents(parents, result) {
38383         for (var i = 0; i < parents.length; i++) {
38384             var parent = parents[i];
38385
38386             if (parent.id in result)
38387                 continue;
38388
38389             result[parent.id] = parent;
38390             addParents(head.parentRelations(parent), result);
38391         }
38392     }
38393
38394
38395     difference.length = function() {
38396         return length;
38397     };
38398
38399
38400     difference.changes = function() {
38401         return changes;
38402     };
38403
38404
38405     difference.extantIDs = function() {
38406         var result = [];
38407         lodash.each(changes, function(change, id) {
38408             if (change.head) result.push(id);
38409         });
38410         return result;
38411     };
38412
38413
38414     difference.modified = function() {
38415         var result = [];
38416         lodash.each(changes, function(change) {
38417             if (change.base && change.head) result.push(change.head);
38418         });
38419         return result;
38420     };
38421
38422
38423     difference.created = function() {
38424         var result = [];
38425         lodash.each(changes, function(change) {
38426             if (!change.base && change.head) result.push(change.head);
38427         });
38428         return result;
38429     };
38430
38431
38432     difference.deleted = function() {
38433         var result = [];
38434         lodash.each(changes, function(change) {
38435             if (change.base && !change.head) result.push(change.base);
38436         });
38437         return result;
38438     };
38439
38440
38441     difference.summary = function() {
38442         var relevant = {};
38443
38444         function addEntity(entity, graph, changeType) {
38445             relevant[entity.id] = {
38446                 entity: entity,
38447                 graph: graph,
38448                 changeType: changeType
38449             };
38450         }
38451
38452         function addParents(entity) {
38453             var parents = head.parentWays(entity);
38454             for (var j = parents.length - 1; j >= 0; j--) {
38455                 var parent = parents[j];
38456                 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
38457             }
38458         }
38459
38460         lodash.each(changes, function(change) {
38461             if (change.head && change.head.geometry(head) !== 'vertex') {
38462                 addEntity(change.head, head, change.base ? 'modified' : 'created');
38463
38464             } else if (change.base && change.base.geometry(base) !== 'vertex') {
38465                 addEntity(change.base, base, 'deleted');
38466
38467             } else if (change.base && change.head) { // modified vertex
38468                 var moved    = !lodash.isEqual(change.base.loc,  change.head.loc),
38469                     retagged = !lodash.isEqual(change.base.tags, change.head.tags);
38470
38471                 if (moved) {
38472                     addParents(change.head);
38473                 }
38474
38475                 if (retagged || (moved && change.head.hasInterestingTags())) {
38476                     addEntity(change.head, head, 'modified');
38477                 }
38478
38479             } else if (change.head && change.head.hasInterestingTags()) { // created vertex
38480                 addEntity(change.head, head, 'created');
38481
38482             } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
38483                 addEntity(change.base, base, 'deleted');
38484             }
38485         });
38486
38487         return values(relevant);
38488     };
38489
38490
38491     difference.complete = function(extent$$1) {
38492         var result = {}, id, change;
38493
38494         for (id in changes) {
38495             change = changes[id];
38496
38497             var h = change.head,
38498                 b = change.base,
38499                 entity = h || b;
38500
38501             if (extent$$1 &&
38502                 (!h || !h.intersects(extent$$1, head)) &&
38503                 (!b || !b.intersects(extent$$1, base)))
38504                 continue;
38505
38506             result[id] = h;
38507
38508             if (entity.type === 'way') {
38509                 var nh = h ? h.nodes : [],
38510                     nb = b ? b.nodes : [],
38511                     diff, i;
38512
38513                 diff = lodash.difference(nh, nb);
38514                 for (i = 0; i < diff.length; i++) {
38515                     result[diff[i]] = head.hasEntity(diff[i]);
38516                 }
38517
38518                 diff = lodash.difference(nb, nh);
38519                 for (i = 0; i < diff.length; i++) {
38520                     result[diff[i]] = head.hasEntity(diff[i]);
38521                 }
38522             }
38523
38524             addParents(head.parentWays(entity), result);
38525             addParents(head.parentRelations(entity), result);
38526         }
38527
38528         return result;
38529     };
38530
38531
38532     return difference;
38533 }
38534
38535 function coreGraph$$1(other, mutable) {
38536     if (!(this instanceof coreGraph$$1)) return new coreGraph$$1(other, mutable);
38537
38538     if (other instanceof coreGraph$$1) {
38539         var base = other.base();
38540         this.entities = lodash.assign(Object.create(base.entities), other.entities);
38541         this._parentWays = lodash.assign(Object.create(base.parentWays), other._parentWays);
38542         this._parentRels = lodash.assign(Object.create(base.parentRels), other._parentRels);
38543
38544     } else {
38545         this.entities = Object.create({});
38546         this._parentWays = Object.create({});
38547         this._parentRels = Object.create({});
38548         this.rebase(other || [], [this]);
38549     }
38550
38551     this.transients = {};
38552     this._childNodes = {};
38553     this.frozen = !mutable;
38554 }
38555
38556
38557 coreGraph$$1.prototype = {
38558
38559     hasEntity: function(id) {
38560         return this.entities[id];
38561     },
38562
38563
38564     entity: function(id) {
38565         var entity = this.entities[id];
38566         if (!entity) {
38567             throw new Error('entity ' + id + ' not found');
38568         }
38569         return entity;
38570     },
38571
38572
38573     transient: function(entity, key, fn) {
38574         var id = entity.id,
38575             transients = this.transients[id] ||
38576             (this.transients[id] = {});
38577
38578         if (transients[key] !== undefined) {
38579             return transients[key];
38580         }
38581
38582         transients[key] = fn.call(entity);
38583
38584         return transients[key];
38585     },
38586
38587
38588     parentWays: function(entity) {
38589         var parents = this._parentWays[entity.id],
38590             result = [];
38591
38592         if (parents) {
38593             for (var i = 0; i < parents.length; i++) {
38594                 result.push(this.entity(parents[i]));
38595             }
38596         }
38597         return result;
38598     },
38599
38600
38601     isPoi: function(entity) {
38602         var parentWays = this._parentWays[entity.id];
38603         return !parentWays || parentWays.length === 0;
38604     },
38605
38606
38607     isShared: function(entity) {
38608         var parentWays = this._parentWays[entity.id];
38609         return parentWays && parentWays.length > 1;
38610     },
38611
38612
38613     parentRelations: function(entity) {
38614         var parents = this._parentRels[entity.id],
38615             result = [];
38616
38617         if (parents) {
38618             for (var i = 0; i < parents.length; i++) {
38619                 result.push(this.entity(parents[i]));
38620             }
38621         }
38622         return result;
38623     },
38624
38625
38626     childNodes: function(entity) {
38627         if (this._childNodes[entity.id]) return this._childNodes[entity.id];
38628         if (!entity.nodes) return [];
38629
38630         var nodes = [];
38631         for (var i = 0; i < entity.nodes.length; i++) {
38632             nodes[i] = this.entity(entity.nodes[i]);
38633         }
38634
38635         if (debug) Object.freeze(nodes);
38636
38637         this._childNodes[entity.id] = nodes;
38638         return this._childNodes[entity.id];
38639     },
38640
38641
38642     base: function() {
38643         return {
38644             'entities': utilGetPrototypeOf(this.entities),
38645             'parentWays': utilGetPrototypeOf(this._parentWays),
38646             'parentRels': utilGetPrototypeOf(this._parentRels)
38647         };
38648     },
38649
38650
38651     // Unlike other graph methods, rebase mutates in place. This is because it
38652     // is used only during the history operation that merges newly downloaded
38653     // data into each state. To external consumers, it should appear as if the
38654     // graph always contained the newly downloaded data.
38655     rebase: function(entities, stack, force) {
38656         var base = this.base(),
38657             i, j, k, id;
38658
38659         for (i = 0; i < entities.length; i++) {
38660             var entity = entities[i];
38661
38662             if (!entity.visible || (!force && base.entities[entity.id]))
38663                 continue;
38664
38665             // Merging data into the base graph
38666             base.entities[entity.id] = entity;
38667             this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
38668
38669             // Restore provisionally-deleted nodes that are discovered to have an extant parent
38670             if (entity.type === 'way') {
38671                 for (j = 0; j < entity.nodes.length; j++) {
38672                     id = entity.nodes[j];
38673                     for (k = 1; k < stack.length; k++) {
38674                         var ents = stack[k].entities;
38675                         if (ents.hasOwnProperty(id) && ents[id] === undefined) {
38676                             delete ents[id];
38677                         }
38678                     }
38679                 }
38680             }
38681         }
38682
38683         for (i = 0; i < stack.length; i++) {
38684             stack[i]._updateRebased();
38685         }
38686     },
38687
38688
38689     _updateRebased: function() {
38690         var base = this.base(),
38691             i, k, child, id, keys;
38692
38693         keys = Object.keys(this._parentWays);
38694         for (i = 0; i < keys.length; i++) {
38695             child = keys[i];
38696             if (base.parentWays[child]) {
38697                 for (k = 0; k < base.parentWays[child].length; k++) {
38698                     id = base.parentWays[child][k];
38699                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentWays[child], id)) {
38700                         this._parentWays[child].push(id);
38701                     }
38702                 }
38703             }
38704         }
38705
38706         keys = Object.keys(this._parentRels);
38707         for (i = 0; i < keys.length; i++) {
38708             child = keys[i];
38709             if (base.parentRels[child]) {
38710                 for (k = 0; k < base.parentRels[child].length; k++) {
38711                     id = base.parentRels[child][k];
38712                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentRels[child], id)) {
38713                         this._parentRels[child].push(id);
38714                     }
38715                 }
38716             }
38717         }
38718
38719         this.transients = {};
38720
38721         // this._childNodes is not updated, under the assumption that
38722         // ways are always downloaded with their child nodes.
38723     },
38724
38725
38726     // Updates calculated properties (parentWays, parentRels) for the specified change
38727     _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
38728
38729         parentWays = parentWays || this._parentWays;
38730         parentRels = parentRels || this._parentRels;
38731
38732         var type = entity && entity.type || oldentity && oldentity.type,
38733             removed, added, ways, rels, i;
38734
38735
38736         if (type === 'way') {
38737
38738             // Update parentWays
38739             if (oldentity && entity) {
38740                 removed = lodash.difference(oldentity.nodes, entity.nodes);
38741                 added = lodash.difference(entity.nodes, oldentity.nodes);
38742             } else if (oldentity) {
38743                 removed = oldentity.nodes;
38744                 added = [];
38745             } else if (entity) {
38746                 removed = [];
38747                 added = entity.nodes;
38748             }
38749             for (i = 0; i < removed.length; i++) {
38750                 parentWays[removed[i]] = lodash.without(parentWays[removed[i]], oldentity.id);
38751             }
38752             for (i = 0; i < added.length; i++) {
38753                 ways = lodash.without(parentWays[added[i]], entity.id);
38754                 ways.push(entity.id);
38755                 parentWays[added[i]] = ways;
38756             }
38757
38758         } else if (type === 'relation') {
38759
38760             // Update parentRels
38761             if (oldentity && entity) {
38762                 removed = lodash.difference(oldentity.members, entity.members);
38763                 added = lodash.difference(entity.members, oldentity);
38764             } else if (oldentity) {
38765                 removed = oldentity.members;
38766                 added = [];
38767             } else if (entity) {
38768                 removed = [];
38769                 added = entity.members;
38770             }
38771             for (i = 0; i < removed.length; i++) {
38772                 parentRels[removed[i].id] = lodash.without(parentRels[removed[i].id], oldentity.id);
38773             }
38774             for (i = 0; i < added.length; i++) {
38775                 rels = lodash.without(parentRels[added[i].id], entity.id);
38776                 rels.push(entity.id);
38777                 parentRels[added[i].id] = rels;
38778             }
38779         }
38780     },
38781
38782
38783     replace: function(entity) {
38784         if (this.entities[entity.id] === entity)
38785             return this;
38786
38787         return this.update(function() {
38788             this._updateCalculated(this.entities[entity.id], entity);
38789             this.entities[entity.id] = entity;
38790         });
38791     },
38792
38793
38794     remove: function(entity) {
38795         return this.update(function() {
38796             this._updateCalculated(entity, undefined);
38797             this.entities[entity.id] = undefined;
38798         });
38799     },
38800
38801
38802     revert: function(id) {
38803         var baseEntity = this.base().entities[id],
38804             headEntity = this.entities[id];
38805
38806         if (headEntity === baseEntity)
38807             return this;
38808
38809         return this.update(function() {
38810             this._updateCalculated(headEntity, baseEntity);
38811             delete this.entities[id];
38812         });
38813     },
38814
38815
38816     update: function() {
38817         var graph = this.frozen ? coreGraph$$1(this, true) : this;
38818
38819         for (var i = 0; i < arguments.length; i++) {
38820             arguments[i].call(graph, graph);
38821         }
38822
38823         if (this.frozen) graph.frozen = true;
38824
38825         return graph;
38826     },
38827
38828
38829     // Obliterates any existing entities
38830     load: function(entities) {
38831         var base = this.base();
38832         this.entities = Object.create(base.entities);
38833
38834         for (var i in entities) {
38835             this.entities[i] = entities[i];
38836             this._updateCalculated(base.entities[i], this.entities[i]);
38837         }
38838
38839         return this;
38840     }
38841 };
38842
38843 var index$10 = partialSort;
38844
38845 // Floyd-Rivest selection algorithm:
38846 // Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right];
38847 // The k-th element will have the (k - left + 1)th smallest value in [left, right]
38848
38849 function partialSort(arr, k, left, right, compare) {
38850     left = left || 0;
38851     right = right || (arr.length - 1);
38852     compare = compare || defaultCompare;
38853
38854     while (right > left) {
38855         if (right - left > 600) {
38856             var n = right - left + 1;
38857             var m = k - left + 1;
38858             var z = Math.log(n);
38859             var s = 0.5 * Math.exp(2 * z / 3);
38860             var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
38861             var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
38862             var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
38863             partialSort(arr, k, newLeft, newRight, compare);
38864         }
38865
38866         var t = arr[k];
38867         var i = left;
38868         var j = right;
38869
38870         swap(arr, left, k);
38871         if (compare(arr[right], t) > 0) swap(arr, left, right);
38872
38873         while (i < j) {
38874             swap(arr, i, j);
38875             i++;
38876             j--;
38877             while (compare(arr[i], t) < 0) i++;
38878             while (compare(arr[j], t) > 0) j--;
38879         }
38880
38881         if (compare(arr[left], t) === 0) swap(arr, left, j);
38882         else {
38883             j++;
38884             swap(arr, j, right);
38885         }
38886
38887         if (j <= k) left = j + 1;
38888         if (k <= j) right = j - 1;
38889     }
38890 }
38891
38892 function swap(arr, i, j) {
38893     var tmp = arr[i];
38894     arr[i] = arr[j];
38895     arr[j] = tmp;
38896 }
38897
38898 function defaultCompare(a, b) {
38899     return a < b ? -1 : a > b ? 1 : 0;
38900 }
38901
38902 var index$9 = rbush;
38903
38904
38905
38906 function rbush(maxEntries, format) {
38907     if (!(this instanceof rbush)) return new rbush(maxEntries, format);
38908
38909     // max entries in a node is 9 by default; min node fill is 40% for best performance
38910     this._maxEntries = Math.max(4, maxEntries || 9);
38911     this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
38912
38913     if (format) {
38914         this._initFormat(format);
38915     }
38916
38917     this.clear();
38918 }
38919
38920 rbush.prototype = {
38921
38922     all: function () {
38923         return this._all(this.data, []);
38924     },
38925
38926     search: function (bbox) {
38927
38928         var node = this.data,
38929             result = [],
38930             toBBox = this.toBBox;
38931
38932         if (!intersects$1(bbox, node)) return result;
38933
38934         var nodesToSearch = [],
38935             i, len, child, childBBox;
38936
38937         while (node) {
38938             for (i = 0, len = node.children.length; i < len; i++) {
38939
38940                 child = node.children[i];
38941                 childBBox = node.leaf ? toBBox(child) : child;
38942
38943                 if (intersects$1(bbox, childBBox)) {
38944                     if (node.leaf) result.push(child);
38945                     else if (contains$2(bbox, childBBox)) this._all(child, result);
38946                     else nodesToSearch.push(child);
38947                 }
38948             }
38949             node = nodesToSearch.pop();
38950         }
38951
38952         return result;
38953     },
38954
38955     collides: function (bbox) {
38956
38957         var node = this.data,
38958             toBBox = this.toBBox;
38959
38960         if (!intersects$1(bbox, node)) return false;
38961
38962         var nodesToSearch = [],
38963             i, len, child, childBBox;
38964
38965         while (node) {
38966             for (i = 0, len = node.children.length; i < len; i++) {
38967
38968                 child = node.children[i];
38969                 childBBox = node.leaf ? toBBox(child) : child;
38970
38971                 if (intersects$1(bbox, childBBox)) {
38972                     if (node.leaf || contains$2(bbox, childBBox)) return true;
38973                     nodesToSearch.push(child);
38974                 }
38975             }
38976             node = nodesToSearch.pop();
38977         }
38978
38979         return false;
38980     },
38981
38982     load: function (data) {
38983         if (!(data && data.length)) return this;
38984
38985         if (data.length < this._minEntries) {
38986             for (var i = 0, len = data.length; i < len; i++) {
38987                 this.insert(data[i]);
38988             }
38989             return this;
38990         }
38991
38992         // recursively build the tree with the given data from stratch using OMT algorithm
38993         var node = this._build(data.slice(), 0, data.length - 1, 0);
38994
38995         if (!this.data.children.length) {
38996             // save as is if tree is empty
38997             this.data = node;
38998
38999         } else if (this.data.height === node.height) {
39000             // split root if trees have the same height
39001             this._splitRoot(this.data, node);
39002
39003         } else {
39004             if (this.data.height < node.height) {
39005                 // swap trees if inserted one is bigger
39006                 var tmpNode = this.data;
39007                 this.data = node;
39008                 node = tmpNode;
39009             }
39010
39011             // insert the small tree into the large tree at appropriate level
39012             this._insert(node, this.data.height - node.height - 1, true);
39013         }
39014
39015         return this;
39016     },
39017
39018     insert: function (item) {
39019         if (item) this._insert(item, this.data.height - 1);
39020         return this;
39021     },
39022
39023     clear: function () {
39024         this.data = createNode([]);
39025         return this;
39026     },
39027
39028     remove: function (item, equalsFn) {
39029         if (!item) return this;
39030
39031         var node = this.data,
39032             bbox = this.toBBox(item),
39033             path = [],
39034             indexes = [],
39035             i, parent, index, goingUp;
39036
39037         // depth-first iterative tree traversal
39038         while (node || path.length) {
39039
39040             if (!node) { // go up
39041                 node = path.pop();
39042                 parent = path[path.length - 1];
39043                 i = indexes.pop();
39044                 goingUp = true;
39045             }
39046
39047             if (node.leaf) { // check current node
39048                 index = findItem(item, node.children, equalsFn);
39049
39050                 if (index !== -1) {
39051                     // item found, remove the item and condense tree upwards
39052                     node.children.splice(index, 1);
39053                     path.push(node);
39054                     this._condense(path);
39055                     return this;
39056                 }
39057             }
39058
39059             if (!goingUp && !node.leaf && contains$2(node, bbox)) { // go down
39060                 path.push(node);
39061                 indexes.push(i);
39062                 i = 0;
39063                 parent = node;
39064                 node = node.children[0];
39065
39066             } else if (parent) { // go right
39067                 i++;
39068                 node = parent.children[i];
39069                 goingUp = false;
39070
39071             } else node = null; // nothing found
39072         }
39073
39074         return this;
39075     },
39076
39077     toBBox: function (item) { return item; },
39078
39079     compareMinX: compareNodeMinX,
39080     compareMinY: compareNodeMinY,
39081
39082     toJSON: function () { return this.data; },
39083
39084     fromJSON: function (data) {
39085         this.data = data;
39086         return this;
39087     },
39088
39089     _all: function (node, result) {
39090         var nodesToSearch = [];
39091         while (node) {
39092             if (node.leaf) result.push.apply(result, node.children);
39093             else nodesToSearch.push.apply(nodesToSearch, node.children);
39094
39095             node = nodesToSearch.pop();
39096         }
39097         return result;
39098     },
39099
39100     _build: function (items, left, right, height) {
39101
39102         var N = right - left + 1,
39103             M = this._maxEntries,
39104             node;
39105
39106         if (N <= M) {
39107             // reached leaf level; return leaf
39108             node = createNode(items.slice(left, right + 1));
39109             calcBBox(node, this.toBBox);
39110             return node;
39111         }
39112
39113         if (!height) {
39114             // target height of the bulk-loaded tree
39115             height = Math.ceil(Math.log(N) / Math.log(M));
39116
39117             // target number of root entries to maximize storage utilization
39118             M = Math.ceil(N / Math.pow(M, height - 1));
39119         }
39120
39121         node = createNode([]);
39122         node.leaf = false;
39123         node.height = height;
39124
39125         // split the items into M mostly square tiles
39126
39127         var N2 = Math.ceil(N / M),
39128             N1 = N2 * Math.ceil(Math.sqrt(M)),
39129             i, j, right2, right3;
39130
39131         multiSelect(items, left, right, N1, this.compareMinX);
39132
39133         for (i = left; i <= right; i += N1) {
39134
39135             right2 = Math.min(i + N1 - 1, right);
39136
39137             multiSelect(items, i, right2, N2, this.compareMinY);
39138
39139             for (j = i; j <= right2; j += N2) {
39140
39141                 right3 = Math.min(j + N2 - 1, right2);
39142
39143                 // pack each entry recursively
39144                 node.children.push(this._build(items, j, right3, height - 1));
39145             }
39146         }
39147
39148         calcBBox(node, this.toBBox);
39149
39150         return node;
39151     },
39152
39153     _chooseSubtree: function (bbox, node, level, path) {
39154
39155         var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
39156
39157         while (true) {
39158             path.push(node);
39159
39160             if (node.leaf || path.length - 1 === level) break;
39161
39162             minArea = minEnlargement = Infinity;
39163
39164             for (i = 0, len = node.children.length; i < len; i++) {
39165                 child = node.children[i];
39166                 area = bboxArea(child);
39167                 enlargement = enlargedArea(bbox, child) - area;
39168
39169                 // choose entry with the least area enlargement
39170                 if (enlargement < minEnlargement) {
39171                     minEnlargement = enlargement;
39172                     minArea = area < minArea ? area : minArea;
39173                     targetNode = child;
39174
39175                 } else if (enlargement === minEnlargement) {
39176                     // otherwise choose one with the smallest area
39177                     if (area < minArea) {
39178                         minArea = area;
39179                         targetNode = child;
39180                     }
39181                 }
39182             }
39183
39184             node = targetNode || node.children[0];
39185         }
39186
39187         return node;
39188     },
39189
39190     _insert: function (item, level, isNode) {
39191
39192         var toBBox = this.toBBox,
39193             bbox = isNode ? item : toBBox(item),
39194             insertPath = [];
39195
39196         // find the best node for accommodating the item, saving all nodes along the path too
39197         var node = this._chooseSubtree(bbox, this.data, level, insertPath);
39198
39199         // put the item into the node
39200         node.children.push(item);
39201         extend$1(node, bbox);
39202
39203         // split on node overflow; propagate upwards if necessary
39204         while (level >= 0) {
39205             if (insertPath[level].children.length > this._maxEntries) {
39206                 this._split(insertPath, level);
39207                 level--;
39208             } else break;
39209         }
39210
39211         // adjust bboxes along the insertion path
39212         this._adjustParentBBoxes(bbox, insertPath, level);
39213     },
39214
39215     // split overflowed node into two
39216     _split: function (insertPath, level) {
39217
39218         var node = insertPath[level],
39219             M = node.children.length,
39220             m = this._minEntries;
39221
39222         this._chooseSplitAxis(node, m, M);
39223
39224         var splitIndex = this._chooseSplitIndex(node, m, M);
39225
39226         var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
39227         newNode.height = node.height;
39228         newNode.leaf = node.leaf;
39229
39230         calcBBox(node, this.toBBox);
39231         calcBBox(newNode, this.toBBox);
39232
39233         if (level) insertPath[level - 1].children.push(newNode);
39234         else this._splitRoot(node, newNode);
39235     },
39236
39237     _splitRoot: function (node, newNode) {
39238         // split root node
39239         this.data = createNode([node, newNode]);
39240         this.data.height = node.height + 1;
39241         this.data.leaf = false;
39242         calcBBox(this.data, this.toBBox);
39243     },
39244
39245     _chooseSplitIndex: function (node, m, M) {
39246
39247         var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
39248
39249         minOverlap = minArea = Infinity;
39250
39251         for (i = m; i <= M - m; i++) {
39252             bbox1 = distBBox(node, 0, i, this.toBBox);
39253             bbox2 = distBBox(node, i, M, this.toBBox);
39254
39255             overlap = intersectionArea(bbox1, bbox2);
39256             area = bboxArea(bbox1) + bboxArea(bbox2);
39257
39258             // choose distribution with minimum overlap
39259             if (overlap < minOverlap) {
39260                 minOverlap = overlap;
39261                 index = i;
39262
39263                 minArea = area < minArea ? area : minArea;
39264
39265             } else if (overlap === minOverlap) {
39266                 // otherwise choose distribution with minimum area
39267                 if (area < minArea) {
39268                     minArea = area;
39269                     index = i;
39270                 }
39271             }
39272         }
39273
39274         return index;
39275     },
39276
39277     // sorts node children by the best axis for split
39278     _chooseSplitAxis: function (node, m, M) {
39279
39280         var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
39281             compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
39282             xMargin = this._allDistMargin(node, m, M, compareMinX),
39283             yMargin = this._allDistMargin(node, m, M, compareMinY);
39284
39285         // if total distributions margin value is minimal for x, sort by minX,
39286         // otherwise it's already sorted by minY
39287         if (xMargin < yMargin) node.children.sort(compareMinX);
39288     },
39289
39290     // total margin of all possible split distributions where each node is at least m full
39291     _allDistMargin: function (node, m, M, compare) {
39292
39293         node.children.sort(compare);
39294
39295         var toBBox = this.toBBox,
39296             leftBBox = distBBox(node, 0, m, toBBox),
39297             rightBBox = distBBox(node, M - m, M, toBBox),
39298             margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
39299             i, child;
39300
39301         for (i = m; i < M - m; i++) {
39302             child = node.children[i];
39303             extend$1(leftBBox, node.leaf ? toBBox(child) : child);
39304             margin += bboxMargin(leftBBox);
39305         }
39306
39307         for (i = M - m - 1; i >= m; i--) {
39308             child = node.children[i];
39309             extend$1(rightBBox, node.leaf ? toBBox(child) : child);
39310             margin += bboxMargin(rightBBox);
39311         }
39312
39313         return margin;
39314     },
39315
39316     _adjustParentBBoxes: function (bbox, path, level) {
39317         // adjust bboxes along the given tree path
39318         for (var i = level; i >= 0; i--) {
39319             extend$1(path[i], bbox);
39320         }
39321     },
39322
39323     _condense: function (path) {
39324         // go through the path, removing empty nodes and updating bboxes
39325         for (var i = path.length - 1, siblings; i >= 0; i--) {
39326             if (path[i].children.length === 0) {
39327                 if (i > 0) {
39328                     siblings = path[i - 1].children;
39329                     siblings.splice(siblings.indexOf(path[i]), 1);
39330
39331                 } else this.clear();
39332
39333             } else calcBBox(path[i], this.toBBox);
39334         }
39335     },
39336
39337     _initFormat: function (format) {
39338         // data format (minX, minY, maxX, maxY accessors)
39339
39340         // uses eval-type function compilation instead of just accepting a toBBox function
39341         // because the algorithms are very sensitive to sorting functions performance,
39342         // so they should be dead simple and without inner calls
39343
39344         var compareArr = ['return a', ' - b', ';'];
39345
39346         this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
39347         this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
39348
39349         this.toBBox = new Function('a',
39350             'return {minX: a' + format[0] +
39351             ', minY: a' + format[1] +
39352             ', maxX: a' + format[2] +
39353             ', maxY: a' + format[3] + '};');
39354     }
39355 };
39356
39357 function findItem(item, items, equalsFn) {
39358     if (!equalsFn) return items.indexOf(item);
39359
39360     for (var i = 0; i < items.length; i++) {
39361         if (equalsFn(item, items[i])) return i;
39362     }
39363     return -1;
39364 }
39365
39366 // calculate node's bbox from bboxes of its children
39367 function calcBBox(node, toBBox) {
39368     distBBox(node, 0, node.children.length, toBBox, node);
39369 }
39370
39371 // min bounding rectangle of node children from k to p-1
39372 function distBBox(node, k, p, toBBox, destNode) {
39373     if (!destNode) destNode = createNode(null);
39374     destNode.minX = Infinity;
39375     destNode.minY = Infinity;
39376     destNode.maxX = -Infinity;
39377     destNode.maxY = -Infinity;
39378
39379     for (var i = k, child; i < p; i++) {
39380         child = node.children[i];
39381         extend$1(destNode, node.leaf ? toBBox(child) : child);
39382     }
39383
39384     return destNode;
39385 }
39386
39387 function extend$1(a, b) {
39388     a.minX = Math.min(a.minX, b.minX);
39389     a.minY = Math.min(a.minY, b.minY);
39390     a.maxX = Math.max(a.maxX, b.maxX);
39391     a.maxY = Math.max(a.maxY, b.maxY);
39392     return a;
39393 }
39394
39395 function compareNodeMinX(a, b) { return a.minX - b.minX; }
39396 function compareNodeMinY(a, b) { return a.minY - b.minY; }
39397
39398 function bboxArea(a)   { return (a.maxX - a.minX) * (a.maxY - a.minY); }
39399 function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
39400
39401 function enlargedArea(a, b) {
39402     return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
39403            (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
39404 }
39405
39406 function intersectionArea(a, b) {
39407     var minX = Math.max(a.minX, b.minX),
39408         minY = Math.max(a.minY, b.minY),
39409         maxX = Math.min(a.maxX, b.maxX),
39410         maxY = Math.min(a.maxY, b.maxY);
39411
39412     return Math.max(0, maxX - minX) *
39413            Math.max(0, maxY - minY);
39414 }
39415
39416 function contains$2(a, b) {
39417     return a.minX <= b.minX &&
39418            a.minY <= b.minY &&
39419            b.maxX <= a.maxX &&
39420            b.maxY <= a.maxY;
39421 }
39422
39423 function intersects$1(a, b) {
39424     return b.minX <= a.maxX &&
39425            b.minY <= a.maxY &&
39426            b.maxX >= a.minX &&
39427            b.maxY >= a.minY;
39428 }
39429
39430 function createNode(children) {
39431     return {
39432         children: children,
39433         height: 1,
39434         leaf: true,
39435         minX: Infinity,
39436         minY: Infinity,
39437         maxX: -Infinity,
39438         maxY: -Infinity
39439     };
39440 }
39441
39442 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
39443 // combines selection algorithm with binary divide & conquer approach
39444
39445 function multiSelect(arr, left, right, n, compare) {
39446     var stack = [left, right],
39447         mid;
39448
39449     while (stack.length) {
39450         right = stack.pop();
39451         left = stack.pop();
39452
39453         if (right - left <= n) continue;
39454
39455         mid = left + Math.ceil((right - left) / n / 2) * n;
39456         index$10(arr, mid, left, right, compare);
39457
39458         stack.push(left, mid, mid, right);
39459     }
39460 }
39461
39462 function coreTree(head) {
39463     var rtree = index$9(),
39464         bboxes = {},
39465         tree = {};
39466
39467
39468     function entityBBox(entity) {
39469         var bbox = entity.extent(head).bbox();
39470         bbox.id = entity.id;
39471         bboxes[entity.id] = bbox;
39472         return bbox;
39473     }
39474
39475
39476     function updateParents(entity, insertions, memo) {
39477         head.parentWays(entity).forEach(function(way) {
39478             if (bboxes[way.id]) {
39479                 rtree.remove(bboxes[way.id]);
39480                 insertions[way.id] = way;
39481             }
39482             updateParents(way, insertions, memo);
39483         });
39484
39485         head.parentRelations(entity).forEach(function(relation) {
39486             if (memo[entity.id]) return;
39487             memo[entity.id] = true;
39488             if (bboxes[relation.id]) {
39489                 rtree.remove(bboxes[relation.id]);
39490                 insertions[relation.id] = relation;
39491             }
39492             updateParents(relation, insertions, memo);
39493         });
39494     }
39495
39496
39497     tree.rebase = function(entities, force) {
39498         var insertions = {};
39499
39500         for (var i = 0; i < entities.length; i++) {
39501             var entity = entities[i];
39502
39503             if (!entity.visible)
39504                 continue;
39505
39506             if (head.entities.hasOwnProperty(entity.id) || bboxes[entity.id]) {
39507                 if (!force) {
39508                     continue;
39509                 } else if (bboxes[entity.id]) {
39510                     rtree.remove(bboxes[entity.id]);
39511                 }
39512             }
39513
39514             insertions[entity.id] = entity;
39515             updateParents(entity, insertions, {});
39516         }
39517
39518         rtree.load(lodash.map(insertions, entityBBox));
39519
39520         return tree;
39521     };
39522
39523
39524     tree.intersects = function(extent, graph) {
39525         if (graph !== head) {
39526             var diff = coreDifference(head, graph),
39527                 insertions = {};
39528
39529             head = graph;
39530
39531             diff.deleted().forEach(function(entity) {
39532                 rtree.remove(bboxes[entity.id]);
39533                 delete bboxes[entity.id];
39534             });
39535
39536             diff.modified().forEach(function(entity) {
39537                 rtree.remove(bboxes[entity.id]);
39538                 insertions[entity.id] = entity;
39539                 updateParents(entity, insertions, {});
39540             });
39541
39542             diff.created().forEach(function(entity) {
39543                 insertions[entity.id] = entity;
39544             });
39545
39546             rtree.load(lodash.map(insertions, entityBBox));
39547         }
39548
39549         return rtree.search(extent.bbox()).map(function(bbox) {
39550             return head.entity(bbox.id);
39551         });
39552     };
39553
39554
39555     return tree;
39556 }
39557
39558 /*
39559  * This code is licensed under the MIT license.
39560  *
39561  * Copyright © 2013, iD authors.
39562  *
39563  * Portions copyright © 2011, Keith Cirkel
39564  * See https://github.com/keithamus/jwerty
39565  *
39566  */
39567 function d3keybinding(namespace$$1) {
39568     var bindings = [];
39569
39570     function matches(binding, event$$1) {
39571         for (var p in binding.event) {
39572             if (event$$1[p] !== binding.event[p])
39573                 return false;
39574         }
39575         return true;
39576     }
39577
39578     function testBindings(isCapturing) {
39579         for (var i = 0; i < bindings.length; i++) {
39580             var binding = bindings[i];
39581
39582             if (!!binding.capture === isCapturing && matches(binding, event)) {
39583                 binding.callback();
39584             }
39585         }
39586     }
39587
39588     function capture() {
39589         testBindings(true);
39590     }
39591
39592     function bubble() {
39593         var tagName = select(event.target).node().tagName;
39594         if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
39595             return;
39596         }
39597         testBindings(false);
39598     }
39599
39600     function keybinding(selection$$1) {
39601         selection$$1 = selection$$1 || select(document);
39602         selection$$1.on('keydown.capture' + namespace$$1, capture, true);
39603         selection$$1.on('keydown.bubble' + namespace$$1, bubble, false);
39604         return keybinding;
39605     }
39606
39607     keybinding.off = function(selection$$1) {
39608         bindings = [];
39609         selection$$1 = selection$$1 || select(document);
39610         selection$$1.on('keydown.capture' + namespace$$1, null);
39611         selection$$1.on('keydown.bubble' + namespace$$1, null);
39612         return keybinding;
39613     };
39614
39615     keybinding.on = function(codes, callback, capture) {
39616         var arr = [].concat(codes);
39617         for (var i = 0; i < arr.length; i++) {
39618             var code = arr[i];
39619             var binding = {
39620                 event: {
39621                     keyCode: 0,
39622                     shiftKey: false,
39623                     ctrlKey: false,
39624                     altKey: false,
39625                     metaKey: false
39626                 },
39627                 capture: capture,
39628                 callback: callback
39629             };
39630
39631             code = code.toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
39632
39633             for (var j = 0; j < code.length; j++) {
39634                 // Normalise matching errors
39635                 if (code[j] === '++') code[i] = '+';
39636
39637                 if (code[j] in d3keybinding.modifierCodes) {
39638                     binding.event[d3keybinding.modifierProperties[d3keybinding.modifierCodes[code[j]]]] = true;
39639                 } else if (code[j] in d3keybinding.keyCodes) {
39640                     binding.event.keyCode = d3keybinding.keyCodes[code[j]];
39641                 }
39642             }
39643
39644             bindings.push(binding);
39645         }
39646
39647         return keybinding;
39648     };
39649
39650     return keybinding;
39651 }
39652
39653
39654 d3keybinding.modifierCodes = {
39655     // Shift key, ⇧
39656     '⇧': 16, shift: 16,
39657     // CTRL key, on Mac: ⌃
39658     '⌃': 17, ctrl: 17,
39659     // ALT key, on Mac: ⌥ (Alt)
39660     '⌥': 18, alt: 18, option: 18,
39661     // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
39662     '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
39663 };
39664
39665 d3keybinding.modifierProperties = {
39666     16: 'shiftKey',
39667     17: 'ctrlKey',
39668     18: 'altKey',
39669     91: 'metaKey'
39670 };
39671
39672 d3keybinding.keyCodes = {
39673     // Backspace key, on Mac: ⌫ (Backspace)
39674     '⌫': 8, backspace: 8,
39675     // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
39676     '⇥': 9, '⇆': 9, tab: 9,
39677     // Return key, ↩
39678     '↩': 13, 'return': 13, enter: 13, '⌅': 13,
39679     // Pause/Break key
39680     'pause': 19, 'pause-break': 19,
39681     // Caps Lock key, ⇪
39682     '⇪': 20, caps: 20, 'caps-lock': 20,
39683     // Escape key, on Mac: ⎋, on Windows: Esc
39684     '⎋': 27, escape: 27, esc: 27,
39685     // Space key
39686     space: 32,
39687     // Page-Up key, or pgup, on Mac: ↖
39688     '↖': 33, pgup: 33, 'page-up': 33,
39689     // Page-Down key, or pgdown, on Mac: ↘
39690     '↘': 34, pgdown: 34, 'page-down': 34,
39691     // END key, on Mac: ⇟
39692     '⇟': 35, end: 35,
39693     // HOME key, on Mac: ⇞
39694     '⇞': 36, home: 36,
39695     // Insert key, or ins
39696     ins: 45, insert: 45,
39697     // Delete key, on Mac: ⌦ (Delete)
39698     '⌦': 46, del: 46, 'delete': 46,
39699     // Left Arrow Key, or ←
39700     '←': 37, left: 37, 'arrow-left': 37,
39701     // Up Arrow Key, or ↑
39702     '↑': 38, up: 38, 'arrow-up': 38,
39703     // Right Arrow Key, or →
39704     '→': 39, right: 39, 'arrow-right': 39,
39705     // Up Arrow Key, or ↓
39706     '↓': 40, down: 40, 'arrow-down': 40,
39707     // odities, printing characters that come out wrong:
39708     // Firefox Equals
39709     'ffequals': 61,
39710     // Num-Multiply, or *
39711     '*': 106, star: 106, asterisk: 106, multiply: 106,
39712     // Num-Plus or +
39713     '+': 107, 'plus': 107,
39714     // Num-Subtract, or -
39715     '-': 109, subtract: 109,
39716     // Firefox Plus
39717     'ffplus': 171,
39718     // Firefox Minus
39719     'ffminus': 173,
39720     // Semicolon
39721     ';': 186, semicolon: 186,
39722     // = or equals
39723     '=': 187, 'equals': 187,
39724     // Comma, or ,
39725     ',': 188, comma: 188,
39726     // Dash / Underscore key
39727     'dash': 189,
39728     // Period, or ., or full-stop
39729     '.': 190, period: 190, 'full-stop': 190,
39730     // Slash, or /, or forward-slash
39731     '/': 191, slash: 191, 'forward-slash': 191,
39732     // Tick, or `, or back-quote
39733     '`': 192, tick: 192, 'back-quote': 192,
39734     // Open bracket, or [
39735     '[': 219, 'open-bracket': 219,
39736     // Back slash, or \
39737     '\\': 220, 'back-slash': 220,
39738     // Close backet, or ]
39739     ']': 221, 'close-bracket': 221,
39740     // Apostrophe, or Quote, or '
39741     '\'': 222, quote: 222, apostrophe: 222
39742 };
39743
39744 // NUMPAD 0-9
39745 var i$1 = 95;
39746 var n = 0;
39747 while (++i$1 < 106) {
39748     d3keybinding.keyCodes['num-' + n] = i$1;
39749     ++n;
39750 }
39751
39752 // 0-9
39753 i$1 = 47; n = 0;
39754 while (++i$1 < 58) {
39755     d3keybinding.keyCodes[n] = i$1;
39756     ++n;
39757 }
39758
39759 // F1-F25
39760 i$1 = 111; n = 1;
39761 while (++i$1 < 136) {
39762     d3keybinding.keyCodes['f' + n] = i$1;
39763     ++n;
39764 }
39765
39766 // a-z
39767 i$1 = 64;
39768 while (++i$1 < 91) {
39769     d3keybinding.keyCodes[String.fromCharCode(i$1).toLowerCase()] = i$1;
39770 }
39771
39772 function tooltip() {
39773   var tooltip = function(selection$$1) {
39774       selection$$1.each(setup);
39775     },
39776     animation = utilFunctor(false),
39777     html$$1 = utilFunctor(false),
39778     title = function() {
39779       var title = this.getAttribute('data-original-title');
39780       if (title) {
39781         return title;
39782       } else {
39783         title = this.getAttribute('title');
39784         this.removeAttribute('title');
39785         this.setAttribute('data-original-title', title);
39786       }
39787       return title;
39788     },
39789     over = 'mouseenter.tooltip',
39790     out = 'mouseleave.tooltip',
39791     placement = utilFunctor('top');
39792
39793
39794   tooltip.title = function(_) {
39795     if (arguments.length) {
39796       title = utilFunctor(_);
39797       return tooltip;
39798     } else {
39799       return title;
39800     }
39801   };
39802
39803
39804   tooltip.html = function(_) {
39805     if (arguments.length) {
39806       html$$1 = utilFunctor(_);
39807       return tooltip;
39808     } else {
39809       return html$$1;
39810     }
39811   };
39812
39813
39814   tooltip.placement = function(_) {
39815     if (arguments.length) {
39816       placement = utilFunctor(_);
39817       return tooltip;
39818     } else {
39819       return placement;
39820     }
39821   };
39822
39823
39824   tooltip.show = function(selection$$1) {
39825     selection$$1.each(show);
39826   };
39827
39828
39829   tooltip.hide = function(selection$$1) {
39830     selection$$1.each(hide);
39831   };
39832
39833
39834   tooltip.toggle = function(selection$$1) {
39835     selection$$1.each(toggle);
39836   };
39837
39838
39839   tooltip.destroy = function(selection$$1) {
39840     selection$$1
39841       .on(over, null)
39842       .on(out, null)
39843       .attr('title', function() {
39844         return this.getAttribute('data-original-title') || this.getAttribute('title');
39845       })
39846       .attr('data-original-title', null)
39847       .selectAll('.tooltip')
39848       .remove();
39849   };
39850
39851
39852   function setup() {
39853     var root = select(this),
39854         animate = animation.apply(this, arguments),
39855         tip = root.selectAll('.tooltip').data([0]);
39856
39857     var enter = tip.enter()
39858       .append('div')
39859       .attr('class', 'tooltip');
39860
39861     enter
39862       .append('div')
39863       .attr('class', 'tooltip-arrow');
39864
39865     enter
39866       .append('div')
39867       .attr('class', 'tooltip-inner');
39868
39869     tip = enter
39870       .merge(tip);
39871
39872     if (animate) {
39873       tip.classed('fade', true);
39874     }
39875
39876     var place = placement.apply(this, arguments);
39877     tip.classed(place, true);
39878
39879     root.on(over, show);
39880     root.on(out, hide);
39881   }
39882
39883
39884   function show() {
39885     var root = select(this),
39886       content = title.apply(this, arguments),
39887       tip = root.selectAll('.tooltip')
39888         .classed('in', true),
39889       markup = html$$1.apply(this, arguments);
39890
39891     tip.selectAll('.tooltip-inner')[markup ? 'html' : 'text'](content);
39892     var place = placement.apply(this, arguments),
39893       outer = getPosition(root.node()),
39894       inner = getPosition(tip.node()),
39895       pos;
39896
39897     switch (place) {
39898       case 'top':
39899         pos = {x: outer.x + (outer.w - inner.w) / 2, y: outer.y - inner.h};
39900         break;
39901       case 'right':
39902         pos = {x: outer.x + outer.w, y: outer.y + (outer.h - inner.h) / 2};
39903         break;
39904       case 'left':
39905         pos = {x: outer.x - inner.w, y: outer.y + (outer.h - inner.h) / 2};
39906         break;
39907       case 'bottom':
39908         pos = {x: Math.max(0, outer.x + (outer.w - inner.w) / 2), y: outer.y + outer.h};
39909         break;
39910     }
39911
39912     if (pos) {
39913       tip.style('left', ~~pos.x + 'px').style('top', ~~pos.y + 'px');
39914     } else {
39915       tip.style('left', null).style('top', null);
39916     }
39917
39918     this.tooltipVisible = true;
39919   }
39920
39921
39922   function hide() {
39923     select(this).selectAll('.tooltip')
39924       .classed('in', false);
39925
39926     this.tooltipVisible = false;
39927   }
39928
39929
39930   function toggle() {
39931     if (this.tooltipVisible) {
39932       hide.apply(this, arguments);
39933     } else {
39934       show.apply(this, arguments);
39935     }
39936   }
39937
39938   return tooltip;
39939 }
39940
39941
39942 function getPosition(node) {
39943   var mode = select(node).style('position');
39944   if (mode === 'absolute' || mode === 'static') {
39945     return {
39946       x: node.offsetLeft,
39947       y: node.offsetTop,
39948       w: node.offsetWidth,
39949       h: node.offsetHeight
39950     };
39951   } else {
39952     return {
39953       x: 0,
39954       y: 0,
39955       w: node.offsetWidth,
39956       h: node.offsetHeight
39957     };
39958   }
39959 }
39960
39961 function svgAreas$$1(projection, context) {
39962     // Patterns only work in Firefox when set directly on element.
39963     // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
39964     var patterns = {
39965         beach: 'beach',
39966         cemetery: 'cemetery',
39967         construction: 'construction',
39968         farm: 'farmland',
39969         farmland: 'farmland',
39970         grave_yard: 'cemetery',
39971         meadow: 'meadow',
39972         military: 'construction',
39973         orchard: 'orchard',
39974         sand: 'beach',
39975         scrub: 'scrub',
39976         wetland: 'wetland',
39977     };
39978
39979     var patternKeys = ['landuse', 'natural', 'amenity'];
39980
39981
39982     function setPattern(d) {
39983         for (var i = 0; i < patternKeys.length; i++) {
39984             if (d.tags.building && d.tags.building !== 'no') continue;
39985
39986             if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
39987                 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
39988                 return;
39989             }
39990         }
39991         this.style.fill = this.style.stroke = '';
39992     }
39993
39994
39995     return function drawAreas(selection$$1, graph, entities, filter) {
39996         var path$$1 = svgPath(projection, graph, true),
39997             areas = {},
39998             multipolygon;
39999
40000         for (var i = 0; i < entities.length; i++) {
40001             var entity = entities[i];
40002             if (entity.geometry(graph) !== 'area') continue;
40003
40004             multipolygon = osmIsSimpleMultipolygonOuterMember(entity, graph);
40005             if (multipolygon) {
40006                 areas[multipolygon.id] = {
40007                     entity: multipolygon.mergeTags(entity.tags),
40008                     area: Math.abs(entity.area(graph))
40009                 };
40010             } else if (!areas[entity.id]) {
40011                 areas[entity.id] = {
40012                     entity: entity,
40013                     area: Math.abs(entity.area(graph))
40014                 };
40015             }
40016         }
40017
40018         areas = values(areas).filter(function hasPath(a) { return path$$1(a.entity); });
40019         areas.sort(function areaSort(a, b) { return b.area - a.area; });
40020         areas = lodash.map(areas, 'entity');
40021
40022         var strokes = areas.filter(function(area$$1) {
40023             return area$$1.type === 'way';
40024         });
40025
40026         var data = {
40027             clip: areas,
40028             shadow: strokes,
40029             stroke: strokes,
40030             fill: areas
40031         };
40032
40033         var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath')
40034            .filter(filter)
40035            .data(data.clip, osmEntity$$1.key);
40036
40037         clipPaths.exit()
40038            .remove();
40039
40040         var clipPathsEnter = clipPaths.enter()
40041            .append('clipPath')
40042            .attr('class', 'clipPath')
40043            .attr('id', function(entity) { return entity.id + '-clippath'; });
40044
40045         clipPathsEnter
40046            .append('path');
40047
40048         clipPaths.merge(clipPathsEnter)
40049            .selectAll('path')
40050            .attr('d', path$$1);
40051
40052
40053         var layer = selection$$1.selectAll('.layer-areas');
40054
40055         var areagroup = layer
40056             .selectAll('g.areagroup')
40057             .data(['fill', 'shadow', 'stroke']);
40058
40059         areagroup = areagroup.enter()
40060             .append('g')
40061             .attr('class', function(d) { return 'areagroup area-' + d; })
40062             .merge(areagroup);
40063
40064         var paths = areagroup
40065             .selectAll('path')
40066             .filter(filter)
40067             .data(function(layer) { return data[layer]; }, osmEntity$$1.key);
40068
40069         paths.exit()
40070             .remove();
40071
40072         var fills = selection$$1.selectAll('.area-fill path.area').nodes();
40073
40074         var bisect$$1 = bisector(function(node) {
40075             return -node.__data__.area(graph);
40076         }).left;
40077
40078         function sortedByArea(entity) {
40079             if (this._parent.__data__ === 'fill') {
40080                 return fills[bisect$$1(fills, -entity.area(graph))];
40081             }
40082         }
40083
40084         paths = paths.enter()
40085             .insert('path', sortedByArea)
40086             .merge(paths)
40087             .each(function(entity) {
40088                 var layer = this.parentNode.__data__;
40089
40090                 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
40091
40092                 if (layer === 'fill') {
40093                     this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
40094                     setPattern.apply(this, arguments);
40095                 }
40096             })
40097             .call(svgTagClasses())
40098             .attr('d', path$$1);
40099     };
40100 }
40101
40102 function svgDebug(projection, context) {
40103
40104     function multipolygons(imagery) {
40105         return imagery.map(function(data$$1) {
40106             return {
40107                 type: 'MultiPolygon',
40108                 coordinates: [ data$$1.polygon ]
40109             };
40110         });
40111     }
40112
40113     function drawDebug(selection$$1) {
40114         var showsTile = context.getDebug('tile'),
40115             showsCollision = context.getDebug('collision'),
40116             showsImagery = context.getDebug('imagery'),
40117             showsImperial = context.getDebug('imperial'),
40118             showsDriveLeft = context.getDebug('driveLeft'),
40119             path$$1 = index$4(projection);
40120
40121
40122         var debugData = [];
40123         if (showsTile) {
40124             debugData.push({ class: 'red', label: 'tile' });
40125         }
40126         if (showsCollision) {
40127             debugData.push({ class: 'yellow', label: 'collision' });
40128         }
40129         if (showsImagery) {
40130             debugData.push({ class: 'orange', label: 'imagery' });
40131         }
40132         if (showsImperial) {
40133             debugData.push({ class: 'cyan', label: 'imperial' });
40134         }
40135         if (showsDriveLeft) {
40136             debugData.push({ class: 'green', label: 'driveLeft' });
40137         }
40138
40139
40140         var legend = select('#content')
40141             .selectAll('.debug-legend')
40142             .data(debugData.length ? [0] : []);
40143
40144         legend.exit()
40145             .remove();
40146
40147         legend = legend.enter()
40148             .append('div')
40149             .attr('class', 'fillD debug-legend')
40150             .merge(legend);
40151
40152
40153         var legendItems = legend.selectAll('.debug-legend-item')
40154             .data(debugData, function(d) { return d.label; });
40155
40156         legendItems.exit()
40157             .remove();
40158
40159         legendItems.enter()
40160             .append('span')
40161             .attr('class', function(d) { return 'debug-legend-item ' + d.class; })
40162             .text(function(d) { return d.label; });
40163
40164
40165         var layer = selection$$1.selectAll('.layer-debug')
40166             .data(showsImagery || showsImperial || showsDriveLeft ? [0] : []);
40167
40168         layer.exit()
40169             .remove();
40170
40171         layer = layer.enter()
40172             .append('g')
40173             .attr('class', 'layer-debug')
40174             .merge(layer);
40175
40176
40177         var extent$$1 = context.map().extent(),
40178             dataImagery = data.imagery || [],
40179             availableImagery = showsImagery && multipolygons(dataImagery.filter(function(source) {
40180                 if (!source.polygon) return false;
40181                 return source.polygon.some(function(polygon) {
40182                     return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
40183                 });
40184             }));
40185
40186         var imagery = layer.selectAll('path.debug-imagery')
40187             .data(showsImagery ? availableImagery : []);
40188
40189         imagery.exit()
40190             .remove();
40191
40192         imagery.enter()
40193             .append('path')
40194             .attr('class', 'debug-imagery debug orange');
40195
40196
40197         var imperial = layer
40198             .selectAll('path.debug-imperial')
40199             .data(showsImperial ? [dataImperial] : []);
40200
40201         imperial.exit()
40202             .remove();
40203
40204         imperial.enter()
40205             .append('path')
40206             .attr('class', 'debug-imperial debug cyan');
40207
40208
40209         var driveLeft = layer
40210             .selectAll('path.debug-drive-left')
40211             .data(showsDriveLeft ? [dataDriveLeft] : []);
40212
40213         driveLeft.exit()
40214             .remove();
40215
40216         driveLeft.enter()
40217             .append('path')
40218             .attr('class', 'debug-drive-left debug green');
40219
40220
40221         // update
40222         layer.selectAll('path')
40223             .attr('d', path$$1);
40224     }
40225
40226
40227     // This looks strange because `enabled` methods on other layers are
40228     // chainable getter/setters, and this one is just a getter.
40229     drawDebug.enabled = function() {
40230         if (!arguments.length) {
40231             return context.getDebug('tile') ||
40232                 context.getDebug('collision') ||
40233                 context.getDebug('imagery') ||
40234                 context.getDebug('imperial') ||
40235                 context.getDebug('driveLeft');
40236         } else {
40237             return this;
40238         }
40239     };
40240
40241
40242     return drawDebug;
40243 }
40244
40245 /*
40246     A standalone SVG element that contains only a `defs` sub-element. To be
40247     used once globally, since defs IDs must be unique within a document.
40248 */
40249 function svgDefs(context) {
40250
40251     function SVGSpriteDefinition(id, href) {
40252         return function(defs) {
40253             request(href)
40254                 .mimeType('image/svg+xml')
40255                 .response(function(xhr) { return xhr.responseXML; })
40256                 .get(function(err, svg) {
40257                     if (err) return;
40258                     defs.node().appendChild(
40259                         select(svg.documentElement).attr('id', id).node()
40260                     );
40261                 });
40262         };
40263     }
40264
40265
40266     return function drawDefs(selection$$1) {
40267         var defs = selection$$1.append('defs');
40268
40269         // marker
40270         defs.append('marker')
40271             .attr('id', 'oneway-marker')
40272             .attr('viewBox', '0 0 10 10')
40273             .attr('refY', 2.5)
40274             .attr('refX', 5)
40275             .attr('markerWidth', 2)
40276             .attr('markerHeight', 2)
40277             .attr('markerUnits', 'strokeWidth')
40278             .attr('orient', 'auto')
40279
40280             .append('path')
40281             .attr('class', 'oneway')
40282             .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')
40283             .attr('stroke', 'none')
40284             .attr('fill', '#000')
40285             .attr('opacity', '0.75');
40286
40287         // patterns
40288         var patterns = defs.selectAll('pattern')
40289             .data([
40290                 // pattern name, pattern image name
40291                 ['wetland', 'wetland'],
40292                 ['construction', 'construction'],
40293                 ['cemetery', 'cemetery'],
40294                 ['orchard', 'orchard'],
40295                 ['farmland', 'farmland'],
40296                 ['beach', 'dots'],
40297                 ['scrub', 'dots'],
40298                 ['meadow', 'dots']
40299             ])
40300             .enter()
40301             .append('pattern')
40302             .attr('id', function (d) {
40303                 return 'pattern-' + d[0];
40304             })
40305             .attr('width', 32)
40306             .attr('height', 32)
40307             .attr('patternUnits', 'userSpaceOnUse');
40308
40309         patterns.append('rect')
40310             .attr('x', 0)
40311             .attr('y', 0)
40312             .attr('width', 32)
40313             .attr('height', 32)
40314             .attr('class', function (d) {
40315                     return 'pattern-color-' + d[0];
40316             });
40317
40318         patterns.append('image')
40319             .attr('x', 0)
40320             .attr('y', 0)
40321             .attr('width', 32)
40322             .attr('height', 32)
40323             .attr('xlink:href', function (d) {
40324                 return context.imagePath('pattern/' + d[1] + '.png');
40325             });
40326
40327         // clip paths
40328         defs.selectAll()
40329             .data([12, 18, 20, 32, 45])
40330             .enter()
40331             .append('clipPath')
40332             .attr('id', function (d) {
40333                 return 'clip-square-' + d;
40334             })
40335             .append('rect')
40336             .attr('x', 0)
40337             .attr('y', 0)
40338             .attr('width', function (d) {
40339                 return d;
40340             })
40341             .attr('height', function (d) {
40342                 return d;
40343             });
40344
40345         defs.call(SVGSpriteDefinition(
40346             'iD-sprite',
40347             context.imagePath('iD-sprite.svg')));
40348
40349         defs.call(SVGSpriteDefinition(
40350             'maki-sprite',
40351             context.imagePath('maki-sprite.svg')));
40352     };
40353 }
40354
40355 var sax = createCommonjsModule(function (module, exports) {
40356 //[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]
40357 //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
40358 //[5]           Name       ::=          NameStartChar (NameChar)*
40359 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
40360 var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\u00B7\u0300-\u036F\\u203F-\u2040]");
40361 var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
40362 //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
40363 //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(',')
40364
40365 //S_TAG,        S_ATTR, S_EQ,   S_V
40366 //S_ATTR_S,     S_E,    S_S,    S_C
40367 var S_TAG = 0;//tag name offerring
40368 var S_ATTR = 1;//attr name offerring 
40369 var S_ATTR_S=2;//attr name end and space offer
40370 var S_EQ = 3;//=space?
40371 var S_V = 4;//attr value(no quot value only)
40372 var S_E = 5;//attr value end and no space(quot end)
40373 var S_S = 6;//(attr value end || tag end ) && (space offer)
40374 var S_C = 7;//closed el<el />
40375
40376 function XMLReader(){
40377         
40378 }
40379
40380 XMLReader.prototype = {
40381         parse:function(source,defaultNSMap,entityMap){
40382                 var domBuilder = this.domBuilder;
40383                 domBuilder.startDocument();
40384                 _copy(defaultNSMap ,defaultNSMap = {});
40385                 parse(source,defaultNSMap,entityMap,
40386                                 domBuilder,this.errorHandler);
40387                 domBuilder.endDocument();
40388         }
40389 };
40390 function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
40391   function fixedFromCharCode(code) {
40392                 // String.prototype.fromCharCode does not supports
40393                 // > 2 bytes unicode chars directly
40394                 if (code > 0xffff) {
40395                         code -= 0x10000;
40396                         var surrogate1 = 0xd800 + (code >> 10)
40397                                 , surrogate2 = 0xdc00 + (code & 0x3ff);
40398
40399                         return String.fromCharCode(surrogate1, surrogate2);
40400                 } else {
40401                         return String.fromCharCode(code);
40402                 }
40403         }
40404         function entityReplacer(a){
40405                 var k = a.slice(1,-1);
40406                 if(k in entityMap){
40407                         return entityMap[k]; 
40408                 }else if(k.charAt(0) === '#'){
40409                         return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))
40410                 }else{
40411                         errorHandler.error('entity not found:'+a);
40412                         return a;
40413                 }
40414         }
40415         function appendText(end){//has some bugs
40416                 if(end>start){
40417                         var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer);
40418                         locator&&position(start);
40419                         domBuilder.characters(xt,0,end-start);
40420                         start = end;
40421                 }
40422         }
40423         function position(p,m){
40424                 while(p>=lineEnd && (m = linePattern.exec(source))){
40425                         lineStart = m.index;
40426                         lineEnd = lineStart + m[0].length;
40427                         locator.lineNumber++;
40428                         //console.log('line++:',locator,startPos,endPos)
40429                 }
40430                 locator.columnNumber = p-lineStart+1;
40431         }
40432         var lineStart = 0;
40433         var lineEnd = 0;
40434         var linePattern = /.+(?:\r\n?|\n)|.*$/g;
40435         var locator = domBuilder.locator;
40436         
40437         var parseStack = [{currentNSMap:defaultNSMapCopy}];
40438         var closeMap = {};
40439         var start = 0;
40440         while(true){
40441                 try{
40442                         var tagStart = source.indexOf('<',start);
40443                         if(tagStart<0){
40444                                 if(!source.substr(start).match(/^\s*$/)){
40445                                         var doc = domBuilder.document;
40446                                 var text = doc.createTextNode(source.substr(start));
40447                                 doc.appendChild(text);
40448                                 domBuilder.currentElement = text;
40449                                 }
40450                                 return;
40451                         }
40452                         if(tagStart>start){
40453                                 appendText(tagStart);
40454                         }
40455                         switch(source.charAt(tagStart+1)){
40456                         case '/':
40457                                 var end = source.indexOf('>',tagStart+3);
40458                                 var tagName = source.substring(tagStart+2,end);
40459                                 var config = parseStack.pop();
40460                                 var localNSMap = config.localNSMap;
40461                         if(config.tagName != tagName){
40462                             errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName );
40463                         }
40464                                 domBuilder.endElement(config.uri,config.localName,tagName);
40465                                 if(localNSMap){
40466                                         for(var prefix in localNSMap){
40467                                                 domBuilder.endPrefixMapping(prefix) ;
40468                                         }
40469                                 }
40470                                 end++;
40471                                 break;
40472                                 // end elment
40473                         case '?':// <?...?>
40474                                 locator&&position(tagStart);
40475                                 end = parseInstruction(source,tagStart,domBuilder);
40476                                 break;
40477                         case '!':// <!doctype,<![CDATA,<!--
40478                                 locator&&position(tagStart);
40479                                 end = parseDCC(source,tagStart,domBuilder,errorHandler);
40480                                 break;
40481                         default:
40482                         
40483                                 locator&&position(tagStart);
40484                                 
40485                                 var el = new ElementAttributes();
40486                                 
40487                                 //elStartEnd
40488                                 var end = parseElementStartPart(source,tagStart,el,entityReplacer,errorHandler);
40489                                 var len = el.length;
40490                                 
40491                                 if(locator){
40492                                         if(len){
40493                                                 //attribute position fixed
40494                                                 for(var i = 0;i<len;i++){
40495                                                         var a = el[i];
40496                                                         position(a.offset);
40497                                                         a.offset = copyLocator(locator,{});
40498                                                 }
40499                                         }
40500                                         position(end);
40501                                 }
40502                                 if(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){
40503                                         el.closed = true;
40504                                         if(!entityMap.nbsp){
40505                                                 errorHandler.warning('unclosed xml attribute');
40506                                         }
40507                                 }
40508                                 appendElement(el,domBuilder,parseStack);
40509                                 
40510                                 
40511                                 if(el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed){
40512                                         end = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder);
40513                                 }else{
40514                                         end++;
40515                                 }
40516                         }
40517                 }catch(e){
40518                         errorHandler.error('element parse error: '+e);
40519                         end = -1;
40520                 }
40521                 if(end>start){
40522                         start = end;
40523                 }else{
40524                         //TODO: 这里有可能sax回退,有位置错误风险
40525                         appendText(Math.max(tagStart,start)+1);
40526                 }
40527         }
40528 }
40529 function copyLocator(f,t){
40530         t.lineNumber = f.lineNumber;
40531         t.columnNumber = f.columnNumber;
40532         return t;
40533 }
40534
40535 /**
40536  * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
40537  * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
40538  */
40539 function parseElementStartPart(source,start,el,entityReplacer,errorHandler){
40540         var attrName;
40541         var value;
40542         var p = ++start;
40543         var s = S_TAG;//status
40544         while(true){
40545                 var c = source.charAt(p);
40546                 switch(c){
40547                 case '=':
40548                         if(s === S_ATTR){//attrName
40549                                 attrName = source.slice(start,p);
40550                                 s = S_EQ;
40551                         }else if(s === S_ATTR_S){
40552                                 s = S_EQ;
40553                         }else{
40554                                 //fatalError: equal must after attrName or space after attrName
40555                                 throw new Error('attribute equal must after attrName');
40556                         }
40557                         break;
40558                 case '\'':
40559                 case '"':
40560                         if(s === S_EQ){//equal
40561                                 start = p+1;
40562                                 p = source.indexOf(c,start);
40563                                 if(p>0){
40564                                         value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40565                                         el.add(attrName,value,start-1);
40566                                         s = S_E;
40567                                 }else{
40568                                         //fatalError: no end quot match
40569                                         throw new Error('attribute value no end \''+c+'\' match');
40570                                 }
40571                         }else if(s == S_V){
40572                                 value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40573                                 //console.log(attrName,value,start,p)
40574                                 el.add(attrName,value,start);
40575                                 //console.dir(el)
40576                                 errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
40577                                 start = p+1;
40578                                 s = S_E;
40579                         }else{
40580                                 //fatalError: no equal before
40581                                 throw new Error('attribute value must after "="');
40582                         }
40583                         break;
40584                 case '/':
40585                         switch(s){
40586                         case S_TAG:
40587                                 el.setTagName(source.slice(start,p));
40588                         case S_E:
40589                         case S_S:
40590                         case S_C:
40591                                 s = S_C;
40592                                 el.closed = true;
40593                         case S_V:
40594                         case S_ATTR:
40595                         case S_ATTR_S:
40596                                 break;
40597                         //case S_EQ:
40598                         default:
40599                                 throw new Error("attribute invalid close char('/')")
40600                         }
40601                         break;
40602                 case ''://end document
40603                         //throw new Error('unexpected end of input')
40604                         errorHandler.error('unexpected end of input');
40605                 case '>':
40606                         switch(s){
40607                         case S_TAG:
40608                                 el.setTagName(source.slice(start,p));
40609                         case S_E:
40610                         case S_S:
40611                         case S_C:
40612                                 break;//normal
40613                         case S_V://Compatible state
40614                         case S_ATTR:
40615                                 value = source.slice(start,p);
40616                                 if(value.slice(-1) === '/'){
40617                                         el.closed  = true;
40618                                         value = value.slice(0,-1);
40619                                 }
40620                         case S_ATTR_S:
40621                                 if(s === S_ATTR_S){
40622                                         value = attrName;
40623                                 }
40624                                 if(s == S_V){
40625                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
40626                                         el.add(attrName,value.replace(/&#?\w+;/g,entityReplacer),start);
40627                                 }else{
40628                                         errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!');
40629                                         el.add(value,value,start);
40630                                 }
40631                                 break;
40632                         case S_EQ:
40633                                 throw new Error('attribute value missed!!');
40634                         }
40635 //                      console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
40636                         return p;
40637                 /*xml space '\x20' | #x9 | #xD | #xA; */
40638                 case '\u0080':
40639                         c = ' ';
40640                 default:
40641                         if(c<= ' '){//space
40642                                 switch(s){
40643                                 case S_TAG:
40644                                         el.setTagName(source.slice(start,p));//tagName
40645                                         s = S_S;
40646                                         break;
40647                                 case S_ATTR:
40648                                         attrName = source.slice(start,p);
40649                                         s = S_ATTR_S;
40650                                         break;
40651                                 case S_V:
40652                                         var value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40653                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
40654                                         el.add(attrName,value,start);
40655                                 case S_E:
40656                                         s = S_S;
40657                                         break;
40658                                 //case S_S:
40659                                 //case S_EQ:
40660                                 //case S_ATTR_S:
40661                                 //      void();break;
40662                                 //case S_C:
40663                                         //ignore warning
40664                                 }
40665                         }else{//not space
40666 //S_TAG,        S_ATTR, S_EQ,   S_V
40667 //S_ATTR_S,     S_E,    S_S,    S_C
40668                                 switch(s){
40669                                 //case S_TAG:void();break;
40670                                 //case S_ATTR:void();break;
40671                                 //case S_V:void();break;
40672                                 case S_ATTR_S:
40673                                         errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead!!');
40674                                         el.add(attrName,attrName,start);
40675                                         start = p;
40676                                         s = S_ATTR;
40677                                         break;
40678                                 case S_E:
40679                                         errorHandler.warning('attribute space is required"'+attrName+'"!!');
40680                                 case S_S:
40681                                         s = S_ATTR;
40682                                         start = p;
40683                                         break;
40684                                 case S_EQ:
40685                                         s = S_V;
40686                                         start = p;
40687                                         break;
40688                                 case S_C:
40689                                         throw new Error("elements closed character '/' and '>' must be connected to");
40690                                 }
40691                         }
40692                 }
40693                 p++;
40694         }
40695 }
40696 /**
40697  * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
40698  */
40699 function appendElement(el,domBuilder,parseStack){
40700         var tagName = el.tagName;
40701         var localNSMap = null;
40702         var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
40703         var i = el.length;
40704         while(i--){
40705                 var a = el[i];
40706                 var qName = a.qName;
40707                 var value = a.value;
40708                 var nsp = qName.indexOf(':');
40709                 if(nsp>0){
40710                         var prefix = a.prefix = qName.slice(0,nsp);
40711                         var localName = qName.slice(nsp+1);
40712                         var nsPrefix = prefix === 'xmlns' && localName;
40713                 }else{
40714                         localName = qName;
40715                         prefix = null;
40716                         nsPrefix = qName === 'xmlns' && '';
40717                 }
40718                 //can not set prefix,because prefix !== ''
40719                 a.localName = localName ;
40720                 //prefix == null for no ns prefix attribute 
40721                 if(nsPrefix !== false){//hack!!
40722                         if(localNSMap == null){
40723                                 localNSMap = {};
40724                                 //console.log(currentNSMap,0)
40725                                 _copy(currentNSMap,currentNSMap={});
40726                                 //console.log(currentNSMap,1)
40727                         }
40728                         currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
40729                         a.uri = 'http://www.w3.org/2000/xmlns/';
40730                         domBuilder.startPrefixMapping(nsPrefix, value); 
40731                 }
40732         }
40733         var i = el.length;
40734         while(i--){
40735                 a = el[i];
40736                 var prefix = a.prefix;
40737                 if(prefix){//no prefix attribute has no namespace
40738                         if(prefix === 'xml'){
40739                                 a.uri = 'http://www.w3.org/XML/1998/namespace';
40740                         }if(prefix !== 'xmlns'){
40741                                 a.uri = currentNSMap[prefix];
40742                                 
40743                                 //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
40744                         }
40745                 }
40746         }
40747         var nsp = tagName.indexOf(':');
40748         if(nsp>0){
40749                 prefix = el.prefix = tagName.slice(0,nsp);
40750                 localName = el.localName = tagName.slice(nsp+1);
40751         }else{
40752                 prefix = null;//important!!
40753                 localName = el.localName = tagName;
40754         }
40755         //no prefix element has default namespace
40756         var ns = el.uri = currentNSMap[prefix || ''];
40757         domBuilder.startElement(ns,localName,tagName,el);
40758         //endPrefixMapping and startPrefixMapping have not any help for dom builder
40759         //localNSMap = null
40760         if(el.closed){
40761                 domBuilder.endElement(ns,localName,tagName);
40762                 if(localNSMap){
40763                         for(prefix in localNSMap){
40764                                 domBuilder.endPrefixMapping(prefix); 
40765                         }
40766                 }
40767         }else{
40768                 el.currentNSMap = currentNSMap;
40769                 el.localNSMap = localNSMap;
40770                 parseStack.push(el);
40771         }
40772 }
40773 function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
40774         if(/^(?:script|textarea)$/i.test(tagName)){
40775                 var elEndStart =  source.indexOf('</'+tagName+'>',elStartEnd);
40776                 var text = source.substring(elStartEnd+1,elEndStart);
40777                 if(/[&<]/.test(text)){
40778                         if(/^script$/i.test(tagName)){
40779                                 //if(!/\]\]>/.test(text)){
40780                                         //lexHandler.startCDATA();
40781                                         domBuilder.characters(text,0,text.length);
40782                                         //lexHandler.endCDATA();
40783                                         return elEndStart;
40784                                 //}
40785                         }//}else{//text area
40786                                 text = text.replace(/&#?\w+;/g,entityReplacer);
40787                                 domBuilder.characters(text,0,text.length);
40788                                 return elEndStart;
40789                         //}
40790                         
40791                 }
40792         }
40793         return elStartEnd+1;
40794 }
40795 function fixSelfClosed(source,elStartEnd,tagName,closeMap){
40796         //if(tagName in closeMap){
40797         var pos = closeMap[tagName];
40798         if(pos == null){
40799                 //console.log(tagName)
40800                 pos = closeMap[tagName] = source.lastIndexOf('</'+tagName+'>');
40801         }
40802         return pos<elStartEnd;
40803         //} 
40804 }
40805 function _copy(source,target){
40806         for(var n in source){target[n] = source[n];}
40807 }
40808 function parseDCC(source,start,domBuilder,errorHandler){//sure start with '<!'
40809         var next= source.charAt(start+2);
40810         switch(next){
40811         case '-':
40812                 if(source.charAt(start + 3) === '-'){
40813                         var end = source.indexOf('-->',start+4);
40814                         //append comment source.substring(4,end)//<!--
40815                         if(end>start){
40816                                 domBuilder.comment(source,start+4,end-start-4);
40817                                 return end+3;
40818                         }else{
40819                                 errorHandler.error("Unclosed comment");
40820                                 return -1;
40821                         }
40822                 }else{
40823                         //error
40824                         return -1;
40825                 }
40826         default:
40827                 if(source.substr(start+3,6) == 'CDATA['){
40828                         var end = source.indexOf(']]>',start+9);
40829                         domBuilder.startCDATA();
40830                         domBuilder.characters(source,start+9,end-start-9);
40831                         domBuilder.endCDATA(); 
40832                         return end+3;
40833                 }
40834                 //<!DOCTYPE
40835                 //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
40836                 var matchs = split(source,start);
40837                 var len = matchs.length;
40838                 if(len>1 && /!doctype/i.test(matchs[0][0])){
40839                         var name = matchs[1][0];
40840                         var pubid = len>3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
40841                         var sysid = len>4 && matchs[4][0];
40842                         var lastMatch = matchs[len-1];
40843                         domBuilder.startDTD(name,pubid && pubid.replace(/^(['"])(.*?)\1$/,'$2'),
40844                                         sysid && sysid.replace(/^(['"])(.*?)\1$/,'$2'));
40845                         domBuilder.endDTD();
40846                         
40847                         return lastMatch.index+lastMatch[0].length
40848                 }
40849         }
40850         return -1;
40851 }
40852
40853
40854
40855 function parseInstruction(source,start,domBuilder){
40856         var end = source.indexOf('?>',start);
40857         if(end){
40858                 var match = source.substring(start,end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
40859                 if(match){
40860                         var len = match[0].length;
40861                         domBuilder.processingInstruction(match[1], match[2]) ;
40862                         return end+2;
40863                 }else{//error
40864                         return -1;
40865                 }
40866         }
40867         return -1;
40868 }
40869
40870 /**
40871  * @param source
40872  */
40873 function ElementAttributes(source){
40874         
40875 }
40876 ElementAttributes.prototype = {
40877         setTagName:function(tagName){
40878                 if(!tagNamePattern.test(tagName)){
40879                         throw new Error('invalid tagName:'+tagName)
40880                 }
40881                 this.tagName = tagName;
40882         },
40883         add:function(qName,value,offset){
40884                 if(!tagNamePattern.test(qName)){
40885                         throw new Error('invalid attribute:'+qName)
40886                 }
40887                 this[this.length++] = {qName:qName,value:value,offset:offset};
40888         },
40889         length:0,
40890         getLocalName:function(i){return this[i].localName},
40891         getOffset:function(i){return this[i].offset},
40892         getQName:function(i){return this[i].qName},
40893         getURI:function(i){return this[i].uri},
40894         getValue:function(i){return this[i].value}
40895 //      ,getIndex:function(uri, localName)){
40896 //              if(localName){
40897 //                      
40898 //              }else{
40899 //                      var qName = uri
40900 //              }
40901 //      },
40902 //      getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
40903 //      getType:function(uri,localName){}
40904 //      getType:function(i){},
40905 };
40906
40907
40908
40909
40910 function _set_proto_(thiz,parent){
40911         thiz.__proto__ = parent;
40912         return thiz;
40913 }
40914 if(!(_set_proto_({},_set_proto_.prototype) instanceof _set_proto_)){
40915         _set_proto_ = function(thiz,parent){
40916                 function p(){}
40917                 p.prototype = parent;
40918                 p = new p();
40919                 for(parent in thiz){
40920                         p[parent] = thiz[parent];
40921                 }
40922                 return p;
40923         };
40924 }
40925
40926 function split(source,start){
40927         var match;
40928         var buf = [];
40929         var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
40930         reg.lastIndex = start;
40931         reg.exec(source);//skip <
40932         while(match = reg.exec(source)){
40933                 buf.push(match);
40934                 if(match[1])return buf;
40935         }
40936 }
40937
40938 if(typeof commonjsRequire == 'function'){
40939         exports.XMLReader = XMLReader;
40940 }
40941 });
40942
40943 var dom = createCommonjsModule(function (module, exports) {
40944 /*
40945  * DOM Level 2
40946  * Object DOMException
40947  * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
40948  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
40949  */
40950
40951 function copy(src,dest){
40952         for(var p in src){
40953                 dest[p] = src[p];
40954         }
40955 }
40956 /**
40957 ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
40958 ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
40959  */
40960 function _extends(Class,Super){
40961         var pt = Class.prototype;
40962         if(Object.create){
40963                 var ppt = Object.create(Super.prototype);
40964                 pt.__proto__ = ppt;
40965         }
40966         if(!(pt instanceof Super)){
40967                 function t(){}
40968                 t.prototype = Super.prototype;
40969                 t = new t();
40970                 copy(pt,t);
40971                 Class.prototype = pt = t;
40972         }
40973         if(pt.constructor != Class){
40974                 if(typeof Class != 'function'){
40975                         console.error("unknow Class:"+Class);
40976                 }
40977                 pt.constructor = Class;
40978         }
40979 }
40980 var htmlns = 'http://www.w3.org/1999/xhtml';
40981 // Node Types
40982 var NodeType = {};
40983 var ELEMENT_NODE                = NodeType.ELEMENT_NODE                = 1;
40984 var ATTRIBUTE_NODE              = NodeType.ATTRIBUTE_NODE              = 2;
40985 var TEXT_NODE                   = NodeType.TEXT_NODE                   = 3;
40986 var CDATA_SECTION_NODE          = NodeType.CDATA_SECTION_NODE          = 4;
40987 var ENTITY_REFERENCE_NODE       = NodeType.ENTITY_REFERENCE_NODE       = 5;
40988 var ENTITY_NODE                 = NodeType.ENTITY_NODE                 = 6;
40989 var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
40990 var COMMENT_NODE                = NodeType.COMMENT_NODE                = 8;
40991 var DOCUMENT_NODE               = NodeType.DOCUMENT_NODE               = 9;
40992 var DOCUMENT_TYPE_NODE          = NodeType.DOCUMENT_TYPE_NODE          = 10;
40993 var DOCUMENT_FRAGMENT_NODE      = NodeType.DOCUMENT_FRAGMENT_NODE      = 11;
40994 var NOTATION_NODE               = NodeType.NOTATION_NODE               = 12;
40995
40996 // ExceptionCode
40997 var ExceptionCode = {};
40998 var ExceptionMessage = {};
40999 var INDEX_SIZE_ERR              = ExceptionCode.INDEX_SIZE_ERR              = ((ExceptionMessage[1]="Index size error"),1);
41000 var DOMSTRING_SIZE_ERR          = ExceptionCode.DOMSTRING_SIZE_ERR          = ((ExceptionMessage[2]="DOMString size error"),2);
41001 var HIERARCHY_REQUEST_ERR       = ExceptionCode.HIERARCHY_REQUEST_ERR       = ((ExceptionMessage[3]="Hierarchy request error"),3);
41002 var WRONG_DOCUMENT_ERR          = ExceptionCode.WRONG_DOCUMENT_ERR          = ((ExceptionMessage[4]="Wrong document"),4);
41003 var INVALID_CHARACTER_ERR       = ExceptionCode.INVALID_CHARACTER_ERR       = ((ExceptionMessage[5]="Invalid character"),5);
41004 var NO_DATA_ALLOWED_ERR         = ExceptionCode.NO_DATA_ALLOWED_ERR         = ((ExceptionMessage[6]="No data allowed"),6);
41005 var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]="No modification allowed"),7);
41006 var NOT_FOUND_ERR               = ExceptionCode.NOT_FOUND_ERR               = ((ExceptionMessage[8]="Not found"),8);
41007 var NOT_SUPPORTED_ERR           = ExceptionCode.NOT_SUPPORTED_ERR           = ((ExceptionMessage[9]="Not supported"),9);
41008 var INUSE_ATTRIBUTE_ERR         = ExceptionCode.INUSE_ATTRIBUTE_ERR         = ((ExceptionMessage[10]="Attribute in use"),10);
41009 //level2
41010 var INVALID_STATE_ERR           = ExceptionCode.INVALID_STATE_ERR               = ((ExceptionMessage[11]="Invalid state"),11);
41011 var SYNTAX_ERR                  = ExceptionCode.SYNTAX_ERR                      = ((ExceptionMessage[12]="Syntax error"),12);
41012 var INVALID_MODIFICATION_ERR    = ExceptionCode.INVALID_MODIFICATION_ERR        = ((ExceptionMessage[13]="Invalid modification"),13);
41013 var NAMESPACE_ERR               = ExceptionCode.NAMESPACE_ERR                   = ((ExceptionMessage[14]="Invalid namespace"),14);
41014 var INVALID_ACCESS_ERR          = ExceptionCode.INVALID_ACCESS_ERR              = ((ExceptionMessage[15]="Invalid access"),15);
41015
41016
41017 function DOMException(code, message) {
41018         if(message instanceof Error){
41019                 var error = message;
41020         }else{
41021                 error = this;
41022                 Error.call(this, ExceptionMessage[code]);
41023                 this.message = ExceptionMessage[code];
41024                 if(Error.captureStackTrace) Error.captureStackTrace(this, DOMException);
41025         }
41026         error.code = code;
41027         if(message) this.message = this.message + ": " + message;
41028         return error;
41029 }
41030 DOMException.prototype = Error.prototype;
41031 copy(ExceptionCode,DOMException);
41032 /**
41033  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
41034  * 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.
41035  * The items in the NodeList are accessible via an integral index, starting from 0.
41036  */
41037 function NodeList() {
41038 }
41039 NodeList.prototype = {
41040         /**
41041          * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
41042          * @standard level1
41043          */
41044         length:0, 
41045         /**
41046          * 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.
41047          * @standard level1
41048          * @param index  unsigned long 
41049          *   Index into the collection.
41050          * @return Node
41051          *      The node at the indexth position in the NodeList, or null if that is not a valid index. 
41052          */
41053         item: function(index) {
41054                 return this[index] || null;
41055         },
41056         toString:function(){
41057                 for(var buf = [], i = 0;i<this.length;i++){
41058                         serializeToString(this[i],buf);
41059                 }
41060                 return buf.join('');
41061         }
41062 };
41063 function LiveNodeList(node,refresh){
41064         this._node = node;
41065         this._refresh = refresh;
41066         _updateLiveList(this);
41067 }
41068 function _updateLiveList(list){
41069         var inc = list._node._inc || list._node.ownerDocument._inc;
41070         if(list._inc != inc){
41071                 var ls = list._refresh(list._node);
41072                 //console.log(ls.length)
41073                 __set__(list,'length',ls.length);
41074                 copy(ls,list);
41075                 list._inc = inc;
41076         }
41077 }
41078 LiveNodeList.prototype.item = function(i){
41079         _updateLiveList(this);
41080         return this[i];
41081 };
41082
41083 _extends(LiveNodeList,NodeList);
41084 /**
41085  * 
41086  * 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.
41087  * NamedNodeMap objects in the DOM are live.
41088  * used for attributes or DocumentType entities 
41089  */
41090 function NamedNodeMap() {
41091 }
41092
41093 function _findNodeIndex(list,node){
41094         var i = list.length;
41095         while(i--){
41096                 if(list[i] === node){return i}
41097         }
41098 }
41099
41100 function _addNamedNode(el,list,newAttr,oldAttr){
41101         if(oldAttr){
41102                 list[_findNodeIndex(list,oldAttr)] = newAttr;
41103         }else{
41104                 list[list.length++] = newAttr;
41105         }
41106         if(el){
41107                 newAttr.ownerElement = el;
41108                 var doc = el.ownerDocument;
41109                 if(doc){
41110                         oldAttr && _onRemoveAttribute(doc,el,oldAttr);
41111                         _onAddAttribute(doc,el,newAttr);
41112                 }
41113         }
41114 }
41115 function _removeNamedNode(el,list,attr){
41116         var i = _findNodeIndex(list,attr);
41117         if(i>=0){
41118                 var lastIndex = list.length-1;
41119                 while(i<lastIndex){
41120                         list[i] = list[++i];
41121                 }
41122                 list.length = lastIndex;
41123                 if(el){
41124                         var doc = el.ownerDocument;
41125                         if(doc){
41126                                 _onRemoveAttribute(doc,el,attr);
41127                                 attr.ownerElement = null;
41128                         }
41129                 }
41130         }else{
41131                 throw DOMException(NOT_FOUND_ERR,new Error())
41132         }
41133 }
41134 NamedNodeMap.prototype = {
41135         length:0,
41136         item:NodeList.prototype.item,
41137         getNamedItem: function(key) {
41138 //              if(key.indexOf(':')>0 || key == 'xmlns'){
41139 //                      return null;
41140 //              }
41141                 var i = this.length;
41142                 while(i--){
41143                         var attr = this[i];
41144                         if(attr.nodeName == key){
41145                                 return attr;
41146                         }
41147                 }
41148         },
41149         setNamedItem: function(attr) {
41150                 var el = attr.ownerElement;
41151                 if(el && el!=this._ownerElement){
41152                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41153                 }
41154                 var oldAttr = this.getNamedItem(attr.nodeName);
41155                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41156                 return oldAttr;
41157         },
41158         /* returns Node */
41159         setNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
41160                 var el = attr.ownerElement, oldAttr;
41161                 if(el && el!=this._ownerElement){
41162                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41163                 }
41164                 oldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName);
41165                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41166                 return oldAttr;
41167         },
41168
41169         /* returns Node */
41170         removeNamedItem: function(key) {
41171                 var attr = this.getNamedItem(key);
41172                 _removeNamedNode(this._ownerElement,this,attr);
41173                 return attr;
41174                 
41175                 
41176         },// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
41177         
41178         //for level2
41179         removeNamedItemNS:function(namespaceURI,localName){
41180                 var attr = this.getNamedItemNS(namespaceURI,localName);
41181                 _removeNamedNode(this._ownerElement,this,attr);
41182                 return attr;
41183         },
41184         getNamedItemNS: function(namespaceURI, localName) {
41185                 var i = this.length;
41186                 while(i--){
41187                         var node = this[i];
41188                         if(node.localName == localName && node.namespaceURI == namespaceURI){
41189                                 return node;
41190                         }
41191                 }
41192                 return null;
41193         }
41194 };
41195 /**
41196  * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
41197  */
41198 function DOMImplementation(/* Object */ features) {
41199         this._features = {};
41200         if (features) {
41201                 for (var feature in features) {
41202                          this._features = features[feature];
41203                 }
41204         }
41205 }
41206
41207 DOMImplementation.prototype = {
41208         hasFeature: function(/* string */ feature, /* string */ version) {
41209                 var versions = this._features[feature.toLowerCase()];
41210                 if (versions && (!version || version in versions)) {
41211                         return true;
41212                 } else {
41213                         return false;
41214                 }
41215         },
41216         // Introduced in DOM Level 2:
41217         createDocument:function(namespaceURI,  qualifiedName, doctype){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
41218                 var doc = new Document();
41219                 doc.implementation = this;
41220                 doc.childNodes = new NodeList();
41221                 doc.doctype = doctype;
41222                 if(doctype){
41223                         doc.appendChild(doctype);
41224                 }
41225                 if(qualifiedName){
41226                         var root = doc.createElementNS(namespaceURI,qualifiedName);
41227                         doc.appendChild(root);
41228                 }
41229                 return doc;
41230         },
41231         // Introduced in DOM Level 2:
41232         createDocumentType:function(qualifiedName, publicId, systemId){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
41233                 var node = new DocumentType();
41234                 node.name = qualifiedName;
41235                 node.nodeName = qualifiedName;
41236                 node.publicId = publicId;
41237                 node.systemId = systemId;
41238                 // Introduced in DOM Level 2:
41239                 //readonly attribute DOMString        internalSubset;
41240                 
41241                 //TODO:..
41242                 //  readonly attribute NamedNodeMap     entities;
41243                 //  readonly attribute NamedNodeMap     notations;
41244                 return node;
41245         }
41246 };
41247
41248
41249 /**
41250  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
41251  */
41252
41253 function Node() {
41254 }
41255
41256 Node.prototype = {
41257         firstChild : null,
41258         lastChild : null,
41259         previousSibling : null,
41260         nextSibling : null,
41261         attributes : null,
41262         parentNode : null,
41263         childNodes : null,
41264         ownerDocument : null,
41265         nodeValue : null,
41266         namespaceURI : null,
41267         prefix : null,
41268         localName : null,
41269         // Modified in DOM Level 2:
41270         insertBefore:function(newChild, refChild){//raises 
41271                 return _insertBefore(this,newChild,refChild);
41272         },
41273         replaceChild:function(newChild, oldChild){//raises 
41274                 this.insertBefore(newChild,oldChild);
41275                 if(oldChild){
41276                         this.removeChild(oldChild);
41277                 }
41278         },
41279         removeChild:function(oldChild){
41280                 return _removeChild(this,oldChild);
41281         },
41282         appendChild:function(newChild){
41283                 return this.insertBefore(newChild,null);
41284         },
41285         hasChildNodes:function(){
41286                 return this.firstChild != null;
41287         },
41288         cloneNode:function(deep){
41289                 return cloneNode(this.ownerDocument||this,this,deep);
41290         },
41291         // Modified in DOM Level 2:
41292         normalize:function(){
41293                 var child = this.firstChild;
41294                 while(child){
41295                         var next = child.nextSibling;
41296                         if(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){
41297                                 this.removeChild(next);
41298                                 child.appendData(next.data);
41299                         }else{
41300                                 child.normalize();
41301                                 child = next;
41302                         }
41303                 }
41304         },
41305         // Introduced in DOM Level 2:
41306         isSupported:function(feature, version){
41307                 return this.ownerDocument.implementation.hasFeature(feature,version);
41308         },
41309     // Introduced in DOM Level 2:
41310     hasAttributes:function(){
41311         return this.attributes.length>0;
41312     },
41313     lookupPrefix:function(namespaceURI){
41314         var el = this;
41315         while(el){
41316                 var map = el._nsMap;
41317                 //console.dir(map)
41318                 if(map){
41319                         for(var n in map){
41320                                 if(map[n] == namespaceURI){
41321                                         return n;
41322                                 }
41323                         }
41324                 }
41325                 el = el.nodeType == 2?el.ownerDocument : el.parentNode;
41326         }
41327         return null;
41328     },
41329     // Introduced in DOM Level 3:
41330     lookupNamespaceURI:function(prefix){
41331         var el = this;
41332         while(el){
41333                 var map = el._nsMap;
41334                 //console.dir(map)
41335                 if(map){
41336                         if(prefix in map){
41337                                 return map[prefix] ;
41338                         }
41339                 }
41340                 el = el.nodeType == 2?el.ownerDocument : el.parentNode;
41341         }
41342         return null;
41343     },
41344     // Introduced in DOM Level 3:
41345     isDefaultNamespace:function(namespaceURI){
41346         var prefix = this.lookupPrefix(namespaceURI);
41347         return prefix == null;
41348     }
41349 };
41350
41351
41352 function _xmlEncoder(c){
41353         return c == '<' && '&lt;' ||
41354          c == '>' && '&gt;' ||
41355          c == '&' && '&amp;' ||
41356          c == '"' && '&quot;' ||
41357          '&#'+c.charCodeAt()+';'
41358 }
41359
41360
41361 copy(NodeType,Node);
41362 copy(NodeType,Node.prototype);
41363
41364 /**
41365  * @param callback return true for continue,false for break
41366  * @return boolean true: break visit;
41367  */
41368 function _visitNode(node,callback){
41369         if(callback(node)){
41370                 return true;
41371         }
41372         if(node = node.firstChild){
41373                 do{
41374                         if(_visitNode(node,callback)){return true}
41375         }while(node=node.nextSibling)
41376     }
41377 }
41378
41379
41380
41381 function Document(){
41382 }
41383 function _onAddAttribute(doc,el,newAttr){
41384         doc && doc._inc++;
41385         var ns = newAttr.namespaceURI;
41386         if(ns == 'http://www.w3.org/2000/xmlns/'){
41387                 //update namespace
41388                 el._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value;
41389         }
41390 }
41391 function _onRemoveAttribute(doc,el,newAttr,remove){
41392         doc && doc._inc++;
41393         var ns = newAttr.namespaceURI;
41394         if(ns == 'http://www.w3.org/2000/xmlns/'){
41395                 //update namespace
41396                 delete el._nsMap[newAttr.prefix?newAttr.localName:''];
41397         }
41398 }
41399 function _onUpdateChild(doc,el,newChild){
41400         if(doc && doc._inc){
41401                 doc._inc++;
41402                 //update childNodes
41403                 var cs = el.childNodes;
41404                 if(newChild){
41405                         cs[cs.length++] = newChild;
41406                 }else{
41407                         //console.log(1)
41408                         var child = el.firstChild;
41409                         var i = 0;
41410                         while(child){
41411                                 cs[i++] = child;
41412                                 child =child.nextSibling;
41413                         }
41414                         cs.length = i;
41415                 }
41416         }
41417 }
41418
41419 /**
41420  * attributes;
41421  * children;
41422  * 
41423  * writeable properties:
41424  * nodeValue,Attr:value,CharacterData:data
41425  * prefix
41426  */
41427 function _removeChild(parentNode,child){
41428         var previous = child.previousSibling;
41429         var next = child.nextSibling;
41430         if(previous){
41431                 previous.nextSibling = next;
41432         }else{
41433                 parentNode.firstChild = next;
41434         }
41435         if(next){
41436                 next.previousSibling = previous;
41437         }else{
41438                 parentNode.lastChild = previous;
41439         }
41440         _onUpdateChild(parentNode.ownerDocument,parentNode);
41441         return child;
41442 }
41443 /**
41444  * preformance key(refChild == null)
41445  */
41446 function _insertBefore(parentNode,newChild,nextChild){
41447         var cp = newChild.parentNode;
41448         if(cp){
41449                 cp.removeChild(newChild);//remove and update
41450         }
41451         if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
41452                 var newFirst = newChild.firstChild;
41453                 if (newFirst == null) {
41454                         return newChild;
41455                 }
41456                 var newLast = newChild.lastChild;
41457         }else{
41458                 newFirst = newLast = newChild;
41459         }
41460         var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
41461
41462         newFirst.previousSibling = pre;
41463         newLast.nextSibling = nextChild;
41464         
41465         
41466         if(pre){
41467                 pre.nextSibling = newFirst;
41468         }else{
41469                 parentNode.firstChild = newFirst;
41470         }
41471         if(nextChild == null){
41472                 parentNode.lastChild = newLast;
41473         }else{
41474                 nextChild.previousSibling = newLast;
41475         }
41476         do{
41477                 newFirst.parentNode = parentNode;
41478         }while(newFirst !== newLast && (newFirst= newFirst.nextSibling))
41479         _onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);
41480         //console.log(parentNode.lastChild.nextSibling == null)
41481         if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
41482                 newChild.firstChild = newChild.lastChild = null;
41483         }
41484         return newChild;
41485 }
41486 function _appendSingleChild(parentNode,newChild){
41487         var cp = newChild.parentNode;
41488         if(cp){
41489                 var pre = parentNode.lastChild;
41490                 cp.removeChild(newChild);//remove and update
41491                 var pre = parentNode.lastChild;
41492         }
41493         var pre = parentNode.lastChild;
41494         newChild.parentNode = parentNode;
41495         newChild.previousSibling = pre;
41496         newChild.nextSibling = null;
41497         if(pre){
41498                 pre.nextSibling = newChild;
41499         }else{
41500                 parentNode.firstChild = newChild;
41501         }
41502         parentNode.lastChild = newChild;
41503         _onUpdateChild(parentNode.ownerDocument,parentNode,newChild);
41504         return newChild;
41505         //console.log("__aa",parentNode.lastChild.nextSibling == null)
41506 }
41507 Document.prototype = {
41508         //implementation : null,
41509         nodeName :  '#document',
41510         nodeType :  DOCUMENT_NODE,
41511         doctype :  null,
41512         documentElement :  null,
41513         _inc : 1,
41514         
41515         insertBefore :  function(newChild, refChild){//raises 
41516                 if(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){
41517                         var child = newChild.firstChild;
41518                         while(child){
41519                                 var next = child.nextSibling;
41520                                 this.insertBefore(child,refChild);
41521                                 child = next;
41522                         }
41523                         return newChild;
41524                 }
41525                 if(this.documentElement == null && newChild.nodeType == 1){
41526                         this.documentElement = newChild;
41527                 }
41528                 
41529                 return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;
41530         },
41531         removeChild :  function(oldChild){
41532                 if(this.documentElement == oldChild){
41533                         this.documentElement = null;
41534                 }
41535                 return _removeChild(this,oldChild);
41536         },
41537         // Introduced in DOM Level 2:
41538         importNode : function(importedNode,deep){
41539                 return importNode(this,importedNode,deep);
41540         },
41541         // Introduced in DOM Level 2:
41542         getElementById :        function(id){
41543                 var rtv = null;
41544                 _visitNode(this.documentElement,function(node){
41545                         if(node.nodeType == 1){
41546                                 if(node.getAttribute('id') == id){
41547                                         rtv = node;
41548                                         return true;
41549                                 }
41550                         }
41551                 });
41552                 return rtv;
41553         },
41554         
41555         //document factory method:
41556         createElement : function(tagName){
41557                 var node = new Element();
41558                 node.ownerDocument = this;
41559                 node.nodeName = tagName;
41560                 node.tagName = tagName;
41561                 node.childNodes = new NodeList();
41562                 var attrs       = node.attributes = new NamedNodeMap();
41563                 attrs._ownerElement = node;
41564                 return node;
41565         },
41566         createDocumentFragment :        function(){
41567                 var node = new DocumentFragment();
41568                 node.ownerDocument = this;
41569                 node.childNodes = new NodeList();
41570                 return node;
41571         },
41572         createTextNode :        function(data){
41573                 var node = new Text();
41574                 node.ownerDocument = this;
41575                 node.appendData(data);
41576                 return node;
41577         },
41578         createComment : function(data){
41579                 var node = new Comment();
41580                 node.ownerDocument = this;
41581                 node.appendData(data);
41582                 return node;
41583         },
41584         createCDATASection :    function(data){
41585                 var node = new CDATASection();
41586                 node.ownerDocument = this;
41587                 node.appendData(data);
41588                 return node;
41589         },
41590         createProcessingInstruction :   function(target,data){
41591                 var node = new ProcessingInstruction();
41592                 node.ownerDocument = this;
41593                 node.tagName = node.target = target;
41594                 node.nodeValue= node.data = data;
41595                 return node;
41596         },
41597         createAttribute :       function(name){
41598                 var node = new Attr();
41599                 node.ownerDocument      = this;
41600                 node.name = name;
41601                 node.nodeName   = name;
41602                 node.localName = name;
41603                 node.specified = true;
41604                 return node;
41605         },
41606         createEntityReference : function(name){
41607                 var node = new EntityReference();
41608                 node.ownerDocument      = this;
41609                 node.nodeName   = name;
41610                 return node;
41611         },
41612         // Introduced in DOM Level 2:
41613         createElementNS :       function(namespaceURI,qualifiedName){
41614                 var node = new Element();
41615                 var pl = qualifiedName.split(':');
41616                 var attrs       = node.attributes = new NamedNodeMap();
41617                 node.childNodes = new NodeList();
41618                 node.ownerDocument = this;
41619                 node.nodeName = qualifiedName;
41620                 node.tagName = qualifiedName;
41621                 node.namespaceURI = namespaceURI;
41622                 if(pl.length == 2){
41623                         node.prefix = pl[0];
41624                         node.localName = pl[1];
41625                 }else{
41626                         //el.prefix = null;
41627                         node.localName = qualifiedName;
41628                 }
41629                 attrs._ownerElement = node;
41630                 return node;
41631         },
41632         // Introduced in DOM Level 2:
41633         createAttributeNS :     function(namespaceURI,qualifiedName){
41634                 var node = new Attr();
41635                 var pl = qualifiedName.split(':');
41636                 node.ownerDocument = this;
41637                 node.nodeName = qualifiedName;
41638                 node.name = qualifiedName;
41639                 node.namespaceURI = namespaceURI;
41640                 node.specified = true;
41641                 if(pl.length == 2){
41642                         node.prefix = pl[0];
41643                         node.localName = pl[1];
41644                 }else{
41645                         //el.prefix = null;
41646                         node.localName = qualifiedName;
41647                 }
41648                 return node;
41649         }
41650 };
41651 _extends(Document,Node);
41652
41653
41654 function Element() {
41655         this._nsMap = {};
41656 }
41657 Element.prototype = {
41658         nodeType : ELEMENT_NODE,
41659         hasAttribute : function(name){
41660                 return this.getAttributeNode(name)!=null;
41661         },
41662         getAttribute : function(name){
41663                 var attr = this.getAttributeNode(name);
41664                 return attr && attr.value || '';
41665         },
41666         getAttributeNode : function(name){
41667                 return this.attributes.getNamedItem(name);
41668         },
41669         setAttribute : function(name, value){
41670                 var attr = this.ownerDocument.createAttribute(name);
41671                 attr.value = attr.nodeValue = "" + value;
41672                 this.setAttributeNode(attr);
41673         },
41674         removeAttribute : function(name){
41675                 var attr = this.getAttributeNode(name);
41676                 attr && this.removeAttributeNode(attr);
41677         },
41678         
41679         //four real opeartion method
41680         appendChild:function(newChild){
41681                 if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
41682                         return this.insertBefore(newChild,null);
41683                 }else{
41684                         return _appendSingleChild(this,newChild);
41685                 }
41686         },
41687         setAttributeNode : function(newAttr){
41688                 return this.attributes.setNamedItem(newAttr);
41689         },
41690         setAttributeNodeNS : function(newAttr){
41691                 return this.attributes.setNamedItemNS(newAttr);
41692         },
41693         removeAttributeNode : function(oldAttr){
41694                 return this.attributes.removeNamedItem(oldAttr.nodeName);
41695         },
41696         //get real attribute name,and remove it by removeAttributeNode
41697         removeAttributeNS : function(namespaceURI, localName){
41698                 var old = this.getAttributeNodeNS(namespaceURI, localName);
41699                 old && this.removeAttributeNode(old);
41700         },
41701         
41702         hasAttributeNS : function(namespaceURI, localName){
41703                 return this.getAttributeNodeNS(namespaceURI, localName)!=null;
41704         },
41705         getAttributeNS : function(namespaceURI, localName){
41706                 var attr = this.getAttributeNodeNS(namespaceURI, localName);
41707                 return attr && attr.value || '';
41708         },
41709         setAttributeNS : function(namespaceURI, qualifiedName, value){
41710                 var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
41711                 attr.value = attr.nodeValue = "" + value;
41712                 this.setAttributeNode(attr);
41713         },
41714         getAttributeNodeNS : function(namespaceURI, localName){
41715                 return this.attributes.getNamedItemNS(namespaceURI, localName);
41716         },
41717         
41718         getElementsByTagName : function(tagName){
41719                 return new LiveNodeList(this,function(base){
41720                         var ls = [];
41721                         _visitNode(base,function(node){
41722                                 if(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){
41723                                         ls.push(node);
41724                                 }
41725                         });
41726                         return ls;
41727                 });
41728         },
41729         getElementsByTagNameNS : function(namespaceURI, localName){
41730                 return new LiveNodeList(this,function(base){
41731                         var ls = [];
41732                         _visitNode(base,function(node){
41733                                 if(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){
41734                                         ls.push(node);
41735                                 }
41736                         });
41737                         return ls;
41738                 });
41739         }
41740 };
41741 Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
41742 Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
41743
41744
41745 _extends(Element,Node);
41746 function Attr() {
41747 }
41748 Attr.prototype.nodeType = ATTRIBUTE_NODE;
41749 _extends(Attr,Node);
41750
41751
41752 function CharacterData() {
41753 }
41754 CharacterData.prototype = {
41755         data : '',
41756         substringData : function(offset, count) {
41757                 return this.data.substring(offset, offset+count);
41758         },
41759         appendData: function(text) {
41760                 text = this.data+text;
41761                 this.nodeValue = this.data = text;
41762                 this.length = text.length;
41763         },
41764         insertData: function(offset,text) {
41765                 this.replaceData(offset,0,text);
41766         
41767         },
41768         appendChild:function(newChild){
41769                 //if(!(newChild instanceof CharacterData)){
41770                         throw new Error(ExceptionMessage[3])
41771                 //}
41772                 return Node.prototype.appendChild.apply(this,arguments)
41773         },
41774         deleteData: function(offset, count) {
41775                 this.replaceData(offset,count,"");
41776         },
41777         replaceData: function(offset, count, text) {
41778                 var start = this.data.substring(0,offset);
41779                 var end = this.data.substring(offset+count);
41780                 text = start + text + end;
41781                 this.nodeValue = this.data = text;
41782                 this.length = text.length;
41783         }
41784 };
41785 _extends(CharacterData,Node);
41786 function Text() {
41787 }
41788 Text.prototype = {
41789         nodeName : "#text",
41790         nodeType : TEXT_NODE,
41791         splitText : function(offset) {
41792                 var text = this.data;
41793                 var newText = text.substring(offset);
41794                 text = text.substring(0, offset);
41795                 this.data = this.nodeValue = text;
41796                 this.length = text.length;
41797                 var newNode = this.ownerDocument.createTextNode(newText);
41798                 if(this.parentNode){
41799                         this.parentNode.insertBefore(newNode, this.nextSibling);
41800                 }
41801                 return newNode;
41802         }
41803 };
41804 _extends(Text,CharacterData);
41805 function Comment() {
41806 }
41807 Comment.prototype = {
41808         nodeName : "#comment",
41809         nodeType : COMMENT_NODE
41810 };
41811 _extends(Comment,CharacterData);
41812
41813 function CDATASection() {
41814 }
41815 CDATASection.prototype = {
41816         nodeName : "#cdata-section",
41817         nodeType : CDATA_SECTION_NODE
41818 };
41819 _extends(CDATASection,CharacterData);
41820
41821
41822 function DocumentType() {
41823 }
41824 DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
41825 _extends(DocumentType,Node);
41826
41827 function Notation() {
41828 }
41829 Notation.prototype.nodeType = NOTATION_NODE;
41830 _extends(Notation,Node);
41831
41832 function Entity() {
41833 }
41834 Entity.prototype.nodeType = ENTITY_NODE;
41835 _extends(Entity,Node);
41836
41837 function EntityReference() {
41838 }
41839 EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
41840 _extends(EntityReference,Node);
41841
41842 function DocumentFragment() {
41843 }
41844 DocumentFragment.prototype.nodeName =   "#document-fragment";
41845 DocumentFragment.prototype.nodeType =   DOCUMENT_FRAGMENT_NODE;
41846 _extends(DocumentFragment,Node);
41847
41848
41849 function ProcessingInstruction() {
41850 }
41851 ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
41852 _extends(ProcessingInstruction,Node);
41853 function XMLSerializer(){}
41854 XMLSerializer.prototype.serializeToString = function(node,attributeSorter){
41855         return node.toString(attributeSorter);
41856 };
41857 Node.prototype.toString =function(attributeSorter){
41858         var buf = [];
41859         serializeToString(this,buf,attributeSorter);
41860         return buf.join('');
41861 };
41862 function serializeToString(node,buf,attributeSorter,isHTML){
41863         switch(node.nodeType){
41864         case ELEMENT_NODE:
41865                 var attrs = node.attributes;
41866                 var len = attrs.length;
41867                 var child = node.firstChild;
41868                 var nodeName = node.tagName;
41869                 isHTML =  (htmlns === node.namespaceURI) ||isHTML; 
41870                 buf.push('<',nodeName);
41871                 if(attributeSorter){
41872                         buf.sort.apply(attrs, attributeSorter);
41873                 }
41874                 for(var i=0;i<len;i++){
41875                         serializeToString(attrs.item(i),buf,attributeSorter,isHTML);
41876                 }
41877                 if(child || isHTML && !/^(?:meta|link|img|br|hr|input|button)$/i.test(nodeName)){
41878                         buf.push('>');
41879                         //if is cdata child node
41880                         if(isHTML && /^script$/i.test(nodeName)){
41881                                 if(child){
41882                                         buf.push(child.data);
41883                                 }
41884                         }else{
41885                                 while(child){
41886                                         serializeToString(child,buf,attributeSorter,isHTML);
41887                                         child = child.nextSibling;
41888                                 }
41889                         }
41890                         buf.push('</',nodeName,'>');
41891                 }else{
41892                         buf.push('/>');
41893                 }
41894                 return;
41895         case DOCUMENT_NODE:
41896         case DOCUMENT_FRAGMENT_NODE:
41897                 var child = node.firstChild;
41898                 while(child){
41899                         serializeToString(child,buf,attributeSorter,isHTML);
41900                         child = child.nextSibling;
41901                 }
41902                 return;
41903         case ATTRIBUTE_NODE:
41904                 return buf.push(' ',node.name,'="',node.value.replace(/[<&"]/g,_xmlEncoder),'"');
41905         case TEXT_NODE:
41906                 return buf.push(node.data.replace(/[<&]/g,_xmlEncoder));
41907         case CDATA_SECTION_NODE:
41908                 return buf.push( '<![CDATA[',node.data,']]>');
41909         case COMMENT_NODE:
41910                 return buf.push( "<!--",node.data,"-->");
41911         case DOCUMENT_TYPE_NODE:
41912                 var pubid = node.publicId;
41913                 var sysid = node.systemId;
41914                 buf.push('<!DOCTYPE ',node.name);
41915                 if(pubid){
41916                         buf.push(' PUBLIC "',pubid);
41917                         if (sysid && sysid!='.') {
41918                                 buf.push( '" "',sysid);
41919                         }
41920                         buf.push('">');
41921                 }else if(sysid && sysid!='.'){
41922                         buf.push(' SYSTEM "',sysid,'">');
41923                 }else{
41924                         var sub = node.internalSubset;
41925                         if(sub){
41926                                 buf.push(" [",sub,"]");
41927                         }
41928                         buf.push(">");
41929                 }
41930                 return;
41931         case PROCESSING_INSTRUCTION_NODE:
41932                 return buf.push( "<?",node.target," ",node.data,"?>");
41933         case ENTITY_REFERENCE_NODE:
41934                 return buf.push( '&',node.nodeName,';');
41935         //case ENTITY_NODE:
41936         //case NOTATION_NODE:
41937         default:
41938                 buf.push('??',node.nodeName);
41939         }
41940 }
41941 function importNode(doc,node,deep){
41942         var node2;
41943         switch (node.nodeType) {
41944         case ELEMENT_NODE:
41945                 node2 = node.cloneNode(false);
41946                 node2.ownerDocument = doc;
41947                 //var attrs = node2.attributes;
41948                 //var len = attrs.length;
41949                 //for(var i=0;i<len;i++){
41950                         //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
41951                 //}
41952         case DOCUMENT_FRAGMENT_NODE:
41953                 break;
41954         case ATTRIBUTE_NODE:
41955                 deep = true;
41956                 break;
41957         //case ENTITY_REFERENCE_NODE:
41958         //case PROCESSING_INSTRUCTION_NODE:
41959         ////case TEXT_NODE:
41960         //case CDATA_SECTION_NODE:
41961         //case COMMENT_NODE:
41962         //      deep = false;
41963         //      break;
41964         //case DOCUMENT_NODE:
41965         //case DOCUMENT_TYPE_NODE:
41966         //cannot be imported.
41967         //case ENTITY_NODE:
41968         //case NOTATION_NODE:
41969         //can not hit in level3
41970         //default:throw e;
41971         }
41972         if(!node2){
41973                 node2 = node.cloneNode(false);//false
41974         }
41975         node2.ownerDocument = doc;
41976         node2.parentNode = null;
41977         if(deep){
41978                 var child = node.firstChild;
41979                 while(child){
41980                         node2.appendChild(importNode(doc,child,deep));
41981                         child = child.nextSibling;
41982                 }
41983         }
41984         return node2;
41985 }
41986 //
41987 //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
41988 //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
41989 function cloneNode(doc,node,deep){
41990         var node2 = new node.constructor();
41991         for(var n in node){
41992                 var v = node[n];
41993                 if(typeof v != 'object' ){
41994                         if(v != node2[n]){
41995                                 node2[n] = v;
41996                         }
41997                 }
41998         }
41999         if(node.childNodes){
42000                 node2.childNodes = new NodeList();
42001         }
42002         node2.ownerDocument = doc;
42003         switch (node2.nodeType) {
42004         case ELEMENT_NODE:
42005                 var attrs       = node.attributes;
42006                 var attrs2      = node2.attributes = new NamedNodeMap();
42007                 var len = attrs.length;
42008                 attrs2._ownerElement = node2;
42009                 for(var i=0;i<len;i++){
42010                         node2.setAttributeNode(cloneNode(doc,attrs.item(i),true));
42011                 }
42012                 break;;
42013         case ATTRIBUTE_NODE:
42014                 deep = true;
42015         }
42016         if(deep){
42017                 var child = node.firstChild;
42018                 while(child){
42019                         node2.appendChild(cloneNode(doc,child,deep));
42020                         child = child.nextSibling;
42021                 }
42022         }
42023         return node2;
42024 }
42025
42026 function __set__(object,key,value){
42027         object[key] = value;
42028 }
42029 //do dynamic
42030 try{
42031         if(Object.defineProperty){
42032                 Object.defineProperty(LiveNodeList.prototype,'length',{
42033                         get:function(){
42034                                 _updateLiveList(this);
42035                                 return this.$$length;
42036                         }
42037                 });
42038                 Object.defineProperty(Node.prototype,'textContent',{
42039                         get:function(){
42040                                 return getTextContent(this);
42041                         },
42042                         set:function(data){
42043                                 switch(this.nodeType){
42044                                 case 1:
42045                                 case 11:
42046                                         while(this.firstChild){
42047                                                 this.removeChild(this.firstChild);
42048                                         }
42049                                         if(data || String(data)){
42050                                                 this.appendChild(this.ownerDocument.createTextNode(data));
42051                                         }
42052                                         break;
42053                                 default:
42054                                         //TODO:
42055                                         this.data = data;
42056                                         this.value = value;
42057                                         this.nodeValue = data;
42058                                 }
42059                         }
42060                 });
42061                 
42062                 function getTextContent(node){
42063                         switch(node.nodeType){
42064                         case 1:
42065                         case 11:
42066                                 var buf = [];
42067                                 node = node.firstChild;
42068                                 while(node){
42069                                         if(node.nodeType!==7 && node.nodeType !==8){
42070                                                 buf.push(getTextContent(node));
42071                                         }
42072                                         node = node.nextSibling;
42073                                 }
42074                                 return buf.join('');
42075                         default:
42076                                 return node.nodeValue;
42077                         }
42078                 }
42079                 __set__ = function(object,key,value){
42080                         //console.log(value)
42081                         object['$$'+key] = value;
42082                 };
42083         }
42084 }catch(e){//ie8
42085 }
42086
42087 if(typeof commonjsRequire == 'function'){
42088         exports.DOMImplementation = DOMImplementation;
42089         exports.XMLSerializer = XMLSerializer;
42090 }
42091 });
42092
42093 var domParser = createCommonjsModule(function (module, exports) {
42094 function DOMParser(options){
42095         this.options = options ||{locator:{}};
42096         
42097 }
42098 DOMParser.prototype.parseFromString = function(source,mimeType){        
42099         var options = this.options;
42100         var sax$$1 =  new XMLReader();
42101         var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
42102         var errorHandler = options.errorHandler;
42103         var locator = options.locator;
42104         var defaultNSMap = options.xmlns||{};
42105         var entityMap = {'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"};
42106         if(locator){
42107                 domBuilder.setDocumentLocator(locator);
42108         }
42109         
42110         sax$$1.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);
42111         sax$$1.domBuilder = options.domBuilder || domBuilder;
42112         if(/\/x?html?$/.test(mimeType)){
42113                 entityMap.nbsp = '\xa0';
42114                 entityMap.copy = '\xa9';
42115                 defaultNSMap['']= 'http://www.w3.org/1999/xhtml';
42116         }
42117         defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
42118         if(source){
42119                 sax$$1.parse(source,defaultNSMap,entityMap);
42120         }else{
42121                 sax$$1.errorHandler.error("invalid document source");
42122         }
42123         return domBuilder.document;
42124 };
42125 function buildErrorHandler(errorImpl,domBuilder,locator){
42126         if(!errorImpl){
42127                 if(domBuilder instanceof DOMHandler){
42128                         return domBuilder;
42129                 }
42130                 errorImpl = domBuilder ;
42131         }
42132         var errorHandler = {};
42133         var isCallback = errorImpl instanceof Function;
42134         locator = locator||{};
42135         function build(key){
42136                 var fn = errorImpl[key];
42137                 if(!fn && isCallback){
42138                         fn = errorImpl.length == 2?function(msg){errorImpl(key,msg);}:errorImpl;
42139                 }
42140                 errorHandler[key] = fn && function(msg){
42141                         fn('[xmldom '+key+']\t'+msg+_locator(locator));
42142                 }||function(){};
42143         }
42144         build('warning');
42145         build('error');
42146         build('fatalError');
42147         return errorHandler;
42148 }
42149
42150 //console.log('#\n\n\n\n\n\n\n####')
42151 /**
42152  * +ContentHandler+ErrorHandler
42153  * +LexicalHandler+EntityResolver2
42154  * -DeclHandler-DTDHandler 
42155  * 
42156  * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
42157  * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
42158  * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
42159  */
42160 function DOMHandler() {
42161     this.cdata = false;
42162 }
42163 function position(locator,node){
42164         node.lineNumber = locator.lineNumber;
42165         node.columnNumber = locator.columnNumber;
42166 }
42167 /**
42168  * @see org.xml.sax.ContentHandler#startDocument
42169  * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
42170  */ 
42171 DOMHandler.prototype = {
42172         startDocument : function() {
42173         this.document = new DOMImplementation().createDocument(null, null, null);
42174         if (this.locator) {
42175                 this.document.documentURI = this.locator.systemId;
42176         }
42177         },
42178         startElement:function(namespaceURI, localName, qName, attrs) {
42179                 var doc = this.document;
42180             var el = doc.createElementNS(namespaceURI, qName||localName);
42181             var len = attrs.length;
42182             appendElement(this, el);
42183             this.currentElement = el;
42184             
42185                 this.locator && position(this.locator,el);
42186             for (var i = 0 ; i < len; i++) {
42187                 var namespaceURI = attrs.getURI(i);
42188                 var value = attrs.getValue(i);
42189                 var qName = attrs.getQName(i);
42190                         var attr = doc.createAttributeNS(namespaceURI, qName);
42191                         if( attr.getOffset){
42192                                 position(attr.getOffset(1),attr);
42193                         }
42194                         attr.value = attr.nodeValue = value;
42195                         el.setAttributeNode(attr);
42196             }
42197         },
42198         endElement:function(namespaceURI, localName, qName) {
42199                 var current = this.currentElement;
42200             var tagName = current.tagName;
42201             this.currentElement = current.parentNode;
42202         },
42203         startPrefixMapping:function(prefix, uri) {
42204         },
42205         endPrefixMapping:function(prefix) {
42206         },
42207         processingInstruction:function(target, data) {
42208             var ins = this.document.createProcessingInstruction(target, data);
42209             this.locator && position(this.locator,ins);
42210             appendElement(this, ins);
42211         },
42212         ignorableWhitespace:function(ch, start, length) {
42213         },
42214         characters:function(chars, start, length) {
42215                 chars = _toString.apply(this,arguments);
42216                 //console.log(chars)
42217                 if(this.currentElement && chars){
42218                         if (this.cdata) {
42219                                 var charNode = this.document.createCDATASection(chars);
42220                                 this.currentElement.appendChild(charNode);
42221                         } else {
42222                                 var charNode = this.document.createTextNode(chars);
42223                                 this.currentElement.appendChild(charNode);
42224                         }
42225                         this.locator && position(this.locator,charNode);
42226                 }
42227         },
42228         skippedEntity:function(name) {
42229         },
42230         endDocument:function() {
42231                 this.document.normalize();
42232         },
42233         setDocumentLocator:function (locator) {
42234             if(this.locator = locator){// && !('lineNumber' in locator)){
42235                 locator.lineNumber = 0;
42236             }
42237         },
42238         //LexicalHandler
42239         comment:function(chars, start, length) {
42240                 chars = _toString.apply(this,arguments);
42241             var comm = this.document.createComment(chars);
42242             this.locator && position(this.locator,comm);
42243             appendElement(this, comm);
42244         },
42245         
42246         startCDATA:function() {
42247             //used in characters() methods
42248             this.cdata = true;
42249         },
42250         endCDATA:function() {
42251             this.cdata = false;
42252         },
42253         
42254         startDTD:function(name, publicId, systemId) {
42255                 var impl = this.document.implementation;
42256             if (impl && impl.createDocumentType) {
42257                 var dt = impl.createDocumentType(name, publicId, systemId);
42258                 this.locator && position(this.locator,dt);
42259                 appendElement(this, dt);
42260             }
42261         },
42262         /**
42263          * @see org.xml.sax.ErrorHandler
42264          * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
42265          */
42266         warning:function(error) {
42267                 console.warn('[xmldom warning]\t'+error,_locator(this.locator));
42268         },
42269         error:function(error) {
42270                 console.error('[xmldom error]\t'+error,_locator(this.locator));
42271         },
42272         fatalError:function(error) {
42273                 console.error('[xmldom fatalError]\t'+error,_locator(this.locator));
42274             throw error;
42275         }
42276 };
42277 function _locator(l){
42278         if(l){
42279                 return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'
42280         }
42281 }
42282 function _toString(chars,start,length){
42283         if(typeof chars == 'string'){
42284                 return chars.substr(start,length)
42285         }else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
42286                 if(chars.length >= start+length || start){
42287                         return new java.lang.String(chars,start,length)+'';
42288                 }
42289                 return chars;
42290         }
42291 }
42292
42293 /*
42294  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
42295  * used method of org.xml.sax.ext.LexicalHandler:
42296  *  #comment(chars, start, length)
42297  *  #startCDATA()
42298  *  #endCDATA()
42299  *  #startDTD(name, publicId, systemId)
42300  *
42301  *
42302  * IGNORED method of org.xml.sax.ext.LexicalHandler:
42303  *  #endDTD()
42304  *  #startEntity(name)
42305  *  #endEntity(name)
42306  *
42307  *
42308  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
42309  * IGNORED method of org.xml.sax.ext.DeclHandler
42310  *      #attributeDecl(eName, aName, type, mode, value)
42311  *  #elementDecl(name, model)
42312  *  #externalEntityDecl(name, publicId, systemId)
42313  *  #internalEntityDecl(name, value)
42314  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
42315  * IGNORED method of org.xml.sax.EntityResolver2
42316  *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
42317  *  #resolveEntity(publicId, systemId)
42318  *  #getExternalSubset(name, baseURI)
42319  * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
42320  * IGNORED method of org.xml.sax.DTDHandler
42321  *  #notationDecl(name, publicId, systemId) {};
42322  *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
42323  */
42324 "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){
42325         DOMHandler.prototype[key] = function(){return null};
42326 });
42327
42328 /* 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 */
42329 function appendElement (hander,node) {
42330     if (!hander.currentElement) {
42331         hander.document.appendChild(node);
42332     } else {
42333         hander.currentElement.appendChild(node);
42334     }
42335 }//appendChild and setAttributeNS are preformance key
42336
42337 if(typeof commonjsRequire == 'function'){
42338         var XMLReader = sax.XMLReader;
42339         var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
42340         exports.XMLSerializer = dom.XMLSerializer ;
42341         exports.DOMParser = DOMParser;
42342 }
42343 });
42344
42345 var togeojson = createCommonjsModule(function (module, exports) {
42346 var toGeoJSON = (function() {
42347     'use strict';
42348
42349     var removeSpace = /\s*/g,
42350         trimSpace = /^\s*|\s*$/g,
42351         splitSpace = /\s+/;
42352     // generate a short, numeric hash of a string
42353     function okhash(x) {
42354         if (!x || !x.length) return 0;
42355         for (var i = 0, h = 0; i < x.length; i++) {
42356             h = ((h << 5) - h) + x.charCodeAt(i) | 0;
42357         } return h;
42358     }
42359     // all Y children of X
42360     function get(x, y) { return x.getElementsByTagName(y); }
42361     function attr(x, y) { return x.getAttribute(y); }
42362     function attrf(x, y) { return parseFloat(attr(x, y)); }
42363     // one Y child of X, if any, otherwise null
42364     function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
42365     // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
42366     function norm(el) { if (el.normalize) { el.normalize(); } return el; }
42367     // cast array x into numbers
42368     function numarray(x) {
42369         for (var j = 0, o = []; j < x.length; j++) { o[j] = parseFloat(x[j]); }
42370         return o;
42371     }
42372     // get the content of a text node, if any
42373     function nodeVal(x) {
42374         if (x) { norm(x); }
42375         return (x && x.textContent) || '';
42376     }
42377     // get the contents of multiple text nodes, if present
42378     function getMulti(x, ys) {
42379         var o = {}, n, k;
42380         for (k = 0; k < ys.length; k++) {
42381             n = get1(x, ys[k]);
42382             if (n) o[ys[k]] = nodeVal(n);
42383         }
42384         return o;
42385     }
42386     // add properties of Y to X, overwriting if present in both
42387     function extend(x, y) { for (var k in y) x[k] = y[k]; }
42388     // get one coordinate from a coordinate array, if any
42389     function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
42390     // get all coordinates from a coordinate array as [[],[]]
42391     function coord(v) {
42392         var coords = v.replace(trimSpace, '').split(splitSpace),
42393             o = [];
42394         for (var i = 0; i < coords.length; i++) {
42395             o.push(coord1(coords[i]));
42396         }
42397         return o;
42398     }
42399     function coordPair(x) {
42400         var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
42401             ele = get1(x, 'ele'),
42402             // handle namespaced attribute in browser
42403             heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
42404             time = get1(x, 'time'),
42405             e;
42406         if (ele) {
42407             e = parseFloat(nodeVal(ele));
42408             if (!isNaN(e)) {
42409                 ll.push(e);
42410             }
42411         }
42412         return {
42413             coordinates: ll,
42414             time: time ? nodeVal(time) : null,
42415             heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
42416         };
42417     }
42418
42419     // create a new feature collection parent object
42420     function fc() {
42421         return {
42422             type: 'FeatureCollection',
42423             features: []
42424         };
42425     }
42426
42427     var serializer;
42428     if (typeof XMLSerializer !== 'undefined') {
42429         /* istanbul ignore next */
42430         serializer = new XMLSerializer();
42431     // only require xmldom in a node environment
42432     } else if ('object' === 'object' && typeof process === 'object' && !process.browser) {
42433         serializer = new (domParser.XMLSerializer)();
42434     }
42435     function xml2str(str) {
42436         // IE9 will create a new XMLSerializer but it'll crash immediately.
42437         // This line is ignored because we don't run coverage tests in IE9
42438         /* istanbul ignore next */
42439         if (str.xml !== undefined) return str.xml;
42440         return serializer.serializeToString(str);
42441     }
42442
42443     var t = {
42444         kml: function(doc) {
42445
42446             var gj = fc(),
42447                 // styleindex keeps track of hashed styles in order to match features
42448                 styleIndex = {}, styleByHash = {},
42449                 // stylemapindex keeps track of style maps to expose in properties
42450                 styleMapIndex = {},
42451                 // atomic geospatial types supported by KML - MultiGeometry is
42452                 // handled separately
42453                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
42454                 // all root placemarks in the file
42455                 placemarks = get(doc, 'Placemark'),
42456                 styles = get(doc, 'Style'),
42457                 styleMaps = get(doc, 'StyleMap');
42458
42459             for (var k = 0; k < styles.length; k++) {
42460                 var hash = okhash(xml2str(styles[k])).toString(16);
42461                 styleIndex['#' + attr(styles[k], 'id')] = hash;
42462                 styleByHash[hash] = styles[k];
42463             }
42464             for (var l = 0; l < styleMaps.length; l++) {
42465                 styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
42466                 var pairs = get(styleMaps[l], 'Pair');
42467                 var pairsMap = {};
42468                 for (var m = 0; m < pairs.length; m++) {
42469                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
42470                 }
42471                 styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
42472
42473             }
42474             for (var j = 0; j < placemarks.length; j++) {
42475                 gj.features = gj.features.concat(getPlacemark(placemarks[j]));
42476             }
42477             function kmlColor(v) {
42478                 var color, opacity;
42479                 v = v || '';
42480                 if (v.substr(0, 1) === '#') { v = v.substr(1); }
42481                 if (v.length === 6 || v.length === 3) { color = v; }
42482                 if (v.length === 8) {
42483                     opacity = parseInt(v.substr(0, 2), 16) / 255;
42484                     color = '#' + v.substr(6, 2) +
42485                         v.substr(4, 2) +
42486                         v.substr(2, 2);
42487                 }
42488                 return [color, isNaN(opacity) ? undefined : opacity];
42489             }
42490             function gxCoord(v) { return numarray(v.split(' ')); }
42491             function gxCoords(root) {
42492                 var elems = get(root, 'coord', 'gx'), coords = [], times = [];
42493                 if (elems.length === 0) elems = get(root, 'gx:coord');
42494                 for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
42495                 var timeElems = get(root, 'when');
42496                 for (var j = 0; j < timeElems.length; j++) times.push(nodeVal(timeElems[j]));
42497                 return {
42498                     coords: coords,
42499                     times: times
42500                 };
42501             }
42502             function getGeometry(root) {
42503                 var geomNode, geomNodes, i, j, k, geoms = [], coordTimes = [];
42504                 if (get1(root, 'MultiGeometry')) { return getGeometry(get1(root, 'MultiGeometry')); }
42505                 if (get1(root, 'MultiTrack')) { return getGeometry(get1(root, 'MultiTrack')); }
42506                 if (get1(root, 'gx:MultiTrack')) { return getGeometry(get1(root, 'gx:MultiTrack')); }
42507                 for (i = 0; i < geotypes.length; i++) {
42508                     geomNodes = get(root, geotypes[i]);
42509                     if (geomNodes) {
42510                         for (j = 0; j < geomNodes.length; j++) {
42511                             geomNode = geomNodes[j];
42512                             if (geotypes[i] === 'Point') {
42513                                 geoms.push({
42514                                     type: 'Point',
42515                                     coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
42516                                 });
42517                             } else if (geotypes[i] === 'LineString') {
42518                                 geoms.push({
42519                                     type: 'LineString',
42520                                     coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
42521                                 });
42522                             } else if (geotypes[i] === 'Polygon') {
42523                                 var rings = get(geomNode, 'LinearRing'),
42524                                     coords = [];
42525                                 for (k = 0; k < rings.length; k++) {
42526                                     coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
42527                                 }
42528                                 geoms.push({
42529                                     type: 'Polygon',
42530                                     coordinates: coords
42531                                 });
42532                             } else if (geotypes[i] === 'Track' ||
42533                                 geotypes[i] === 'gx:Track') {
42534                                 var track = gxCoords(geomNode);
42535                                 geoms.push({
42536                                     type: 'LineString',
42537                                     coordinates: track.coords
42538                                 });
42539                                 if (track.times.length) coordTimes.push(track.times);
42540                             }
42541                         }
42542                     }
42543                 }
42544                 return {
42545                     geoms: geoms,
42546                     coordTimes: coordTimes
42547                 };
42548             }
42549             function getPlacemark(root) {
42550                 var geomsAndTimes = getGeometry(root), i, properties = {},
42551                     name = nodeVal(get1(root, 'name')),
42552                     address = nodeVal(get1(root, 'address')),
42553                     styleUrl = nodeVal(get1(root, 'styleUrl')),
42554                     description = nodeVal(get1(root, 'description')),
42555                     timeSpan = get1(root, 'TimeSpan'),
42556                     timeStamp = get1(root, 'TimeStamp'),
42557                     extendedData = get1(root, 'ExtendedData'),
42558                     lineStyle = get1(root, 'LineStyle'),
42559                     polyStyle = get1(root, 'PolyStyle'),
42560                     visibility = get1(root, 'visibility');
42561
42562                 if (!geomsAndTimes.geoms.length) return [];
42563                 if (name) properties.name = name;
42564                 if (address) properties.address = address;
42565                 if (styleUrl) {
42566                     if (styleUrl[0] !== '#') {
42567                         styleUrl = '#' + styleUrl;
42568                     }
42569
42570                     properties.styleUrl = styleUrl;
42571                     if (styleIndex[styleUrl]) {
42572                         properties.styleHash = styleIndex[styleUrl];
42573                     }
42574                     if (styleMapIndex[styleUrl]) {
42575                         properties.styleMapHash = styleMapIndex[styleUrl];
42576                         properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
42577                     }
42578                     // Try to populate the lineStyle or polyStyle since we got the style hash
42579                     var style = styleByHash[properties.styleHash];
42580                     if (style) {
42581                         if (!lineStyle) lineStyle = get1(style, 'LineStyle');
42582                         if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
42583                     }
42584                 }
42585                 if (description) properties.description = description;
42586                 if (timeSpan) {
42587                     var begin = nodeVal(get1(timeSpan, 'begin'));
42588                     var end = nodeVal(get1(timeSpan, 'end'));
42589                     properties.timespan = { begin: begin, end: end };
42590                 }
42591                 if (timeStamp) {
42592                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
42593                 }
42594                 if (lineStyle) {
42595                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
42596                         color = linestyles[0],
42597                         opacity = linestyles[1],
42598                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
42599                     if (color) properties.stroke = color;
42600                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
42601                     if (!isNaN(width)) properties['stroke-width'] = width;
42602                 }
42603                 if (polyStyle) {
42604                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
42605                         pcolor = polystyles[0],
42606                         popacity = polystyles[1],
42607                         fill = nodeVal(get1(polyStyle, 'fill')),
42608                         outline = nodeVal(get1(polyStyle, 'outline'));
42609                     if (pcolor) properties.fill = pcolor;
42610                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
42611                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
42612                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
42613                 }
42614                 if (extendedData) {
42615                     var datas = get(extendedData, 'Data'),
42616                         simpleDatas = get(extendedData, 'SimpleData');
42617
42618                     for (i = 0; i < datas.length; i++) {
42619                         properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
42620                     }
42621                     for (i = 0; i < simpleDatas.length; i++) {
42622                         properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
42623                     }
42624                 }
42625                 if (visibility) {
42626                     properties.visibility = nodeVal(visibility);
42627                 }
42628                 if (geomsAndTimes.coordTimes.length) {
42629                     properties.coordTimes = (geomsAndTimes.coordTimes.length === 1) ?
42630                         geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
42631                 }
42632                 var feature = {
42633                     type: 'Feature',
42634                     geometry: (geomsAndTimes.geoms.length === 1) ? geomsAndTimes.geoms[0] : {
42635                         type: 'GeometryCollection',
42636                         geometries: geomsAndTimes.geoms
42637                     },
42638                     properties: properties
42639                 };
42640                 if (attr(root, 'id')) feature.id = attr(root, 'id');
42641                 return [feature];
42642             }
42643             return gj;
42644         },
42645         gpx: function(doc) {
42646             var i,
42647                 tracks = get(doc, 'trk'),
42648                 routes = get(doc, 'rte'),
42649                 waypoints = get(doc, 'wpt'),
42650                 // a feature collection
42651                 gj = fc(),
42652                 feature;
42653             for (i = 0; i < tracks.length; i++) {
42654                 feature = getTrack(tracks[i]);
42655                 if (feature) gj.features.push(feature);
42656             }
42657             for (i = 0; i < routes.length; i++) {
42658                 feature = getRoute(routes[i]);
42659                 if (feature) gj.features.push(feature);
42660             }
42661             for (i = 0; i < waypoints.length; i++) {
42662                 gj.features.push(getPoint(waypoints[i]));
42663             }
42664             function getPoints(node, pointname) {
42665                 var pts = get(node, pointname),
42666                     line = [],
42667                     times = [],
42668                     heartRates = [],
42669                     l = pts.length;
42670                 if (l < 2) return {};  // Invalid line in GeoJSON
42671                 for (var i = 0; i < l; i++) {
42672                     var c = coordPair(pts[i]);
42673                     line.push(c.coordinates);
42674                     if (c.time) times.push(c.time);
42675                     if (c.heartRate) heartRates.push(c.heartRate);
42676                 }
42677                 return {
42678                     line: line,
42679                     times: times,
42680                     heartRates: heartRates
42681                 };
42682             }
42683             function getTrack(node) {
42684                 var segments = get(node, 'trkseg'),
42685                     track = [],
42686                     times = [],
42687                     heartRates = [],
42688                     line;
42689                 for (var i = 0; i < segments.length; i++) {
42690                     line = getPoints(segments[i], 'trkpt');
42691                     if (line) {
42692                         if (line.line) track.push(line.line);
42693                         if (line.times && line.times.length) times.push(line.times);
42694                         if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
42695                     }
42696                 }
42697                 if (track.length === 0) return;
42698                 var properties = getProperties(node);
42699                 extend(properties, getLineStyle(get1(node, 'extensions')));
42700                 if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
42701                 if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
42702                 return {
42703                     type: 'Feature',
42704                     properties: properties,
42705                     geometry: {
42706                         type: track.length === 1 ? 'LineString' : 'MultiLineString',
42707                         coordinates: track.length === 1 ? track[0] : track
42708                     }
42709                 };
42710             }
42711             function getRoute(node) {
42712                 var line = getPoints(node, 'rtept');
42713                 if (!line.line) return;
42714                 var prop = getProperties(node);
42715                 extend(prop, getLineStyle(get1(node, 'extensions')));
42716                 var routeObj = {
42717                     type: 'Feature',
42718                     properties: prop,
42719                     geometry: {
42720                         type: 'LineString',
42721                         coordinates: line.line
42722                     }
42723                 };
42724                 return routeObj;
42725             }
42726             function getPoint(node) {
42727                 var prop = getProperties(node);
42728                 extend(prop, getMulti(node, ['sym']));
42729                 return {
42730                     type: 'Feature',
42731                     properties: prop,
42732                     geometry: {
42733                         type: 'Point',
42734                         coordinates: coordPair(node).coordinates
42735                     }
42736                 };
42737             }
42738             function getLineStyle(extensions) {
42739                 var style = {};
42740                 if (extensions) {
42741                     var lineStyle = get1(extensions, 'line');
42742                     if (lineStyle) {
42743                         var color = nodeVal(get1(lineStyle, 'color')),
42744                             opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
42745                             width = parseFloat(nodeVal(get1(lineStyle, 'width')));
42746                         if (color) style.stroke = color;
42747                         if (!isNaN(opacity)) style['stroke-opacity'] = opacity;
42748                         // GPX width is in mm, convert to px with 96 px per inch
42749                         if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
42750                     }
42751                 }
42752                 return style;
42753             }
42754             function getProperties(node) {
42755                 var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
42756                     links = get(node, 'link');
42757                 if (links.length) prop.links = [];
42758                 for (var i = 0, link; i < links.length; i++) {
42759                     link = { href: attr(links[i], 'href') };
42760                     extend(link, getMulti(links[i], ['text', 'type']));
42761                     prop.links.push(link);
42762                 }
42763                 return prop;
42764             }
42765             return gj;
42766         }
42767     };
42768     return t;
42769 })();
42770
42771 module.exports = toGeoJSON;
42772 });
42773
42774 function svgGpx(projection, context, dispatch$$1) {
42775     var showLabels = true,
42776         detected = utilDetect(),
42777         layer;
42778
42779
42780     function init() {
42781         if (svgGpx.initialized) return;  // run once
42782
42783         svgGpx.geojson = {};
42784         svgGpx.enabled = true;
42785
42786         function over() {
42787             event.stopPropagation();
42788             event.preventDefault();
42789             event.dataTransfer.dropEffect = 'copy';
42790         }
42791
42792         select('body')
42793             .attr('dropzone', 'copy')
42794             .on('drop.localgpx', function() {
42795                 event.stopPropagation();
42796                 event.preventDefault();
42797                 if (!detected.filedrop) return;
42798                 drawGpx.files(event.dataTransfer.files);
42799             })
42800             .on('dragenter.localgpx', over)
42801             .on('dragexit.localgpx', over)
42802             .on('dragover.localgpx', over);
42803
42804         svgGpx.initialized = true;
42805     }
42806
42807
42808     function drawGpx(selection$$1) {
42809         var geojson = svgGpx.geojson,
42810             enabled = svgGpx.enabled;
42811
42812         layer = selection$$1.selectAll('.layer-gpx')
42813             .data(enabled ? [0] : []);
42814
42815         layer.exit()
42816             .remove();
42817
42818         layer = layer.enter()
42819             .append('g')
42820             .attr('class', 'layer-gpx')
42821             .merge(layer);
42822
42823
42824         var paths = layer
42825             .selectAll('path')
42826             .data([geojson]);
42827
42828         paths.exit()
42829             .remove();
42830
42831         paths = paths.enter()
42832             .append('path')
42833             .attr('class', 'gpx')
42834             .merge(paths);
42835
42836
42837         var path$$1 = index$4(projection);
42838
42839         paths
42840             .attr('d', path$$1);
42841
42842
42843         var labels = layer.selectAll('text')
42844             .data(showLabels && geojson.features ? geojson.features : []);
42845
42846         labels.exit()
42847             .remove();
42848
42849         labels = labels.enter()
42850             .append('text')
42851             .attr('class', 'gpx')
42852             .merge(labels);
42853
42854         labels
42855             .text(function(d) {
42856                 return d.properties.desc || d.properties.name;
42857             })
42858             .attr('x', function(d) {
42859                 var centroid = path$$1.centroid(d);
42860                 return centroid[0] + 7;
42861             })
42862             .attr('y', function(d) {
42863                 var centroid = path$$1.centroid(d);
42864                 return centroid[1];
42865             });
42866
42867     }
42868
42869
42870     function toDom(x) {
42871         return (new DOMParser()).parseFromString(x, 'text/xml');
42872     }
42873
42874
42875     function getExtension(fileName) {
42876         if (lodash.isUndefined(fileName)) {
42877             return '';
42878         }
42879
42880         var lastDotIndex = fileName.lastIndexOf('.');
42881         if (lastDotIndex < 0) {
42882             return '';
42883         }
42884
42885         return fileName.substr(lastDotIndex);
42886     }
42887
42888
42889     function parseSaveAndZoom(extension, data) {
42890         switch (extension) {
42891             default:
42892                 drawGpx.geojson(togeojson.gpx(toDom(data))).fitZoom();
42893                 break;
42894             case '.kml':
42895                 drawGpx.geojson(togeojson.kml(toDom(data))).fitZoom();
42896                 break;
42897             case '.geojson':
42898             case '.json':
42899                 drawGpx.geojson(JSON.parse(data)).fitZoom();
42900                 break;
42901         }
42902     }
42903
42904
42905     drawGpx.showLabels = function(_) {
42906         if (!arguments.length) return showLabels;
42907         showLabels = _;
42908         return this;
42909     };
42910
42911
42912     drawGpx.enabled = function(_) {
42913         if (!arguments.length) return svgGpx.enabled;
42914         svgGpx.enabled = _;
42915         dispatch$$1.call('change');
42916         return this;
42917     };
42918
42919
42920     drawGpx.hasGpx = function() {
42921         var geojson = svgGpx.geojson;
42922         return (!(lodash.isEmpty(geojson) || lodash.isEmpty(geojson.features)));
42923     };
42924
42925
42926     drawGpx.geojson = function(gj) {
42927         if (!arguments.length) return svgGpx.geojson;
42928         if (lodash.isEmpty(gj) || lodash.isEmpty(gj.features)) return this;
42929         svgGpx.geojson = gj;
42930         dispatch$$1.call('change');
42931         return this;
42932     };
42933
42934
42935     drawGpx.url = function(url) {
42936         text(url, function(err, data) {
42937             if (!err) {
42938                 var extension = getExtension(url);
42939                 parseSaveAndZoom(extension, data);
42940             }
42941         });
42942         return this;
42943     };
42944
42945
42946     drawGpx.files = function(fileList) {
42947         if (!fileList.length) return this;
42948         var f = fileList[0],
42949             reader = new FileReader();
42950
42951         reader.onload = (function(file) {
42952             var extension = getExtension(file.name);
42953
42954             return function (e) {
42955                 parseSaveAndZoom(extension, e.target.result);
42956             };
42957         })(f);
42958
42959         reader.readAsText(f);
42960         return this;
42961     };
42962
42963
42964     drawGpx.fitZoom = function() {
42965         if (!this.hasGpx()) return this;
42966         var geojson = svgGpx.geojson;
42967
42968         var map$$1 = context.map(),
42969             viewport = map$$1.trimmedExtent().polygon(),
42970             coords = lodash.reduce(geojson.features, function(coords, feature) {
42971                 var c = feature.geometry.coordinates;
42972
42973                 /* eslint-disable no-fallthrough */
42974                 switch (feature.geometry.type) {
42975                     case 'Point':
42976                         c = [c];
42977                     case 'MultiPoint':
42978                     case 'LineString':
42979                         break;
42980
42981                     case 'MultiPolygon':
42982                         c = lodash.flatten(c);
42983                     case 'Polygon':
42984                     case 'MultiLineString':
42985                         c = lodash.flatten(c);
42986                         break;
42987                 }
42988                 /* eslint-enable no-fallthrough */
42989
42990                 return lodash.union(coords, c);
42991             }, []);
42992
42993         if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
42994             var extent$$1 = geoExtent$$1(bounds({ type: 'LineString', coordinates: coords }));
42995             map$$1.centerZoom(extent$$1.center(), map$$1.trimmedExtentZoom(extent$$1));
42996         }
42997
42998         return this;
42999     };
43000
43001
43002     init();
43003     return drawGpx;
43004 }
43005
43006 function svgIcon(name, svgklass, useklass) {
43007     return function drawIcon(selection) {
43008         selection.selectAll('svg')
43009             .data([0])
43010             .enter()
43011             .append('svg')
43012             .attr('class', 'icon ' + (svgklass || ''))
43013             .append('use')
43014             .attr('xlink:href', name)
43015             .attr('class', useklass);
43016     };
43017 }
43018
43019 function svgLabels(projection, context) {
43020     var path$$1 = index$4(projection),
43021         detected = utilDetect(),
43022         baselineHack = (detected.ie || detected.browser.toLowerCase() === 'edge'),
43023         rdrawn = index$9(),
43024         rskipped = index$9(),
43025         textWidthCache = {},
43026         entitybboxes = {};
43027
43028     // Listed from highest to lowest priority
43029     var labelStack = [
43030         ['line', 'aeroway', '*', 12],
43031         ['line', 'highway', 'motorway', 12],
43032         ['line', 'highway', 'trunk', 12],
43033         ['line', 'highway', 'primary', 12],
43034         ['line', 'highway', 'secondary', 12],
43035         ['line', 'highway', 'tertiary', 12],
43036         ['line', 'highway', '*', 12],
43037         ['line', 'railway', '*', 12],
43038         ['line', 'waterway', '*', 12],
43039         ['area', 'aeroway', '*', 12],
43040         ['area', 'amenity', '*', 12],
43041         ['area', 'building', '*', 12],
43042         ['area', 'historic', '*', 12],
43043         ['area', 'leisure', '*', 12],
43044         ['area', 'man_made', '*', 12],
43045         ['area', 'natural', '*', 12],
43046         ['area', 'shop', '*', 12],
43047         ['area', 'tourism', '*', 12],
43048         ['area', 'camp_site', '*', 12],
43049         ['point', 'aeroway', '*', 10],
43050         ['point', 'amenity', '*', 10],
43051         ['point', 'building', '*', 10],
43052         ['point', 'historic', '*', 10],
43053         ['point', 'leisure', '*', 10],
43054         ['point', 'man_made', '*', 10],
43055         ['point', 'natural', '*', 10],
43056         ['point', 'shop', '*', 10],
43057         ['point', 'tourism', '*', 10],
43058         ['point', 'camp_site', '*', 10],
43059         ['line', 'name', '*', 12],
43060         ['area', 'name', '*', 12],
43061         ['point', 'name', '*', 10]
43062     ];
43063
43064
43065     function blacklisted(preset) {
43066         var noIcons = ['building', 'landuse', 'natural'];
43067         return lodash.some(noIcons, function(s) {
43068             return preset.id.indexOf(s) >= 0;
43069         });
43070     }
43071
43072
43073     function get(array, prop) {
43074         return function(d, i) { return array[i][prop]; };
43075     }
43076
43077
43078     function textWidth(text$$1, size, elem) {
43079         var c = textWidthCache[size];
43080         if (!c) c = textWidthCache[size] = {};
43081
43082         if (c[text$$1]) {
43083             return c[text$$1];
43084
43085         } else if (elem) {
43086             c[text$$1] = elem.getComputedTextLength();
43087             return c[text$$1];
43088
43089         } else {
43090             var str = encodeURIComponent(text$$1).match(/%[CDEFcdef]/g);
43091             if (str === null) {
43092                 return size / 3 * 2 * text$$1.length;
43093             } else {
43094                 return size / 3 * (2 * text$$1.length + str.length);
43095             }
43096         }
43097     }
43098
43099
43100     function drawLinePaths(selection$$1, entities, filter, classes, labels) {
43101         var paths = selection$$1.selectAll('path')
43102             .filter(filter)
43103             .data(entities, osmEntity$$1.key);
43104
43105         paths.exit()
43106             .remove();
43107
43108         paths.enter()
43109             .append('path')
43110             .style('stroke-width', get(labels, 'font-size'))
43111             .attr('id', function(d) { return 'labelpath-' + d.id; })
43112             .attr('class', classes)
43113             .merge(paths)
43114             .attr('d', get(labels, 'lineString'));
43115     }
43116
43117
43118     function drawLineLabels(selection$$1, entities, filter, classes, labels) {
43119         var texts = selection$$1.selectAll('text.' + classes)
43120             .filter(filter)
43121             .data(entities, osmEntity$$1.key);
43122
43123         texts.exit()
43124             .remove();
43125
43126         texts.enter()
43127             .append('text')
43128             .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
43129             .attr('dy', baselineHack ? '0.35em' : null)
43130             .append('textPath')
43131             .attr('class', 'textpath');
43132
43133         texts = selection$$1.selectAll('text.' + classes);
43134
43135         texts.selectAll('.textpath')
43136             .filter(filter)
43137             .data(entities, osmEntity$$1.key)
43138             .attr('startOffset', '50%')
43139             .attr('xlink:href', function(d) { return '#labelpath-' + d.id; })
43140             .text(utilDisplayNameForPath);
43141     }
43142
43143
43144     function drawPointLabels(selection$$1, entities, filter, classes, labels) {
43145         var texts = selection$$1.selectAll('text.' + classes)
43146             .filter(filter)
43147             .data(entities, osmEntity$$1.key);
43148
43149         texts.exit()
43150             .remove();
43151
43152         texts = texts.enter()
43153             .append('text')
43154             .attr('class', function(d, i) {
43155                 return classes + ' ' + labels[i].classes + ' ' + d.id;
43156             })
43157             .merge(texts);
43158
43159         texts
43160             .attr('x', get(labels, 'x'))
43161             .attr('y', get(labels, 'y'))
43162             .style('text-anchor', get(labels, 'textAnchor'))
43163             .text(utilDisplayName)
43164             .each(function(d, i) {
43165                 textWidth(utilDisplayName(d), labels[i].height, this);
43166             });
43167     }
43168
43169
43170     function drawAreaLabels(selection$$1, entities, filter, classes, labels) {
43171         entities = entities.filter(hasText);
43172         labels = labels.filter(hasText);
43173         drawPointLabels(selection$$1, entities, filter, classes, labels);
43174
43175         function hasText(d, i) {
43176             return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
43177         }
43178     }
43179
43180
43181     function drawAreaIcons(selection$$1, entities, filter, classes, labels) {
43182         var icons = selection$$1.selectAll('use.' + classes)
43183             .filter(filter)
43184             .data(entities, osmEntity$$1.key);
43185
43186         icons.exit()
43187             .remove();
43188
43189         icons = icons.enter()
43190             .append('use')
43191             .attr('class', 'icon ' + classes)
43192             .attr('width', '17px')
43193             .attr('height', '17px')
43194             .merge(icons);
43195
43196         icons
43197             .attr('transform', get(labels, 'transform'))
43198             .attr('xlink:href', function(d) {
43199                 var preset = context.presets().match(d, context.graph()),
43200                     picon = preset && preset.icon;
43201
43202                 if (!picon)
43203                     return '';
43204                 else {
43205                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
43206                     return '#' + picon + (isMaki ? '-15' : '');
43207                 }
43208             });
43209     }
43210
43211
43212     function drawCollisionBoxes(selection$$1, rtree, which) {
43213         var showDebug = context.getDebug('collision'),
43214             classes = 'debug ' + which + ' ' +
43215                 (which === 'debug-skipped' ? 'orange' : 'yellow');
43216
43217         var debug = selection$$1.selectAll('.layer-label-debug')
43218                 .data(showDebug ? [true] : []);
43219
43220         debug.exit()
43221             .remove();
43222
43223         debug = debug.enter()
43224             .append('g')
43225             .attr('class', 'layer-label-debug')
43226             .merge(debug);
43227
43228         if (showDebug) {
43229             var gj = rtree.all().map(function(d) {
43230                 return { type: 'Polygon', coordinates: [[
43231                     [d.minX, d.minY],
43232                     [d.maxX, d.minY],
43233                     [d.maxX, d.maxY],
43234                     [d.minX, d.maxY],
43235                     [d.minX, d.minY]
43236                 ]]};
43237             });
43238
43239             var debugboxes = debug.selectAll('.' + which)
43240                 .data(gj);
43241
43242             debugboxes.exit()
43243                 .remove();
43244
43245             debugboxes = debugboxes.enter()
43246                 .append('path')
43247                 .attr('class', classes)
43248                 .merge(debugboxes);
43249
43250             debugboxes
43251                 .attr('d', index$4());
43252         }
43253     }
43254
43255
43256     function drawLabels(selection$$1, graph, entities, filter, dimensions, fullRedraw) {
43257         var lowZoom = context.surface().classed('low-zoom');
43258
43259         var labelable = [], i, j, k, entity, geometry;
43260         for (i = 0; i < labelStack.length; i++) {
43261             labelable.push([]);
43262         }
43263
43264         if (fullRedraw) {
43265             rdrawn.clear();
43266             rskipped.clear();
43267             entitybboxes = {};
43268         } else {
43269             for (i = 0; i < entities.length; i++) {
43270                 entity = entities[i];
43271                 var toRemove = []
43272                     .concat(entitybboxes[entity.id] || [])
43273                     .concat(entitybboxes[entity.id + 'I'] || []);
43274
43275                 for (j = 0; j < toRemove.length; j++) {
43276                     rdrawn.remove(toRemove[j]);
43277                     rskipped.remove(toRemove[j]);
43278                 }
43279             }
43280         }
43281
43282         // Split entities into groups specified by labelStack
43283         for (i = 0; i < entities.length; i++) {
43284             entity = entities[i];
43285             geometry = entity.geometry(graph);
43286             if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43287
43288             var preset = geometry === 'area' && context.presets().match(entity, graph),
43289                 icon = preset && !blacklisted(preset) && preset.icon;
43290
43291             if (!icon && !utilDisplayName(entity))
43292                 continue;
43293
43294             for (k = 0; k < labelStack.length; k++) {
43295                 var matchGeom = labelStack[k][0],
43296                     matchKey = labelStack[k][1],
43297                     matchVal = labelStack[k][2],
43298                     hasVal = entity.tags[matchKey];
43299
43300                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
43301                     labelable[k].push(entity);
43302                     break;
43303                 }
43304             }
43305         }
43306
43307         var positions = {
43308             point: [],
43309             line: [],
43310             area: []
43311         };
43312
43313         var labelled = {
43314             point: [],
43315             line: [],
43316             area: []
43317         };
43318
43319         // Try and find a valid label for labellable entities
43320         for (k = 0; k < labelable.length; k++) {
43321             var fontSize = labelStack[k][3];
43322             for (i = 0; i < labelable[k].length; i++) {
43323                 entity = labelable[k][i];
43324                 geometry = entity.geometry(graph);
43325
43326                 var getName = (geometry === 'line') ? utilDisplayNameForPath : utilDisplayName,
43327                     name = getName(entity),
43328                     width = name && textWidth(name, fontSize),
43329                     p;
43330
43331                 if (geometry === 'point') {
43332                     p = getPointLabel(entity, width, fontSize, geometry);
43333                 } else if (geometry === 'vertex' && !lowZoom) {
43334                     // don't label vertices at low zoom because they don't have icons
43335                     p = getPointLabel(entity, width, fontSize, geometry);
43336                 } else if (geometry === 'line') {
43337                     p = getLineLabel(entity, width, fontSize);
43338                 } else if (geometry === 'area') {
43339                     p = getAreaLabel(entity, width, fontSize);
43340                 }
43341
43342                 if (p) {
43343                     if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43344                     p.classes = geometry + ' tag-' + labelStack[k][1];
43345                     positions[geometry].push(p);
43346                     labelled[geometry].push(entity);
43347                 }
43348             }
43349         }
43350
43351
43352         function getPointLabel(entity, width, height, geometry) {
43353             var y = (geometry === 'point' ? -12 : 0),
43354                 pointOffsets = {
43355                     ltr: [15, y, 'start'],
43356                     rtl: [-15, y, 'end']
43357                 };
43358
43359             var coord = projection(entity.loc),
43360                 margin = 2,
43361                 offset = pointOffsets[textDirection],
43362                 p = {
43363                     height: height,
43364                     width: width,
43365                     x: coord[0] + offset[0],
43366                     y: coord[1] + offset[1],
43367                     textAnchor: offset[2]
43368                 },
43369                 bbox;
43370
43371             if (textDirection === 'rtl') {
43372                 bbox = {
43373                     minX: p.x - width - margin,
43374                     minY: p.y - (height / 2) - margin,
43375                     maxX: p.x + margin,
43376                     maxY: p.y + (height / 2) + margin
43377                 };
43378             } else {
43379                 bbox = {
43380                     minX: p.x - margin,
43381                     minY: p.y - (height / 2) - margin,
43382                     maxX: p.x + width + margin,
43383                     maxY: p.y + (height / 2) + margin
43384                 };
43385             }
43386
43387             if (tryInsert([bbox], entity.id, true)) {
43388                 return p;
43389             }
43390         }
43391
43392
43393         function getLineLabel(entity, width, height) {
43394             var viewport = geoExtent$$1(context.projection.clipExtent()).polygon(),
43395                 nodes = lodash.map(graph.childNodes(entity), 'loc').map(projection),
43396                 length = geoPathLength(nodes);
43397
43398             if (length < width + 20) return;
43399
43400             // % along the line to attempt to place the label
43401             var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70,
43402                                25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
43403             var margin = 3;
43404
43405             for (var i = 0; i < lineOffsets.length; i++) {
43406                 var offset = lineOffsets[i],
43407                     middle = offset / 100 * length,
43408                     start = middle - width / 2;
43409
43410                 if (start < 0 || start + width > length) continue;
43411
43412                 // generate subpath and ignore paths that are invalid or don't cross viewport.
43413                 var sub = subpath(nodes, start, start + width);
43414                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
43415                     continue;
43416                 }
43417
43418                 var isReverse = reverse(sub);
43419                 if (isReverse) {
43420                     sub = sub.reverse();
43421                 }
43422
43423                 var bboxes = [],
43424                     boxsize = (height + 2) / 2;
43425
43426                 for (var j = 0; j < sub.length - 1; j++) {
43427                     var a = sub[j];
43428                     var b = sub[j + 1];
43429                     var num = Math.max(1, Math.floor(geoEuclideanDistance(a, b) / boxsize / 2));
43430
43431                     for (var box = 0; box < num; box++) {
43432                         var p = geoInterp(a, b, box / num);
43433                         var x0 = p[0] - boxsize - margin;
43434                         var y0 = p[1] - boxsize - margin;
43435                         var x1 = p[0] + boxsize + margin;
43436                         var y1 = p[1] + boxsize + margin;
43437
43438                         bboxes.push({
43439                             minX: Math.min(x0, x1),
43440                             minY: Math.min(y0, y1),
43441                             maxX: Math.max(x0, x1),
43442                             maxY: Math.max(y0, y1)
43443                         });
43444                     }
43445                 }
43446
43447                 if (tryInsert(bboxes, entity.id, false)) {
43448                     return {
43449                         'font-size': height + 2,
43450                         lineString: lineString(sub),
43451                         startOffset: offset + '%'
43452                     };
43453                 }
43454             }
43455
43456             function reverse(p) {
43457                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
43458                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
43459             }
43460
43461             function lineString(nodes) {
43462                 return 'M' + nodes.join('L');
43463             }
43464
43465             function subpath(nodes, from, to) {
43466                 var sofar = 0,
43467                     start, end, i0, i1;
43468
43469                 for (var i = 0; i < nodes.length - 1; i++) {
43470                     var a = nodes[i],
43471                         b = nodes[i + 1];
43472                     var current = geoEuclideanDistance(a, b);
43473                     var portion;
43474                     if (!start && sofar + current >= from) {
43475                         portion = (from - sofar) / current;
43476                         start = [
43477                             a[0] + portion * (b[0] - a[0]),
43478                             a[1] + portion * (b[1] - a[1])
43479                         ];
43480                         i0 = i + 1;
43481                     }
43482                     if (!end && sofar + current >= to) {
43483                         portion = (to - sofar) / current;
43484                         end = [
43485                             a[0] + portion * (b[0] - a[0]),
43486                             a[1] + portion * (b[1] - a[1])
43487                         ];
43488                         i1 = i + 1;
43489                     }
43490                     sofar += current;
43491                 }
43492
43493                 var ret = nodes.slice(i0, i1);
43494                 ret.unshift(start);
43495                 ret.push(end);
43496                 return ret;
43497             }
43498         }
43499
43500
43501         function getAreaLabel(entity, width, height) {
43502             var centroid = path$$1.centroid(entity.asGeoJSON(graph, true)),
43503                 extent$$1 = entity.extent(graph),
43504                 entitywidth = projection(extent$$1[1])[0] - projection(extent$$1[0])[0];
43505
43506             if (isNaN(centroid[0]) || entitywidth < 20) return;
43507
43508             var iconSize = 20,
43509                 iconX = centroid[0] - (iconSize / 2),
43510                 iconY = centroid[1] - (iconSize / 2),
43511                 margin = 2,
43512                 textOffset = iconSize + margin,
43513                 p = { transform: 'translate(' + iconX + ',' + iconY + ')' };
43514
43515             var bbox = {
43516                 minX: iconX,
43517                 minY: iconY,
43518                 maxX: iconX + iconSize,
43519                 maxY: iconY + iconSize
43520             };
43521
43522             // try to add icon
43523             if (tryInsert([bbox], entity.id + 'I', true)) {
43524                 if (width && entitywidth >= width + 20) {
43525                     var labelX = centroid[0],
43526                         labelY = centroid[1] + textOffset;
43527
43528                     bbox = {
43529                         minX: labelX - (width / 2) - margin,
43530                         minY: labelY - (height / 2) - margin,
43531                         maxX: labelX + (width / 2) + margin,
43532                         maxY: labelY + (height / 2) + margin
43533                     };
43534
43535                     // try to add label
43536                     if (tryInsert([bbox], entity.id, true)) {
43537                         p.x = labelX;
43538                         p.y = labelY;
43539                         p.textAnchor = 'middle';
43540                         p.height = height;
43541                     }
43542                 }
43543
43544                 return p;
43545             }
43546         }
43547
43548
43549         function tryInsert(bboxes, id, saveSkipped) {
43550             var skipped = false,
43551                 bbox;
43552
43553             for (var i = 0; i < bboxes.length; i++) {
43554                 bbox = bboxes[i];
43555                 bbox.id = id;
43556
43557                 // Check that label is visible
43558                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
43559                     skipped = true;
43560                     break;
43561                 }
43562                 if (rdrawn.collides(bbox)) {
43563                     skipped = true;
43564                     break;
43565                 }
43566             }
43567
43568             entitybboxes[id] = bboxes;
43569
43570             if (skipped) {
43571                 if (saveSkipped) {
43572                     rskipped.load(bboxes);
43573                 }
43574             } else {
43575                 rdrawn.load(bboxes);
43576             }
43577
43578             return !skipped;
43579         }
43580
43581
43582         var label = selection$$1.selectAll('.layer-label'),
43583             halo = selection$$1.selectAll('.layer-halo');
43584
43585         // points
43586         drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
43587         drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
43588
43589         // lines
43590         drawLinePaths(halo, labelled.line, filter, '', positions.line);
43591         drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
43592         drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
43593
43594         // areas
43595         drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
43596         drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
43597         drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
43598         drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area);
43599
43600         // debug
43601         drawCollisionBoxes(label, rskipped, 'debug-skipped');
43602         drawCollisionBoxes(label, rdrawn, 'debug-drawn');
43603
43604         selection$$1.call(filterLabels);
43605     }
43606
43607
43608     function filterLabels(selection$$1) {
43609         var layers = selection$$1
43610             .selectAll('.layer-label, .layer-halo');
43611
43612         layers.selectAll('.proximate')
43613             .classed('proximate', false);
43614
43615         var mouse$$1 = context.mouse(),
43616             graph = context.graph(),
43617             selectedIDs = context.selectedIDs(),
43618             ids = [],
43619             pad, bbox;
43620
43621         // hide labels near the mouse
43622         if (mouse$$1) {
43623             pad = 20;
43624             bbox = { minX: mouse$$1[0] - pad, minY: mouse$$1[1] - pad, maxX: mouse$$1[0] + pad, maxY: mouse$$1[1] + pad };
43625             ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
43626         }
43627
43628         // hide labels along selected ways, or near selected vertices
43629         for (var i = 0; i < selectedIDs.length; i++) {
43630             var entity = graph.hasEntity(selectedIDs[i]);
43631             if (!entity) continue;
43632             var geometry = entity.geometry(graph);
43633
43634             if (geometry === 'line') {
43635                 ids.push(selectedIDs[i]);
43636             } else if (geometry === 'vertex') {
43637                 var point = context.projection(entity.loc);
43638                 pad = 10;
43639                 bbox = { minX: point[0] - pad, minY: point[1] - pad, maxX: point[0] + pad, maxY: point[1] + pad };
43640                 ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
43641             }
43642         }
43643
43644         layers.selectAll(utilEntitySelector(ids))
43645             .classed('proximate', true);
43646     }
43647
43648
43649     var throttleFilterLabels = lodash.throttle(filterLabels, 100);
43650
43651
43652     drawLabels.observe = function(selection$$1) {
43653         var listener = function() { throttleFilterLabels(selection$$1); };
43654         selection$$1.on('mousemove.hidelabels', listener);
43655         context.on('enter.hidelabels', listener);
43656     };
43657
43658
43659     drawLabels.off = function(selection$$1) {
43660         throttleFilterLabels.cancel();
43661         selection$$1.on('mousemove.hidelabels', null);
43662         context.on('enter.hidelabels', null);
43663     };
43664
43665
43666     return drawLabels;
43667 }
43668
43669 function refresh(selection, node) {
43670     var cr = node.getBoundingClientRect();
43671     var prop = [cr.width, cr.height];
43672     selection.property('__dimensions__', prop);
43673     return prop;
43674 }
43675
43676 function utilGetDimensions(selection, force) {
43677     if (!selection || selection.empty()) {
43678         return [0, 0];
43679     }
43680     var node = selection.node(),
43681         cached = selection.property('__dimensions__');
43682     return (!cached || force) ? refresh(selection, node) : cached;
43683 }
43684
43685
43686 function utilSetDimensions(selection, dimensions) {
43687     if (!selection || selection.empty()) {
43688         return selection;
43689     }
43690     var node = selection.node();
43691     if (dimensions === null) {
43692         refresh(selection, node);
43693         return selection;
43694     }
43695     return selection
43696         .property('__dimensions__', [dimensions[0], dimensions[1]])
43697         .attr('width', dimensions[0])
43698         .attr('height', dimensions[1]);
43699 }
43700
43701 function svgPointTransform(projection) {
43702     return function(entity) {
43703         // http://jsperf.com/short-array-join
43704         var pt = projection(entity.loc);
43705         return 'translate(' + pt[0] + ',' + pt[1] + ')';
43706     };
43707 }
43708
43709 function d3geoTile() {
43710   var size = [960, 500],
43711       scale = 256,
43712       scaleExtent = [0, 20],
43713       translate = [size[0] / 2, size[1] / 2],
43714       zoomDelta = 0;
43715
43716   function bound(_) {
43717       return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
43718   }
43719
43720   function tile() {
43721     var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
43722         z0 = bound(Math.round(z + zoomDelta)),
43723         k = Math.pow(2, z - z0 + 8),
43724         origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
43725         tiles = [],
43726         cols = sequence(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
43727         rows = sequence(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
43728
43729     rows.forEach(function(y) {
43730       cols.forEach(function(x) {
43731         tiles.push([x, y, z0]);
43732       });
43733     });
43734
43735     tiles.translate = origin;
43736     tiles.scale = k;
43737
43738     return tiles;
43739   }
43740
43741   tile.scaleExtent = function(_) {
43742     if (!arguments.length) return scaleExtent;
43743     scaleExtent = _;
43744     return tile;
43745   };
43746
43747   tile.size = function(_) {
43748     if (!arguments.length) return size;
43749     size = _;
43750     return tile;
43751   };
43752
43753   tile.scale = function(_) {
43754     if (!arguments.length) return scale;
43755     scale = _;
43756     return tile;
43757   };
43758
43759   tile.translate = function(_) {
43760     if (!arguments.length) return translate;
43761     translate = _;
43762     return tile;
43763   };
43764
43765   tile.zoomDelta = function(_) {
43766     if (!arguments.length) return zoomDelta;
43767     zoomDelta = +_;
43768     return tile;
43769   };
43770
43771   return tile;
43772 }
43773
43774 /* global Mapillary:false */
43775 var apibase = 'https://a.mapillary.com/v2/';
43776 var viewercss = 'mapillary-js/mapillary.min.css';
43777 var viewerjs = 'mapillary-js/mapillary.min.js';
43778 var trafficocss = 'traffico/stylesheets/traffico.css';
43779 var clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
43780 var maxResults = 1000;
43781 var tileZoom = 14;
43782 var dispatch$2 = dispatch('loadedImages', 'loadedSigns');
43783 var mapillaryCache;
43784 var mapillaryClicks;
43785 var mapillaryImage;
43786 var mapillarySignDefs;
43787 var mapillaryViewer;
43788
43789
43790 function abortRequest(i) {
43791     i.abort();
43792 }
43793
43794
43795 function nearNullIsland(x, y, z) {
43796     if (z >= 7) {
43797         var center = Math.pow(2, z - 1),
43798             width = Math.pow(2, z - 6),
43799             min$$1 = center - (width / 2),
43800             max$$1 = center + (width / 2) - 1;
43801         return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
43802     }
43803     return false;
43804 }
43805
43806
43807 function maxPageAtZoom(z) {
43808     if (z < 15)   return 2;
43809     if (z === 15) return 5;
43810     if (z === 16) return 10;
43811     if (z === 17) return 20;
43812     if (z === 18) return 40;
43813     if (z > 18)   return 80;
43814 }
43815
43816
43817 function getTiles(projection) {
43818     var s = projection.scale() * 2 * Math.PI,
43819         z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
43820         ts = 256 * Math.pow(2, z - tileZoom),
43821         origin = [
43822             s / 2 - projection.translate()[0],
43823             s / 2 - projection.translate()[1]];
43824
43825     return d3geoTile()
43826         .scaleExtent([tileZoom, tileZoom])
43827         .scale(s)
43828         .size(projection.clipExtent()[1])
43829         .translate(projection.translate())()
43830         .map(function(tile) {
43831             var x = tile[0] * ts - origin[0],
43832                 y = tile[1] * ts - origin[1];
43833
43834             return {
43835                 id: tile.toString(),
43836                 xyz: tile,
43837                 extent: geoExtent$$1(
43838                     projection.invert([x, y + ts]),
43839                     projection.invert([x + ts, y])
43840                 )
43841             };
43842         });
43843 }
43844
43845
43846 function loadTiles(which, url, projection) {
43847     var s = projection.scale() * 2 * Math.PI,
43848         currZoom = Math.floor(Math.max(Math.log(s) / Math.log(2) - 8, 0));
43849
43850     var tiles = getTiles(projection).filter(function(t) {
43851             return !nearNullIsland(t.xyz[0], t.xyz[1], t.xyz[2]);
43852         });
43853
43854     lodash.filter(which.inflight, function(v, k) {
43855         var wanted = lodash.find(tiles, function(tile) { return k === (tile.id + ',0'); });
43856         if (!wanted) delete which.inflight[k];
43857         return !wanted;
43858     }).map(abortRequest);
43859
43860     tiles.forEach(function(tile) {
43861         loadNextTilePage(which, currZoom, url, tile);
43862     });
43863 }
43864
43865
43866 function loadNextTilePage(which, currZoom, url, tile) {
43867     var cache = mapillaryCache[which],
43868         rect = tile.extent.rectangle(),
43869         maxPages = maxPageAtZoom(currZoom),
43870         nextPage = cache.nextPage[tile.id] || 0;
43871
43872     if (nextPage > maxPages) return;
43873
43874     var id = tile.id + ',' + String(nextPage);
43875     if (cache.loaded[id] || cache.inflight[id]) return;
43876
43877     cache.inflight[id] = json(url +
43878         utilQsString({
43879             geojson: 'true',
43880             limit: maxResults,
43881             page: nextPage,
43882             client_id: clientId,
43883             min_lon: rect[0],
43884             min_lat: rect[1],
43885             max_lon: rect[2],
43886             max_lat: rect[3]
43887         }), function(err, data) {
43888             cache.loaded[id] = true;
43889             delete cache.inflight[id];
43890             if (err || !data.features || !data.features.length) return;
43891
43892             var features = [],
43893                 feature, loc, d;
43894
43895             for (var i = 0; i < data.features.length; i++) {
43896                 feature = data.features[i];
43897                 loc = feature.geometry.coordinates;
43898                 d = { key: feature.properties.key, loc: loc };
43899                 if (which === 'images') d.ca = feature.properties.ca;
43900                 if (which === 'signs') d.signs = feature.properties.rects;
43901
43902                 features.push({minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d});
43903             }
43904
43905             cache.rtree.load(features);
43906
43907             if (which === 'images') dispatch$2.call('loadedImages');
43908             if (which === 'signs') dispatch$2.call('loadedSigns');
43909
43910             if (data.features.length === maxResults) {  // more pages to load
43911                 cache.nextPage[tile.id] = nextPage + 1;
43912                 loadNextTilePage(which, currZoom, url, tile);
43913             } else {
43914                 cache.nextPage[tile.id] = Infinity;     // no more pages to load
43915             }
43916         }
43917     );
43918 }
43919
43920
43921 // partition viewport into `psize` x `psize` regions
43922 function partitionViewport(psize, projection) {
43923     var dimensions = projection.clipExtent()[1];
43924     psize = psize || 16;
43925     var cols = sequence(0, dimensions[0], psize),
43926         rows = sequence(0, dimensions[1], psize),
43927         partitions = [];
43928
43929     rows.forEach(function(y) {
43930         cols.forEach(function(x) {
43931             var min$$1 = [x, y + psize],
43932                 max$$1 = [x + psize, y];
43933             partitions.push(
43934                 geoExtent$$1(projection.invert(min$$1), projection.invert(max$$1)));
43935         });
43936     });
43937
43938     return partitions;
43939 }
43940
43941
43942 // no more than `limit` results per partition.
43943 function searchLimited(psize, limit, projection, rtree) {
43944     limit = limit || 3;
43945
43946     var partitions = partitionViewport(psize, projection);
43947     return lodash.flatten(lodash.compact(lodash.map(partitions, function(extent$$1) {
43948         return rtree.search(extent$$1.bbox())
43949             .slice(0, limit)
43950             .map(function(d) { return d.data; });
43951     })));
43952 }
43953
43954
43955
43956 var serviceMapillary = {
43957
43958     init: function() {
43959         if (!mapillaryCache) {
43960             this.reset();
43961         }
43962
43963         this.event = utilRebind(this, dispatch$2, 'on');
43964     },
43965
43966     reset: function() {
43967         var cache = mapillaryCache;
43968
43969         if (cache) {
43970             if (cache.images && cache.images.inflight) {
43971                 lodash.forEach(cache.images.inflight, abortRequest);
43972             }
43973             if (cache.signs && cache.signs.inflight) {
43974                 lodash.forEach(cache.signs.inflight, abortRequest);
43975             }
43976         }
43977
43978         mapillaryCache = {
43979             images: { inflight: {}, loaded: {}, nextPage: {}, rtree: index$9() },
43980             signs:  { inflight: {}, loaded: {}, nextPage: {}, rtree: index$9() }
43981         };
43982
43983         mapillaryImage = null;
43984         mapillaryClicks = [];
43985     },
43986
43987
43988     images: function(projection) {
43989         var psize = 16, limit = 3;
43990         return searchLimited(psize, limit, projection, mapillaryCache.images.rtree);
43991     },
43992
43993
43994     signs: function(projection) {
43995         var psize = 32, limit = 3;
43996         return searchLimited(psize, limit, projection, mapillaryCache.signs.rtree);
43997     },
43998
43999
44000     signsSupported: function() {
44001         var detected = utilDetect();
44002         if (detected.ie) return false;
44003         if ((detected.browser.toLowerCase() === 'safari') && (parseFloat(detected.version) < 10)) return false;
44004         return true;
44005     },
44006
44007
44008     signHTML: function(d) {
44009         if (!mapillarySignDefs) return;
44010
44011         var detectionPackage = d.signs[0].package,
44012             type = d.signs[0].type,
44013             country = detectionPackage.split('_')[1];
44014
44015         return mapillarySignDefs[country][type];
44016     },
44017
44018
44019     loadImages: function(projection) {
44020         var url = apibase + 'search/im/geojson?';
44021         loadTiles('images', url, projection);
44022     },
44023
44024
44025     loadSigns: function(context, projection) {
44026         var url = apibase + 'search/im/geojson/or?';
44027         loadTiles('signs', url, projection);
44028
44029         // load traffico css
44030         select('head').selectAll('#traffico')
44031             .data([0])
44032             .enter()
44033             .append('link')
44034             .attr('id', 'traffico')
44035             .attr('rel', 'stylesheet')
44036             .attr('href', context.asset(trafficocss));
44037
44038         // load traffico sign defs
44039         if (!mapillarySignDefs) {
44040             mapillarySignDefs = {};
44041             lodash.each(['au', 'br', 'ca', 'de', 'us'], function(region) {
44042                 json(context.asset('traffico/string-maps/' + region + '-map.json'), function(err, data) {
44043                     if (err) return;
44044                     if (region === 'de') region = 'eu';
44045                     mapillarySignDefs[region] = data;
44046                 });
44047             });
44048         }
44049     },
44050
44051
44052     loadViewer: function(context) {
44053         var that = this;
44054         var wrap = select('#content').selectAll('.mapillary-wrap')
44055             .data([0]);
44056
44057         var enter = wrap.enter()
44058             .append('div')
44059             .attr('class', 'mapillary-wrap')
44060             .classed('al', true)       // 'al'=left,  'ar'=right
44061             .classed('hidden', true);
44062
44063         enter
44064             .append('button')
44065             .attr('class', 'thumb-hide')
44066             .on('click', function () { that.hideViewer(); })
44067             .append('div')
44068             .call(svgIcon('#icon-close'));
44069
44070         enter
44071             .append('div')
44072             .attr('id', 'mly')
44073             .attr('class', 'mly-wrapper')
44074             .classed('active', false);
44075
44076         // load mapillary-viewercss
44077         select('head').selectAll('#mapillary-viewercss')
44078             .data([0])
44079             .enter()
44080             .append('link')
44081             .attr('id', 'mapillary-viewercss')
44082             .attr('rel', 'stylesheet')
44083             .attr('href', context.asset(viewercss));
44084
44085         // load mapillary-viewerjs
44086         select('head').selectAll('#mapillary-viewerjs')
44087             .data([0])
44088             .enter()
44089             .append('script')
44090             .attr('id', 'mapillary-viewerjs')
44091             .attr('src', context.asset(viewerjs));
44092     },
44093
44094
44095     showViewer: function() {
44096         select('#content')
44097             .selectAll('.mapillary-wrap')
44098             .classed('hidden', false)
44099             .selectAll('.mly-wrapper')
44100             .classed('active', true);
44101
44102         return this;
44103     },
44104
44105
44106     hideViewer: function() {
44107         select('#content')
44108             .selectAll('.mapillary-wrap')
44109             .classed('hidden', true)
44110             .selectAll('.mly-wrapper')
44111             .classed('active', false);
44112
44113         selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
44114             .classed('selected', false);
44115
44116         mapillaryImage = null;
44117         return this;
44118     },
44119
44120
44121     updateViewer: function(imageKey, context) {
44122         if (!imageKey) return;
44123
44124         if (!mapillaryViewer) {
44125             this.initViewer(imageKey, context);
44126         } else {
44127             mapillaryViewer.moveToKey(imageKey);
44128         }
44129
44130         return this;
44131     },
44132
44133
44134     initViewer: function(imageKey, context) {
44135         var that = this;
44136         if (Mapillary && imageKey) {
44137             var opts = {
44138                 baseImageSize: 320,
44139                 component: {
44140                     cover: false,
44141                     keyboard: false
44142                 }
44143             };
44144
44145             mapillaryViewer = new Mapillary.Viewer('mly', clientId, imageKey, opts);
44146             mapillaryViewer.on('nodechanged', nodeChanged);
44147         }
44148
44149         function nodeChanged(node) {
44150             var clicks = mapillaryClicks;
44151             var index = clicks.indexOf(node.key);
44152             if (index > -1) {    // nodechange initiated from clicking on a marker..
44153                 clicks.splice(index, 1);
44154             } else {             // nodechange initiated from the Mapillary viewer controls..
44155                 var loc = node.computedLatLon ? [node.computedLatLon.lon, node.computedLatLon.lat] : [node.latLon.lon, node.latLon.lat];
44156                 context.map().centerEase(loc);
44157                 that.selectedImage(node.key, false);
44158             }
44159         }
44160     },
44161
44162
44163     selectedImage: function(imageKey, fromClick) {
44164         if (!arguments.length) return mapillaryImage;
44165
44166         mapillaryImage = imageKey;
44167         if (fromClick) {
44168             mapillaryClicks.push(imageKey);
44169         }
44170
44171         selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
44172             .classed('selected', function(d) { return d.key === imageKey; });
44173
44174         return this;
44175     },
44176
44177
44178     cache: function(_) {
44179         if (!arguments.length) return mapillaryCache;
44180         mapillaryCache = _;
44181         return this;
44182     },
44183
44184
44185     signDefs: function(_) {
44186         if (!arguments.length) return mapillarySignDefs;
44187         mapillarySignDefs = _;
44188         return this;
44189     }
44190
44191 };
44192
44193 var apibase$1 = 'https://nominatim.openstreetmap.org/';
44194 var inflight = {};
44195 var nominatimCache;
44196
44197
44198 var serviceNominatim = {
44199
44200     init: function() {
44201         inflight = {};
44202         nominatimCache = index$9();
44203     },
44204
44205     reset: function() {
44206         lodash.forEach(inflight, function(req) { req.abort(); });
44207         inflight = {};
44208         nominatimCache = index$9();
44209     },
44210
44211
44212     countryCode: function (location, callback) {
44213         var countryCodes = nominatimCache.search(
44214             { minX: location[0], minY: location[1], maxX: location[0], maxY: location[1] }
44215         );
44216
44217         if (countryCodes.length > 0) {
44218             return callback(null, countryCodes[0].data);
44219         }
44220
44221         var params = { format: 'json', addressdetails: 1, lat: location[1], lon: location[0] };
44222         var url = apibase$1 + 'reverse?' + utilQsString(params);
44223         if (inflight[url]) return;
44224
44225         inflight[url] = json(url, function(err, result) {
44226             delete inflight[url];
44227
44228             if (err)
44229                 return callback(err);
44230             else if (result && result.error)
44231                 return callback(result.error);
44232
44233             var extent$$1 = geoExtent$$1(location).padByMeters(1000);
44234             nominatimCache.insert(lodash.assign(extent$$1.bbox(),
44235                 { data: result.address.country_code }
44236             ));
44237
44238             callback(null, result.address.country_code);
44239         });
44240     },
44241
44242
44243     search: function (val, callback) {
44244         var searchVal = encodeURIComponent(val);
44245         var url = apibase$1 + 'search/' + searchVal + '?limit=10&format=json';
44246         if (inflight[url]) return;
44247
44248         inflight[url] = json(url, function(err, result) {
44249             delete inflight[url];
44250             callback(err, result);
44251         });
44252     }
44253
44254 };
44255
44256 var hashes = createCommonjsModule(function (module, exports) {
44257 /**
44258  * jshashes - https://github.com/h2non/jshashes
44259  * Released under the "New BSD" license
44260  *
44261  * Algorithms specification:
44262  *
44263  * MD5 - http://www.ietf.org/rfc/rfc1321.txt
44264  * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
44265  * SHA1   - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44266  * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44267  * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44268  * HMAC - http://www.ietf.org/rfc/rfc2104.txt
44269  */
44270 (function() {
44271   var Hashes;
44272
44273   function utf8Encode(str) {
44274     var x, y, output = '',
44275       i = -1,
44276       l;
44277
44278     if (str && str.length) {
44279       l = str.length;
44280       while ((i += 1) < l) {
44281         /* Decode utf-16 surrogate pairs */
44282         x = str.charCodeAt(i);
44283         y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
44284         if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
44285           x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
44286           i += 1;
44287         }
44288         /* Encode output as utf-8 */
44289         if (x <= 0x7F) {
44290           output += String.fromCharCode(x);
44291         } else if (x <= 0x7FF) {
44292           output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F),
44293             0x80 | (x & 0x3F));
44294         } else if (x <= 0xFFFF) {
44295           output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
44296             0x80 | ((x >>> 6) & 0x3F),
44297             0x80 | (x & 0x3F));
44298         } else if (x <= 0x1FFFFF) {
44299           output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
44300             0x80 | ((x >>> 12) & 0x3F),
44301             0x80 | ((x >>> 6) & 0x3F),
44302             0x80 | (x & 0x3F));
44303         }
44304       }
44305     }
44306     return output;
44307   }
44308
44309   function utf8Decode(str) {
44310     var i, ac, c1, c2, c3, arr = [],
44311       l;
44312     i = ac = c1 = c2 = c3 = 0;
44313
44314     if (str && str.length) {
44315       l = str.length;
44316       str += '';
44317
44318       while (i < l) {
44319         c1 = str.charCodeAt(i);
44320         ac += 1;
44321         if (c1 < 128) {
44322           arr[ac] = String.fromCharCode(c1);
44323           i += 1;
44324         } else if (c1 > 191 && c1 < 224) {
44325           c2 = str.charCodeAt(i + 1);
44326           arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
44327           i += 2;
44328         } else {
44329           c2 = str.charCodeAt(i + 1);
44330           c3 = str.charCodeAt(i + 2);
44331           arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
44332           i += 3;
44333         }
44334       }
44335     }
44336     return arr.join('');
44337   }
44338
44339   /**
44340    * Add integers, wrapping at 2^32. This uses 16-bit operations internally
44341    * to work around bugs in some JS interpreters.
44342    */
44343
44344   function safe_add(x, y) {
44345     var lsw = (x & 0xFFFF) + (y & 0xFFFF),
44346       msw = (x >> 16) + (y >> 16) + (lsw >> 16);
44347     return (msw << 16) | (lsw & 0xFFFF);
44348   }
44349
44350   /**
44351    * Bitwise rotate a 32-bit number to the left.
44352    */
44353
44354   function bit_rol(num, cnt) {
44355     return (num << cnt) | (num >>> (32 - cnt));
44356   }
44357
44358   /**
44359    * Convert a raw string to a hex string
44360    */
44361
44362   function rstr2hex(input, hexcase) {
44363     var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
44364       output = '',
44365       x, i = 0,
44366       l = input.length;
44367     for (; i < l; i += 1) {
44368       x = input.charCodeAt(i);
44369       output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
44370     }
44371     return output;
44372   }
44373
44374   /**
44375    * Encode a string as utf-16
44376    */
44377
44378   function binb2rstr(input) {
44379     var i, l = input.length * 32,
44380       output = '';
44381     for (i = 0; i < l; i += 8) {
44382       output += String.fromCharCode((input[i >> 5] >>> (24 - i % 32)) & 0xFF);
44383     }
44384     return output;
44385   }
44386
44387   /**
44388    * Convert an array of little-endian words to a string
44389    */
44390
44391   function binl2rstr(input) {
44392     var i, l = input.length * 32,
44393       output = '';
44394     for (i = 0; i < l; i += 8) {
44395       output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
44396     }
44397     return output;
44398   }
44399
44400   /**
44401    * Convert a raw string to an array of little-endian words
44402    * Characters >255 have their high-byte silently ignored.
44403    */
44404
44405   function rstr2binl(input) {
44406     var i, l = input.length * 8,
44407       output = Array(input.length >> 2),
44408       lo = output.length;
44409     for (i = 0; i < lo; i += 1) {
44410       output[i] = 0;
44411     }
44412     for (i = 0; i < l; i += 8) {
44413       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
44414     }
44415     return output;
44416   }
44417
44418   /**
44419    * Convert a raw string to an array of big-endian words
44420    * Characters >255 have their high-byte silently ignored.
44421    */
44422
44423   function rstr2binb(input) {
44424     var i, l = input.length * 8,
44425       output = Array(input.length >> 2),
44426       lo = output.length;
44427     for (i = 0; i < lo; i += 1) {
44428       output[i] = 0;
44429     }
44430     for (i = 0; i < l; i += 8) {
44431       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
44432     }
44433     return output;
44434   }
44435
44436   /**
44437    * Convert a raw string to an arbitrary string encoding
44438    */
44439
44440   function rstr2any(input, encoding) {
44441     var divisor = encoding.length,
44442       remainders = Array(),
44443       i, q, x, ld, quotient, dividend, output, full_length;
44444
44445     /* Convert to an array of 16-bit big-endian values, forming the dividend */
44446     dividend = Array(Math.ceil(input.length / 2));
44447     ld = dividend.length;
44448     for (i = 0; i < ld; i += 1) {
44449       dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
44450     }
44451
44452     /**
44453      * Repeatedly perform a long division. The binary array forms the dividend,
44454      * the length of the encoding is the divisor. Once computed, the quotient
44455      * forms the dividend for the next step. We stop when the dividend is zerHashes.
44456      * All remainders are stored for later use.
44457      */
44458     while (dividend.length > 0) {
44459       quotient = Array();
44460       x = 0;
44461       for (i = 0; i < dividend.length; i += 1) {
44462         x = (x << 16) + dividend[i];
44463         q = Math.floor(x / divisor);
44464         x -= q * divisor;
44465         if (quotient.length > 0 || q > 0) {
44466           quotient[quotient.length] = q;
44467         }
44468       }
44469       remainders[remainders.length] = x;
44470       dividend = quotient;
44471     }
44472
44473     /* Convert the remainders to the output string */
44474     output = '';
44475     for (i = remainders.length - 1; i >= 0; i--) {
44476       output += encoding.charAt(remainders[i]);
44477     }
44478
44479     /* Append leading zero equivalents */
44480     full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
44481     for (i = output.length; i < full_length; i += 1) {
44482       output = encoding[0] + output;
44483     }
44484     return output;
44485   }
44486
44487   /**
44488    * Convert a raw string to a base-64 string
44489    */
44490
44491   function rstr2b64(input, b64pad) {
44492     var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
44493       output = '',
44494       len = input.length,
44495       i, j, triplet;
44496     b64pad = b64pad || '=';
44497     for (i = 0; i < len; i += 3) {
44498       triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
44499       for (j = 0; j < 4; j += 1) {
44500         if (i * 8 + j * 6 > input.length * 8) {
44501           output += b64pad;
44502         } else {
44503           output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
44504         }
44505       }
44506     }
44507     return output;
44508   }
44509
44510   Hashes = {
44511     /**
44512      * @property {String} version
44513      * @readonly
44514      */
44515     VERSION: '1.0.5',
44516     /**
44517      * @member Hashes
44518      * @class Base64
44519      * @constructor
44520      */
44521     Base64: function() {
44522       // private properties
44523       var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
44524         pad = '=', // default pad according with the RFC standard
44525         url = false, // URL encoding support @todo
44526         utf8 = true; // by default enable UTF-8 support encoding
44527
44528       // public method for encoding
44529       this.encode = function(input) {
44530         var i, j, triplet,
44531           output = '',
44532           len = input.length;
44533
44534         pad = pad || '=';
44535         input = (utf8) ? utf8Encode(input) : input;
44536
44537         for (i = 0; i < len; i += 3) {
44538           triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
44539           for (j = 0; j < 4; j += 1) {
44540             if (i * 8 + j * 6 > len * 8) {
44541               output += pad;
44542             } else {
44543               output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
44544             }
44545           }
44546         }
44547         return output;
44548       };
44549
44550       // public method for decoding
44551       this.decode = function(input) {
44552         // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
44553         var i, o1, o2, o3, h1, h2, h3, h4, bits, ac,
44554           dec = '',
44555           arr = [];
44556         if (!input) {
44557           return input;
44558         }
44559
44560         i = ac = 0;
44561         input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
44562         //input += '';
44563
44564         do { // unpack four hexets into three octets using index points in b64
44565           h1 = tab.indexOf(input.charAt(i += 1));
44566           h2 = tab.indexOf(input.charAt(i += 1));
44567           h3 = tab.indexOf(input.charAt(i += 1));
44568           h4 = tab.indexOf(input.charAt(i += 1));
44569
44570           bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
44571
44572           o1 = bits >> 16 & 0xff;
44573           o2 = bits >> 8 & 0xff;
44574           o3 = bits & 0xff;
44575           ac += 1;
44576
44577           if (h3 === 64) {
44578             arr[ac] = String.fromCharCode(o1);
44579           } else if (h4 === 64) {
44580             arr[ac] = String.fromCharCode(o1, o2);
44581           } else {
44582             arr[ac] = String.fromCharCode(o1, o2, o3);
44583           }
44584         } while (i < input.length);
44585
44586         dec = arr.join('');
44587         dec = (utf8) ? utf8Decode(dec) : dec;
44588
44589         return dec;
44590       };
44591
44592       // set custom pad string
44593       this.setPad = function(str) {
44594         pad = str || pad;
44595         return this;
44596       };
44597       // set custom tab string characters
44598       this.setTab = function(str) {
44599         tab = str || tab;
44600         return this;
44601       };
44602       this.setUTF8 = function(bool) {
44603         if (typeof bool === 'boolean') {
44604           utf8 = bool;
44605         }
44606         return this;
44607       };
44608     },
44609
44610     /**
44611      * CRC-32 calculation
44612      * @member Hashes
44613      * @method CRC32
44614      * @static
44615      * @param {String} str Input String
44616      * @return {String}
44617      */
44618     CRC32: function(str) {
44619       var crc = 0,
44620         x = 0,
44621         y = 0,
44622         table, i, iTop;
44623       str = utf8Encode(str);
44624
44625       table = [
44626         '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ',
44627         '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ',
44628         '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ',
44629         '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ',
44630         'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ',
44631         '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ',
44632         'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ',
44633         '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ',
44634         'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ',
44635         '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ',
44636         'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ',
44637         '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ',
44638         'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ',
44639         '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ',
44640         '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ',
44641         '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ',
44642         '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ',
44643         'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ',
44644         '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ',
44645         'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ',
44646         '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ',
44647         'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ',
44648         '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ',
44649         'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ',
44650         '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ',
44651         'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'
44652       ].join('');
44653
44654       crc = crc ^ (-1);
44655       for (i = 0, iTop = str.length; i < iTop; i += 1) {
44656         y = (crc ^ str.charCodeAt(i)) & 0xFF;
44657         x = '0x' + table.substr(y * 9, 8);
44658         crc = (crc >>> 8) ^ x;
44659       }
44660       // always return a positive number (that's what >>> 0 does)
44661       return (crc ^ (-1)) >>> 0;
44662     },
44663     /**
44664      * @member Hashes
44665      * @class MD5
44666      * @constructor
44667      * @param {Object} [config]
44668      *
44669      * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
44670      * Digest Algorithm, as defined in RFC 1321.
44671      * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
44672      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
44673      * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
44674      */
44675     MD5: function(options) {
44676       /**
44677        * Private config properties. You may need to tweak these to be compatible with
44678        * the server-side, but the defaults work in most cases.
44679        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
44680        */
44681       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
44682         b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
44683         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
44684
44685       // privileged (public) methods
44686       this.hex = function(s) {
44687         return rstr2hex(rstr(s, utf8), hexcase);
44688       };
44689       this.b64 = function(s) {
44690         return rstr2b64(rstr(s), b64pad);
44691       };
44692       this.any = function(s, e) {
44693         return rstr2any(rstr(s, utf8), e);
44694       };
44695       this.raw = function(s) {
44696         return rstr(s, utf8);
44697       };
44698       this.hex_hmac = function(k, d) {
44699         return rstr2hex(rstr_hmac(k, d), hexcase);
44700       };
44701       this.b64_hmac = function(k, d) {
44702         return rstr2b64(rstr_hmac(k, d), b64pad);
44703       };
44704       this.any_hmac = function(k, d, e) {
44705         return rstr2any(rstr_hmac(k, d), e);
44706       };
44707       /**
44708        * Perform a simple self-test to see if the VM is working
44709        * @return {String} Hexadecimal hash sample
44710        */
44711       this.vm_test = function() {
44712         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
44713       };
44714       /**
44715        * Enable/disable uppercase hexadecimal returned string
44716        * @param {Boolean}
44717        * @return {Object} this
44718        */
44719       this.setUpperCase = function(a) {
44720         if (typeof a === 'boolean') {
44721           hexcase = a;
44722         }
44723         return this;
44724       };
44725       /**
44726        * Defines a base64 pad string
44727        * @param {String} Pad
44728        * @return {Object} this
44729        */
44730       this.setPad = function(a) {
44731         b64pad = a || b64pad;
44732         return this;
44733       };
44734       /**
44735        * Defines a base64 pad string
44736        * @param {Boolean}
44737        * @return {Object} [this]
44738        */
44739       this.setUTF8 = function(a) {
44740         if (typeof a === 'boolean') {
44741           utf8 = a;
44742         }
44743         return this;
44744       };
44745
44746       // private methods
44747
44748       /**
44749        * Calculate the MD5 of a raw string
44750        */
44751
44752       function rstr(s) {
44753         s = (utf8) ? utf8Encode(s) : s;
44754         return binl2rstr(binl(rstr2binl(s), s.length * 8));
44755       }
44756
44757       /**
44758        * Calculate the HMAC-MD5, of a key and some data (raw strings)
44759        */
44760
44761       function rstr_hmac(key, data) {
44762         var bkey, ipad, opad, hash, i;
44763
44764         key = (utf8) ? utf8Encode(key) : key;
44765         data = (utf8) ? utf8Encode(data) : data;
44766         bkey = rstr2binl(key);
44767         if (bkey.length > 16) {
44768           bkey = binl(bkey, key.length * 8);
44769         }
44770
44771         ipad = Array(16), opad = Array(16);
44772         for (i = 0; i < 16; i += 1) {
44773           ipad[i] = bkey[i] ^ 0x36363636;
44774           opad[i] = bkey[i] ^ 0x5C5C5C5C;
44775         }
44776         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
44777         return binl2rstr(binl(opad.concat(hash), 512 + 128));
44778       }
44779
44780       /**
44781        * Calculate the MD5 of an array of little-endian words, and a bit length.
44782        */
44783
44784       function binl(x, len) {
44785         var i, olda, oldb, oldc, oldd,
44786           a = 1732584193,
44787           b = -271733879,
44788           c = -1732584194,
44789           d = 271733878;
44790
44791         /* append padding */
44792         x[len >> 5] |= 0x80 << ((len) % 32);
44793         x[(((len + 64) >>> 9) << 4) + 14] = len;
44794
44795         for (i = 0; i < x.length; i += 16) {
44796           olda = a;
44797           oldb = b;
44798           oldc = c;
44799           oldd = d;
44800
44801           a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
44802           d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
44803           c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
44804           b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
44805           a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
44806           d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
44807           c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
44808           b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
44809           a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
44810           d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
44811           c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
44812           b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
44813           a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
44814           d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
44815           c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
44816           b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
44817
44818           a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
44819           d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
44820           c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
44821           b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
44822           a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
44823           d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
44824           c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
44825           b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
44826           a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
44827           d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
44828           c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
44829           b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
44830           a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
44831           d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
44832           c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
44833           b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
44834
44835           a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
44836           d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
44837           c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
44838           b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
44839           a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
44840           d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
44841           c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
44842           b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
44843           a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
44844           d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
44845           c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
44846           b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
44847           a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
44848           d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
44849           c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
44850           b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
44851
44852           a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
44853           d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
44854           c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
44855           b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
44856           a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
44857           d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
44858           c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
44859           b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
44860           a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
44861           d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
44862           c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
44863           b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
44864           a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
44865           d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
44866           c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
44867           b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
44868
44869           a = safe_add(a, olda);
44870           b = safe_add(b, oldb);
44871           c = safe_add(c, oldc);
44872           d = safe_add(d, oldd);
44873         }
44874         return Array(a, b, c, d);
44875       }
44876
44877       /**
44878        * These functions implement the four basic operations the algorithm uses.
44879        */
44880
44881       function md5_cmn(q, a, b, x, s, t) {
44882         return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
44883       }
44884
44885       function md5_ff(a, b, c, d, x, s, t) {
44886         return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
44887       }
44888
44889       function md5_gg(a, b, c, d, x, s, t) {
44890         return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
44891       }
44892
44893       function md5_hh(a, b, c, d, x, s, t) {
44894         return md5_cmn(b ^ c ^ d, a, b, x, s, t);
44895       }
44896
44897       function md5_ii(a, b, c, d, x, s, t) {
44898         return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
44899       }
44900     },
44901     /**
44902      * @member Hashes
44903      * @class Hashes.SHA1
44904      * @param {Object} [config]
44905      * @constructor
44906      *
44907      * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
44908      * Version 2.2 Copyright Paul Johnston 2000 - 2009.
44909      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
44910      * See http://pajhome.org.uk/crypt/md5 for details.
44911      */
44912     SHA1: function(options) {
44913       /**
44914        * Private config properties. You may need to tweak these to be compatible with
44915        * the server-side, but the defaults work in most cases.
44916        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
44917        */
44918       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
44919         b64pad = (options && typeof options.pad === 'string') ? options.pda : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
44920         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
44921
44922       // public methods
44923       this.hex = function(s) {
44924         return rstr2hex(rstr(s, utf8), hexcase);
44925       };
44926       this.b64 = function(s) {
44927         return rstr2b64(rstr(s, utf8), b64pad);
44928       };
44929       this.any = function(s, e) {
44930         return rstr2any(rstr(s, utf8), e);
44931       };
44932       this.raw = function(s) {
44933         return rstr(s, utf8);
44934       };
44935       this.hex_hmac = function(k, d) {
44936         return rstr2hex(rstr_hmac(k, d));
44937       };
44938       this.b64_hmac = function(k, d) {
44939         return rstr2b64(rstr_hmac(k, d), b64pad);
44940       };
44941       this.any_hmac = function(k, d, e) {
44942         return rstr2any(rstr_hmac(k, d), e);
44943       };
44944       /**
44945        * Perform a simple self-test to see if the VM is working
44946        * @return {String} Hexadecimal hash sample
44947        * @public
44948        */
44949       this.vm_test = function() {
44950         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
44951       };
44952       /**
44953        * @description Enable/disable uppercase hexadecimal returned string
44954        * @param {boolean}
44955        * @return {Object} this
44956        * @public
44957        */
44958       this.setUpperCase = function(a) {
44959         if (typeof a === 'boolean') {
44960           hexcase = a;
44961         }
44962         return this;
44963       };
44964       /**
44965        * @description Defines a base64 pad string
44966        * @param {string} Pad
44967        * @return {Object} this
44968        * @public
44969        */
44970       this.setPad = function(a) {
44971         b64pad = a || b64pad;
44972         return this;
44973       };
44974       /**
44975        * @description Defines a base64 pad string
44976        * @param {boolean}
44977        * @return {Object} this
44978        * @public
44979        */
44980       this.setUTF8 = function(a) {
44981         if (typeof a === 'boolean') {
44982           utf8 = a;
44983         }
44984         return this;
44985       };
44986
44987       // private methods
44988
44989       /**
44990        * Calculate the SHA-512 of a raw string
44991        */
44992
44993       function rstr(s) {
44994         s = (utf8) ? utf8Encode(s) : s;
44995         return binb2rstr(binb(rstr2binb(s), s.length * 8));
44996       }
44997
44998       /**
44999        * Calculate the HMAC-SHA1 of a key and some data (raw strings)
45000        */
45001
45002       function rstr_hmac(key, data) {
45003         var bkey, ipad, opad, i, hash;
45004         key = (utf8) ? utf8Encode(key) : key;
45005         data = (utf8) ? utf8Encode(data) : data;
45006         bkey = rstr2binb(key);
45007
45008         if (bkey.length > 16) {
45009           bkey = binb(bkey, key.length * 8);
45010         }
45011         ipad = Array(16), opad = Array(16);
45012         for (i = 0; i < 16; i += 1) {
45013           ipad[i] = bkey[i] ^ 0x36363636;
45014           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45015         }
45016         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45017         return binb2rstr(binb(opad.concat(hash), 512 + 160));
45018       }
45019
45020       /**
45021        * Calculate the SHA-1 of an array of big-endian words, and a bit length
45022        */
45023
45024       function binb(x, len) {
45025         var i, j, t, olda, oldb, oldc, oldd, olde,
45026           w = Array(80),
45027           a = 1732584193,
45028           b = -271733879,
45029           c = -1732584194,
45030           d = 271733878,
45031           e = -1009589776;
45032
45033         /* append padding */
45034         x[len >> 5] |= 0x80 << (24 - len % 32);
45035         x[((len + 64 >> 9) << 4) + 15] = len;
45036
45037         for (i = 0; i < x.length; i += 16) {
45038           olda = a,
45039           oldb = b;
45040           oldc = c;
45041           oldd = d;
45042           olde = e;
45043
45044           for (j = 0; j < 80; j += 1) {
45045             if (j < 16) {
45046               w[j] = x[i + j];
45047             } else {
45048               w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
45049             }
45050             t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
45051               safe_add(safe_add(e, w[j]), sha1_kt(j)));
45052             e = d;
45053             d = c;
45054             c = bit_rol(b, 30);
45055             b = a;
45056             a = t;
45057           }
45058
45059           a = safe_add(a, olda);
45060           b = safe_add(b, oldb);
45061           c = safe_add(c, oldc);
45062           d = safe_add(d, oldd);
45063           e = safe_add(e, olde);
45064         }
45065         return Array(a, b, c, d, e);
45066       }
45067
45068       /**
45069        * Perform the appropriate triplet combination function for the current
45070        * iteration
45071        */
45072
45073       function sha1_ft(t, b, c, d) {
45074         if (t < 20) {
45075           return (b & c) | ((~b) & d);
45076         }
45077         if (t < 40) {
45078           return b ^ c ^ d;
45079         }
45080         if (t < 60) {
45081           return (b & c) | (b & d) | (c & d);
45082         }
45083         return b ^ c ^ d;
45084       }
45085
45086       /**
45087        * Determine the appropriate additive constant for the current iteration
45088        */
45089
45090       function sha1_kt(t) {
45091         return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
45092           (t < 60) ? -1894007588 : -899497514;
45093       }
45094     },
45095     /**
45096      * @class Hashes.SHA256
45097      * @param {config}
45098      *
45099      * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
45100      * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
45101      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45102      * See http://pajhome.org.uk/crypt/md5 for details.
45103      * Also http://anmar.eu.org/projects/jssha2/
45104      */
45105     SHA256: function(options) {
45106       /**
45107        * Private properties configuration variables. You may need to tweak these to be compatible with
45108        * the server-side, but the defaults work in most cases.
45109        * @see this.setUpperCase() method
45110        * @see this.setPad() method
45111        */
45112       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase  */
45113         b64pad = (options && typeof options.pad === 'string') ? options.pda : '=',
45114         /* base-64 pad character. Default '=' for strict RFC compliance   */
45115         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45116         /* enable/disable utf8 encoding */
45117         sha256_K;
45118
45119       /* privileged (public) methods */
45120       this.hex = function(s) {
45121         return rstr2hex(rstr(s, utf8));
45122       };
45123       this.b64 = function(s) {
45124         return rstr2b64(rstr(s, utf8), b64pad);
45125       };
45126       this.any = function(s, e) {
45127         return rstr2any(rstr(s, utf8), e);
45128       };
45129       this.raw = function(s) {
45130         return rstr(s, utf8);
45131       };
45132       this.hex_hmac = function(k, d) {
45133         return rstr2hex(rstr_hmac(k, d));
45134       };
45135       this.b64_hmac = function(k, d) {
45136         return rstr2b64(rstr_hmac(k, d), b64pad);
45137       };
45138       this.any_hmac = function(k, d, e) {
45139         return rstr2any(rstr_hmac(k, d), e);
45140       };
45141       /**
45142        * Perform a simple self-test to see if the VM is working
45143        * @return {String} Hexadecimal hash sample
45144        * @public
45145        */
45146       this.vm_test = function() {
45147         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45148       };
45149       /**
45150        * Enable/disable uppercase hexadecimal returned string
45151        * @param {boolean}
45152        * @return {Object} this
45153        * @public
45154        */
45155       this.setUpperCase = function(a) {
45156         if (typeof a === 'boolean') {
45157           hexcase = a;
45158         }
45159         return this;
45160       };
45161       /**
45162        * @description Defines a base64 pad string
45163        * @param {string} Pad
45164        * @return {Object} this
45165        * @public
45166        */
45167       this.setPad = function(a) {
45168         b64pad = a || b64pad;
45169         return this;
45170       };
45171       /**
45172        * Defines a base64 pad string
45173        * @param {boolean}
45174        * @return {Object} this
45175        * @public
45176        */
45177       this.setUTF8 = function(a) {
45178         if (typeof a === 'boolean') {
45179           utf8 = a;
45180         }
45181         return this;
45182       };
45183
45184       // private methods
45185
45186       /**
45187        * Calculate the SHA-512 of a raw string
45188        */
45189
45190       function rstr(s, utf8) {
45191         s = (utf8) ? utf8Encode(s) : s;
45192         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45193       }
45194
45195       /**
45196        * Calculate the HMAC-sha256 of a key and some data (raw strings)
45197        */
45198
45199       function rstr_hmac(key, data) {
45200         key = (utf8) ? utf8Encode(key) : key;
45201         data = (utf8) ? utf8Encode(data) : data;
45202         var hash, i = 0,
45203           bkey = rstr2binb(key),
45204           ipad = Array(16),
45205           opad = Array(16);
45206
45207         if (bkey.length > 16) {
45208           bkey = binb(bkey, key.length * 8);
45209         }
45210
45211         for (; i < 16; i += 1) {
45212           ipad[i] = bkey[i] ^ 0x36363636;
45213           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45214         }
45215
45216         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45217         return binb2rstr(binb(opad.concat(hash), 512 + 256));
45218       }
45219
45220       /*
45221        * Main sha256 function, with its support functions
45222        */
45223
45224       function sha256_S(X, n) {
45225         return (X >>> n) | (X << (32 - n));
45226       }
45227
45228       function sha256_R(X, n) {
45229         return (X >>> n);
45230       }
45231
45232       function sha256_Ch(x, y, z) {
45233         return ((x & y) ^ ((~x) & z));
45234       }
45235
45236       function sha256_Maj(x, y, z) {
45237         return ((x & y) ^ (x & z) ^ (y & z));
45238       }
45239
45240       function sha256_Sigma0256(x) {
45241         return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));
45242       }
45243
45244       function sha256_Sigma1256(x) {
45245         return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));
45246       }
45247
45248       function sha256_Gamma0256(x) {
45249         return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));
45250       }
45251
45252       function sha256_Gamma1256(x) {
45253         return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));
45254       }
45255
45256       sha256_K = [
45257         1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
45258         1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
45259         264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
45260         113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
45261         1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
45262         430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
45263         1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998
45264       ];
45265
45266       function binb(m, l) {
45267         var HASH = [1779033703, -1150833019, 1013904242, -1521486534,
45268           1359893119, -1694144372, 528734635, 1541459225
45269         ];
45270         var W = new Array(64);
45271         var a, b, c, d, e, f, g, h;
45272         var i, j, T1, T2;
45273
45274         /* append padding */
45275         m[l >> 5] |= 0x80 << (24 - l % 32);
45276         m[((l + 64 >> 9) << 4) + 15] = l;
45277
45278         for (i = 0; i < m.length; i += 16) {
45279           a = HASH[0];
45280           b = HASH[1];
45281           c = HASH[2];
45282           d = HASH[3];
45283           e = HASH[4];
45284           f = HASH[5];
45285           g = HASH[6];
45286           h = HASH[7];
45287
45288           for (j = 0; j < 64; j += 1) {
45289             if (j < 16) {
45290               W[j] = m[j + i];
45291             } else {
45292               W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
45293                 sha256_Gamma0256(W[j - 15])), W[j - 16]);
45294             }
45295
45296             T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
45297               sha256_K[j]), W[j]);
45298             T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
45299             h = g;
45300             g = f;
45301             f = e;
45302             e = safe_add(d, T1);
45303             d = c;
45304             c = b;
45305             b = a;
45306             a = safe_add(T1, T2);
45307           }
45308
45309           HASH[0] = safe_add(a, HASH[0]);
45310           HASH[1] = safe_add(b, HASH[1]);
45311           HASH[2] = safe_add(c, HASH[2]);
45312           HASH[3] = safe_add(d, HASH[3]);
45313           HASH[4] = safe_add(e, HASH[4]);
45314           HASH[5] = safe_add(f, HASH[5]);
45315           HASH[6] = safe_add(g, HASH[6]);
45316           HASH[7] = safe_add(h, HASH[7]);
45317         }
45318         return HASH;
45319       }
45320
45321     },
45322
45323     /**
45324      * @class Hashes.SHA512
45325      * @param {config}
45326      *
45327      * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
45328      * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
45329      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45330      * See http://pajhome.org.uk/crypt/md5 for details.
45331      */
45332     SHA512: function(options) {
45333       /**
45334        * Private properties configuration variables. You may need to tweak these to be compatible with
45335        * the server-side, but the defaults work in most cases.
45336        * @see this.setUpperCase() method
45337        * @see this.setPad() method
45338        */
45339       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
45340         /* hexadecimal output case format. false - lowercase; true - uppercase  */
45341         b64pad = (options && typeof options.pad === 'string') ? options.pda : '=',
45342         /* base-64 pad character. Default '=' for strict RFC compliance   */
45343         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45344         /* enable/disable utf8 encoding */
45345         sha512_k;
45346
45347       /* privileged (public) methods */
45348       this.hex = function(s) {
45349         return rstr2hex(rstr(s));
45350       };
45351       this.b64 = function(s) {
45352         return rstr2b64(rstr(s), b64pad);
45353       };
45354       this.any = function(s, e) {
45355         return rstr2any(rstr(s), e);
45356       };
45357       this.raw = function(s) {
45358         return rstr(s, utf8);
45359       };
45360       this.hex_hmac = function(k, d) {
45361         return rstr2hex(rstr_hmac(k, d));
45362       };
45363       this.b64_hmac = function(k, d) {
45364         return rstr2b64(rstr_hmac(k, d), b64pad);
45365       };
45366       this.any_hmac = function(k, d, e) {
45367         return rstr2any(rstr_hmac(k, d), e);
45368       };
45369       /**
45370        * Perform a simple self-test to see if the VM is working
45371        * @return {String} Hexadecimal hash sample
45372        * @public
45373        */
45374       this.vm_test = function() {
45375         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45376       };
45377       /**
45378        * @description Enable/disable uppercase hexadecimal returned string
45379        * @param {boolean}
45380        * @return {Object} this
45381        * @public
45382        */
45383       this.setUpperCase = function(a) {
45384         if (typeof a === 'boolean') {
45385           hexcase = a;
45386         }
45387         return this;
45388       };
45389       /**
45390        * @description Defines a base64 pad string
45391        * @param {string} Pad
45392        * @return {Object} this
45393        * @public
45394        */
45395       this.setPad = function(a) {
45396         b64pad = a || b64pad;
45397         return this;
45398       };
45399       /**
45400        * @description Defines a base64 pad string
45401        * @param {boolean}
45402        * @return {Object} this
45403        * @public
45404        */
45405       this.setUTF8 = function(a) {
45406         if (typeof a === 'boolean') {
45407           utf8 = a;
45408         }
45409         return this;
45410       };
45411
45412       /* private methods */
45413
45414       /**
45415        * Calculate the SHA-512 of a raw string
45416        */
45417
45418       function rstr(s) {
45419         s = (utf8) ? utf8Encode(s) : s;
45420         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45421       }
45422       /*
45423        * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
45424        */
45425
45426       function rstr_hmac(key, data) {
45427         key = (utf8) ? utf8Encode(key) : key;
45428         data = (utf8) ? utf8Encode(data) : data;
45429
45430         var hash, i = 0,
45431           bkey = rstr2binb(key),
45432           ipad = Array(32),
45433           opad = Array(32);
45434
45435         if (bkey.length > 32) {
45436           bkey = binb(bkey, key.length * 8);
45437         }
45438
45439         for (; i < 32; i += 1) {
45440           ipad[i] = bkey[i] ^ 0x36363636;
45441           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45442         }
45443
45444         hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
45445         return binb2rstr(binb(opad.concat(hash), 1024 + 512));
45446       }
45447
45448       /**
45449        * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
45450        */
45451
45452       function binb(x, len) {
45453         var j, i, l,
45454           W = new Array(80),
45455           hash = new Array(16),
45456           //Initial hash values
45457           H = [
45458             new int64(0x6a09e667, -205731576),
45459             new int64(-1150833019, -2067093701),
45460             new int64(0x3c6ef372, -23791573),
45461             new int64(-1521486534, 0x5f1d36f1),
45462             new int64(0x510e527f, -1377402159),
45463             new int64(-1694144372, 0x2b3e6c1f),
45464             new int64(0x1f83d9ab, -79577749),
45465             new int64(0x5be0cd19, 0x137e2179)
45466           ],
45467           T1 = new int64(0, 0),
45468           T2 = new int64(0, 0),
45469           a = new int64(0, 0),
45470           b = new int64(0, 0),
45471           c = new int64(0, 0),
45472           d = new int64(0, 0),
45473           e = new int64(0, 0),
45474           f = new int64(0, 0),
45475           g = new int64(0, 0),
45476           h = new int64(0, 0),
45477           //Temporary variables not specified by the document
45478           s0 = new int64(0, 0),
45479           s1 = new int64(0, 0),
45480           Ch = new int64(0, 0),
45481           Maj = new int64(0, 0),
45482           r1 = new int64(0, 0),
45483           r2 = new int64(0, 0),
45484           r3 = new int64(0, 0);
45485
45486         if (sha512_k === undefined) {
45487           //SHA512 constants
45488           sha512_k = [
45489             new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
45490             new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
45491             new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
45492             new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
45493             new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
45494             new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
45495             new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
45496             new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
45497             new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
45498             new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
45499             new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
45500             new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
45501             new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
45502             new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
45503             new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
45504             new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
45505             new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
45506             new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
45507             new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
45508             new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
45509             new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
45510             new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
45511             new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
45512             new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
45513             new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
45514             new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
45515             new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
45516             new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
45517             new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
45518             new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
45519             new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
45520             new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
45521             new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
45522             new int64(-354779690, -840897762), new int64(-176337025, -294727304),
45523             new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
45524             new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
45525             new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
45526             new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
45527             new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
45528             new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)
45529           ];
45530         }
45531
45532         for (i = 0; i < 80; i += 1) {
45533           W[i] = new int64(0, 0);
45534         }
45535
45536         // append padding to the source string. The format is described in the FIPS.
45537         x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
45538         x[((len + 128 >> 10) << 5) + 31] = len;
45539         l = x.length;
45540         for (i = 0; i < l; i += 32) { //32 dwords is the block size
45541           int64copy(a, H[0]);
45542           int64copy(b, H[1]);
45543           int64copy(c, H[2]);
45544           int64copy(d, H[3]);
45545           int64copy(e, H[4]);
45546           int64copy(f, H[5]);
45547           int64copy(g, H[6]);
45548           int64copy(h, H[7]);
45549
45550           for (j = 0; j < 16; j += 1) {
45551             W[j].h = x[i + 2 * j];
45552             W[j].l = x[i + 2 * j + 1];
45553           }
45554
45555           for (j = 16; j < 80; j += 1) {
45556             //sigma1
45557             int64rrot(r1, W[j - 2], 19);
45558             int64revrrot(r2, W[j - 2], 29);
45559             int64shr(r3, W[j - 2], 6);
45560             s1.l = r1.l ^ r2.l ^ r3.l;
45561             s1.h = r1.h ^ r2.h ^ r3.h;
45562             //sigma0
45563             int64rrot(r1, W[j - 15], 1);
45564             int64rrot(r2, W[j - 15], 8);
45565             int64shr(r3, W[j - 15], 7);
45566             s0.l = r1.l ^ r2.l ^ r3.l;
45567             s0.h = r1.h ^ r2.h ^ r3.h;
45568
45569             int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
45570           }
45571
45572           for (j = 0; j < 80; j += 1) {
45573             //Ch
45574             Ch.l = (e.l & f.l) ^ (~e.l & g.l);
45575             Ch.h = (e.h & f.h) ^ (~e.h & g.h);
45576
45577             //Sigma1
45578             int64rrot(r1, e, 14);
45579             int64rrot(r2, e, 18);
45580             int64revrrot(r3, e, 9);
45581             s1.l = r1.l ^ r2.l ^ r3.l;
45582             s1.h = r1.h ^ r2.h ^ r3.h;
45583
45584             //Sigma0
45585             int64rrot(r1, a, 28);
45586             int64revrrot(r2, a, 2);
45587             int64revrrot(r3, a, 7);
45588             s0.l = r1.l ^ r2.l ^ r3.l;
45589             s0.h = r1.h ^ r2.h ^ r3.h;
45590
45591             //Maj
45592             Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
45593             Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
45594
45595             int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
45596             int64add(T2, s0, Maj);
45597
45598             int64copy(h, g);
45599             int64copy(g, f);
45600             int64copy(f, e);
45601             int64add(e, d, T1);
45602             int64copy(d, c);
45603             int64copy(c, b);
45604             int64copy(b, a);
45605             int64add(a, T1, T2);
45606           }
45607           int64add(H[0], H[0], a);
45608           int64add(H[1], H[1], b);
45609           int64add(H[2], H[2], c);
45610           int64add(H[3], H[3], d);
45611           int64add(H[4], H[4], e);
45612           int64add(H[5], H[5], f);
45613           int64add(H[6], H[6], g);
45614           int64add(H[7], H[7], h);
45615         }
45616
45617         //represent the hash as an array of 32-bit dwords
45618         for (i = 0; i < 8; i += 1) {
45619           hash[2 * i] = H[i].h;
45620           hash[2 * i + 1] = H[i].l;
45621         }
45622         return hash;
45623       }
45624
45625       //A constructor for 64-bit numbers
45626
45627       function int64(h, l) {
45628         this.h = h;
45629         this.l = l;
45630         //this.toString = int64toString;
45631       }
45632
45633       //Copies src into dst, assuming both are 64-bit numbers
45634
45635       function int64copy(dst, src) {
45636         dst.h = src.h;
45637         dst.l = src.l;
45638       }
45639
45640       //Right-rotates a 64-bit number by shift
45641       //Won't handle cases of shift>=32
45642       //The function revrrot() is for that
45643
45644       function int64rrot(dst, x, shift) {
45645         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
45646         dst.h = (x.h >>> shift) | (x.l << (32 - shift));
45647       }
45648
45649       //Reverses the dwords of the source and then rotates right by shift.
45650       //This is equivalent to rotation by 32+shift
45651
45652       function int64revrrot(dst, x, shift) {
45653         dst.l = (x.h >>> shift) | (x.l << (32 - shift));
45654         dst.h = (x.l >>> shift) | (x.h << (32 - shift));
45655       }
45656
45657       //Bitwise-shifts right a 64-bit number by shift
45658       //Won't handle shift>=32, but it's never needed in SHA512
45659
45660       function int64shr(dst, x, shift) {
45661         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
45662         dst.h = (x.h >>> shift);
45663       }
45664
45665       //Adds two 64-bit numbers
45666       //Like the original implementation, does not rely on 32-bit operations
45667
45668       function int64add(dst, x, y) {
45669         var w0 = (x.l & 0xffff) + (y.l & 0xffff);
45670         var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
45671         var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
45672         var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
45673         dst.l = (w0 & 0xffff) | (w1 << 16);
45674         dst.h = (w2 & 0xffff) | (w3 << 16);
45675       }
45676
45677       //Same, except with 4 addends. Works faster than adding them one by one.
45678
45679       function int64add4(dst, a, b, c, d) {
45680         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
45681         var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
45682         var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
45683         var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
45684         dst.l = (w0 & 0xffff) | (w1 << 16);
45685         dst.h = (w2 & 0xffff) | (w3 << 16);
45686       }
45687
45688       //Same, except with 5 addends
45689
45690       function int64add5(dst, a, b, c, d, e) {
45691         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
45692           w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
45693           w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
45694           w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
45695         dst.l = (w0 & 0xffff) | (w1 << 16);
45696         dst.h = (w2 & 0xffff) | (w3 << 16);
45697       }
45698     },
45699     /**
45700      * @class Hashes.RMD160
45701      * @constructor
45702      * @param {Object} [config]
45703      *
45704      * A JavaScript implementation of the RIPEMD-160 Algorithm
45705      * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
45706      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45707      * See http://pajhome.org.uk/crypt/md5 for details.
45708      * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
45709      */
45710     RMD160: function(options) {
45711       /**
45712        * Private properties configuration variables. You may need to tweak these to be compatible with
45713        * the server-side, but the defaults work in most cases.
45714        * @see this.setUpperCase() method
45715        * @see this.setPad() method
45716        */
45717       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
45718         /* hexadecimal output case format. false - lowercase; true - uppercase  */
45719         b64pad = (options && typeof options.pad === 'string') ? options.pda : '=',
45720         /* base-64 pad character. Default '=' for strict RFC compliance   */
45721         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45722         /* enable/disable utf8 encoding */
45723         rmd160_r1 = [
45724           0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
45725           7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
45726           3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
45727           1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
45728           4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
45729         ],
45730         rmd160_r2 = [
45731           5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
45732           6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
45733           15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
45734           8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
45735           12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
45736         ],
45737         rmd160_s1 = [
45738           11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
45739           7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
45740           11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
45741           11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
45742           9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
45743         ],
45744         rmd160_s2 = [
45745           8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
45746           9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
45747           9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
45748           15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
45749           8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
45750         ];
45751
45752       /* privileged (public) methods */
45753       this.hex = function(s) {
45754         return rstr2hex(rstr(s, utf8));
45755       };
45756       this.b64 = function(s) {
45757         return rstr2b64(rstr(s, utf8), b64pad);
45758       };
45759       this.any = function(s, e) {
45760         return rstr2any(rstr(s, utf8), e);
45761       };
45762       this.raw = function(s) {
45763         return rstr(s, utf8);
45764       };
45765       this.hex_hmac = function(k, d) {
45766         return rstr2hex(rstr_hmac(k, d));
45767       };
45768       this.b64_hmac = function(k, d) {
45769         return rstr2b64(rstr_hmac(k, d), b64pad);
45770       };
45771       this.any_hmac = function(k, d, e) {
45772         return rstr2any(rstr_hmac(k, d), e);
45773       };
45774       /**
45775        * Perform a simple self-test to see if the VM is working
45776        * @return {String} Hexadecimal hash sample
45777        * @public
45778        */
45779       this.vm_test = function() {
45780         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45781       };
45782       /**
45783        * @description Enable/disable uppercase hexadecimal returned string
45784        * @param {boolean}
45785        * @return {Object} this
45786        * @public
45787        */
45788       this.setUpperCase = function(a) {
45789         if (typeof a === 'boolean') {
45790           hexcase = a;
45791         }
45792         return this;
45793       };
45794       /**
45795        * @description Defines a base64 pad string
45796        * @param {string} Pad
45797        * @return {Object} this
45798        * @public
45799        */
45800       this.setPad = function(a) {
45801         if (typeof a !== 'undefined') {
45802           b64pad = a;
45803         }
45804         return this;
45805       };
45806       /**
45807        * @description Defines a base64 pad string
45808        * @param {boolean}
45809        * @return {Object} this
45810        * @public
45811        */
45812       this.setUTF8 = function(a) {
45813         if (typeof a === 'boolean') {
45814           utf8 = a;
45815         }
45816         return this;
45817       };
45818
45819       /* private methods */
45820
45821       /**
45822        * Calculate the rmd160 of a raw string
45823        */
45824
45825       function rstr(s) {
45826         s = (utf8) ? utf8Encode(s) : s;
45827         return binl2rstr(binl(rstr2binl(s), s.length * 8));
45828       }
45829
45830       /**
45831        * Calculate the HMAC-rmd160 of a key and some data (raw strings)
45832        */
45833
45834       function rstr_hmac(key, data) {
45835         key = (utf8) ? utf8Encode(key) : key;
45836         data = (utf8) ? utf8Encode(data) : data;
45837         var i, hash,
45838           bkey = rstr2binl(key),
45839           ipad = Array(16),
45840           opad = Array(16);
45841
45842         if (bkey.length > 16) {
45843           bkey = binl(bkey, key.length * 8);
45844         }
45845
45846         for (i = 0; i < 16; i += 1) {
45847           ipad[i] = bkey[i] ^ 0x36363636;
45848           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45849         }
45850         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
45851         return binl2rstr(binl(opad.concat(hash), 512 + 160));
45852       }
45853
45854       /**
45855        * Convert an array of little-endian words to a string
45856        */
45857
45858       function binl2rstr(input) {
45859         var i, output = '',
45860           l = input.length * 32;
45861         for (i = 0; i < l; i += 8) {
45862           output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
45863         }
45864         return output;
45865       }
45866
45867       /**
45868        * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
45869        */
45870
45871       function binl(x, len) {
45872         var T, j, i, l,
45873           h0 = 0x67452301,
45874           h1 = 0xefcdab89,
45875           h2 = 0x98badcfe,
45876           h3 = 0x10325476,
45877           h4 = 0xc3d2e1f0,
45878           A1, B1, C1, D1, E1,
45879           A2, B2, C2, D2, E2;
45880
45881         /* append padding */
45882         x[len >> 5] |= 0x80 << (len % 32);
45883         x[(((len + 64) >>> 9) << 4) + 14] = len;
45884         l = x.length;
45885
45886         for (i = 0; i < l; i += 16) {
45887           A1 = A2 = h0;
45888           B1 = B2 = h1;
45889           C1 = C2 = h2;
45890           D1 = D2 = h3;
45891           E1 = E2 = h4;
45892           for (j = 0; j <= 79; j += 1) {
45893             T = safe_add(A1, rmd160_f(j, B1, C1, D1));
45894             T = safe_add(T, x[i + rmd160_r1[j]]);
45895             T = safe_add(T, rmd160_K1(j));
45896             T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
45897             A1 = E1;
45898             E1 = D1;
45899             D1 = bit_rol(C1, 10);
45900             C1 = B1;
45901             B1 = T;
45902             T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
45903             T = safe_add(T, x[i + rmd160_r2[j]]);
45904             T = safe_add(T, rmd160_K2(j));
45905             T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
45906             A2 = E2;
45907             E2 = D2;
45908             D2 = bit_rol(C2, 10);
45909             C2 = B2;
45910             B2 = T;
45911           }
45912
45913           T = safe_add(h1, safe_add(C1, D2));
45914           h1 = safe_add(h2, safe_add(D1, E2));
45915           h2 = safe_add(h3, safe_add(E1, A2));
45916           h3 = safe_add(h4, safe_add(A1, B2));
45917           h4 = safe_add(h0, safe_add(B1, C2));
45918           h0 = T;
45919         }
45920         return [h0, h1, h2, h3, h4];
45921       }
45922
45923       // specific algorithm methods
45924
45925       function rmd160_f(j, x, y, z) {
45926         return (0 <= j && j <= 15) ? (x ^ y ^ z) :
45927           (16 <= j && j <= 31) ? (x & y) | (~x & z) :
45928           (32 <= j && j <= 47) ? (x | ~y) ^ z :
45929           (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
45930           (64 <= j && j <= 79) ? x ^ (y | ~z) :
45931           'rmd160_f: j out of range';
45932       }
45933
45934       function rmd160_K1(j) {
45935         return (0 <= j && j <= 15) ? 0x00000000 :
45936           (16 <= j && j <= 31) ? 0x5a827999 :
45937           (32 <= j && j <= 47) ? 0x6ed9eba1 :
45938           (48 <= j && j <= 63) ? 0x8f1bbcdc :
45939           (64 <= j && j <= 79) ? 0xa953fd4e :
45940           'rmd160_K1: j out of range';
45941       }
45942
45943       function rmd160_K2(j) {
45944         return (0 <= j && j <= 15) ? 0x50a28be6 :
45945           (16 <= j && j <= 31) ? 0x5c4dd124 :
45946           (32 <= j && j <= 47) ? 0x6d703ef3 :
45947           (48 <= j && j <= 63) ? 0x7a6d76e9 :
45948           (64 <= j && j <= 79) ? 0x00000000 :
45949           'rmd160_K2: j out of range';
45950       }
45951     }
45952   };
45953
45954   // exposes Hashes
45955   (function(window, undefined) {
45956     var freeExports = false;
45957     {
45958       freeExports = exports;
45959       if (exports && typeof commonjsGlobal === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
45960         window = commonjsGlobal;
45961       }
45962     }
45963
45964     if (typeof undefined === 'function' && typeof undefined.amd === 'object' && undefined.amd) {
45965       // define as an anonymous module, so, through path mapping, it can be aliased
45966       undefined(function() {
45967         return Hashes;
45968       });
45969     } else if (freeExports) {
45970       // in Node.js or RingoJS v0.8.0+
45971       if ('object' === 'object' && module && module.exports === freeExports) {
45972         module.exports = Hashes;
45973       }
45974       // in Narwhal or RingoJS v0.7.0-
45975       else {
45976         freeExports.Hashes = Hashes;
45977       }
45978     } else {
45979       // in a browser or Rhino
45980       window.Hashes = Hashes;
45981     }
45982   }(this));
45983 }()); // IIFE
45984 });
45985
45986 var immutable = extend$2;
45987
45988 var hasOwnProperty = Object.prototype.hasOwnProperty;
45989
45990 function extend$2() {
45991     var target = {};
45992
45993     for (var i = 0; i < arguments.length; i++) {
45994         var source = arguments[i];
45995
45996         for (var key in source) {
45997             if (hasOwnProperty.call(source, key)) {
45998                 target[key] = source[key];
45999             }
46000         }
46001     }
46002
46003     return target
46004 }
46005
46006 var sha1 = new hashes.SHA1();
46007
46008 var ohauth = {};
46009
46010 ohauth.qsString = function(obj) {
46011     return Object.keys(obj).sort().map(function(key) {
46012         return ohauth.percentEncode(key) + '=' +
46013             ohauth.percentEncode(obj[key]);
46014     }).join('&');
46015 };
46016
46017 ohauth.stringQs = function(str) {
46018     return str.split('&').filter(function (pair) {
46019         return pair !== '';
46020     }).reduce(function(obj, pair){
46021         var parts = pair.split('=');
46022         obj[decodeURIComponent(parts[0])] = (null === parts[1]) ?
46023             '' : decodeURIComponent(parts[1]);
46024         return obj;
46025     }, {});
46026 };
46027
46028 ohauth.rawxhr = function(method, url, data, headers, callback) {
46029     var xhr = new XMLHttpRequest(),
46030         twoHundred = /^20\d$/;
46031     xhr.onreadystatechange = function() {
46032         if (4 === xhr.readyState && 0 !== xhr.status) {
46033             if (twoHundred.test(xhr.status)) callback(null, xhr);
46034             else return callback(xhr, null);
46035         }
46036     };
46037     xhr.onerror = function(e) { return callback(e, null); };
46038     xhr.open(method, url, true);
46039     for (var h in headers) xhr.setRequestHeader(h, headers[h]);
46040     xhr.send(data);
46041     return xhr;
46042 };
46043
46044 ohauth.xhr = function(method, url, auth, data, options, callback) {
46045     var headers = (options && options.header) || {
46046         'Content-Type': 'application/x-www-form-urlencoded'
46047     };
46048     headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
46049     return ohauth.rawxhr(method, url, data, headers, callback);
46050 };
46051
46052 ohauth.nonce = function() {
46053     for (var o = ''; o.length < 6;) {
46054         o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
46055     }
46056     return o;
46057 };
46058
46059 ohauth.authHeader = function(obj) {
46060     return Object.keys(obj).sort().map(function(key) {
46061         return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
46062     }).join(', ');
46063 };
46064
46065 ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
46066
46067 ohauth.percentEncode = function(s) {
46068     return encodeURIComponent(s)
46069         .replace(/\!/g, '%21').replace(/\'/g, '%27')
46070         .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
46071 };
46072
46073 ohauth.baseString = function(method, url, params) {
46074     if (params.oauth_signature) delete params.oauth_signature;
46075     return [
46076         method,
46077         ohauth.percentEncode(url),
46078         ohauth.percentEncode(ohauth.qsString(params))].join('&');
46079 };
46080
46081 ohauth.signature = function(oauth_secret, token_secret, baseString) {
46082     return sha1.b64_hmac(
46083         ohauth.percentEncode(oauth_secret) + '&' +
46084         ohauth.percentEncode(token_secret),
46085         baseString);
46086 };
46087
46088 /**
46089  * Takes an options object for configuration (consumer_key,
46090  * consumer_secret, version, signature_method, token, token_secret)
46091  * and returns a function that generates the Authorization header
46092  * for given data.
46093  *
46094  * The returned function takes these parameters:
46095  * - method: GET/POST/...
46096  * - uri: full URI with protocol, port, path and query string
46097  * - extra_params: any extra parameters (that are passed in the POST data),
46098  *   can be an object or a from-urlencoded string.
46099  *
46100  * Returned function returns full OAuth header with "OAuth" string in it.
46101  */
46102
46103 ohauth.headerGenerator = function(options) {
46104     options = options || {};
46105     var consumer_key = options.consumer_key || '',
46106         consumer_secret = options.consumer_secret || '',
46107         signature_method = options.signature_method || 'HMAC-SHA1',
46108         version = options.version || '1.0',
46109         token = options.token || '',
46110         token_secret = options.token_secret || '';
46111
46112     return function(method, uri, extra_params) {
46113         method = method.toUpperCase();
46114         if (typeof extra_params === 'string' && extra_params.length > 0) {
46115             extra_params = ohauth.stringQs(extra_params);
46116         }
46117
46118         var uri_parts = uri.split('?', 2),
46119         base_uri = uri_parts[0];
46120
46121         var query_params = uri_parts.length === 2 ?
46122             ohauth.stringQs(uri_parts[1]) : {};
46123
46124         var oauth_params = {
46125             oauth_consumer_key: consumer_key,
46126             oauth_signature_method: signature_method,
46127             oauth_version: version,
46128             oauth_timestamp: ohauth.timestamp(),
46129             oauth_nonce: ohauth.nonce()
46130         };
46131
46132         if (token) oauth_params.oauth_token = token;
46133
46134         var all_params = immutable({}, oauth_params, query_params, extra_params),
46135             base_str = ohauth.baseString(method, base_uri, all_params);
46136
46137         oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
46138
46139         return 'OAuth ' + ohauth.authHeader(oauth_params);
46140     };
46141 };
46142
46143 var index$13 = ohauth;
46144
46145 var store = createCommonjsModule(function (module, exports) {
46146 "use strict"
46147 // Module export pattern from
46148 // https://github.com/umdjs/umd/blob/master/returnExports.js
46149 ;(function (root, factory) {
46150     if (typeof undefined === 'function' && undefined.amd) {
46151         // AMD. Register as an anonymous module.
46152         undefined([], factory);
46153     } else {
46154         // Node. Does not work with strict CommonJS, but
46155         // only CommonJS-like environments that support module.exports,
46156         // like Node.
46157         module.exports = factory();
46158     }
46159 }(commonjsGlobal, function () {
46160         
46161         // Store.js
46162         var store = {},
46163                 win = (typeof window != 'undefined' ? window : commonjsGlobal),
46164                 doc = win.document,
46165                 localStorageName = 'localStorage',
46166                 scriptTag = 'script',
46167                 storage;
46168
46169         store.disabled = false;
46170         store.version = '1.3.20';
46171         store.set = function(key, value) {};
46172         store.get = function(key, defaultVal) {};
46173         store.has = function(key) { return store.get(key) !== undefined };
46174         store.remove = function(key) {};
46175         store.clear = function() {};
46176         store.transact = function(key, defaultVal, transactionFn) {
46177                 if (transactionFn == null) {
46178                         transactionFn = defaultVal;
46179                         defaultVal = null;
46180                 }
46181                 if (defaultVal == null) {
46182                         defaultVal = {};
46183                 }
46184                 var val = store.get(key, defaultVal);
46185                 transactionFn(val);
46186                 store.set(key, val);
46187         };
46188         store.getAll = function() {};
46189         store.forEach = function() {};
46190
46191         store.serialize = function(value) {
46192                 return JSON.stringify(value)
46193         };
46194         store.deserialize = function(value) {
46195                 if (typeof value != 'string') { return undefined }
46196                 try { return JSON.parse(value) }
46197                 catch(e) { return value || undefined }
46198         };
46199
46200         // Functions to encapsulate questionable FireFox 3.6.13 behavior
46201         // when about.config::dom.storage.enabled === false
46202         // See https://github.com/marcuswestin/store.js/issues#issue/13
46203         function isLocalStorageNameSupported() {
46204                 try { return (localStorageName in win && win[localStorageName]) }
46205                 catch(err) { return false }
46206         }
46207
46208         if (isLocalStorageNameSupported()) {
46209                 storage = win[localStorageName];
46210                 store.set = function(key, val) {
46211                         if (val === undefined) { return store.remove(key) }
46212                         storage.setItem(key, store.serialize(val));
46213                         return val
46214                 };
46215                 store.get = function(key, defaultVal) {
46216                         var val = store.deserialize(storage.getItem(key));
46217                         return (val === undefined ? defaultVal : val)
46218                 };
46219                 store.remove = function(key) { storage.removeItem(key); };
46220                 store.clear = function() { storage.clear(); };
46221                 store.getAll = function() {
46222                         var ret = {};
46223                         store.forEach(function(key, val) {
46224                                 ret[key] = val;
46225                         });
46226                         return ret
46227                 };
46228                 store.forEach = function(callback) {
46229                         for (var i=0; i<storage.length; i++) {
46230                                 var key = storage.key(i);
46231                                 callback(key, store.get(key));
46232                         }
46233                 };
46234         } else if (doc && doc.documentElement.addBehavior) {
46235                 var storageOwner,
46236                         storageContainer;
46237                 // Since #userData storage applies only to specific paths, we need to
46238                 // somehow link our data to a specific path.  We choose /favicon.ico
46239                 // as a pretty safe option, since all browsers already make a request to
46240                 // this URL anyway and being a 404 will not hurt us here.  We wrap an
46241                 // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
46242                 // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
46243                 // since the iframe access rules appear to allow direct access and
46244                 // manipulation of the document element, even for a 404 page.  This
46245                 // document can be used instead of the current document (which would
46246                 // have been limited to the current path) to perform #userData storage.
46247                 try {
46248                         storageContainer = new ActiveXObject('htmlfile');
46249                         storageContainer.open();
46250                         storageContainer.write('<'+scriptTag+'>document.w=window</'+scriptTag+'><iframe src="/favicon.ico"></iframe>');
46251                         storageContainer.close();
46252                         storageOwner = storageContainer.w.frames[0].document;
46253                         storage = storageOwner.createElement('div');
46254                 } catch(e) {
46255                         // somehow ActiveXObject instantiation failed (perhaps some special
46256                         // security settings or otherwse), fall back to per-path storage
46257                         storage = doc.createElement('div');
46258                         storageOwner = doc.body;
46259                 }
46260                 var withIEStorage = function(storeFunction) {
46261                         return function() {
46262                                 var args = Array.prototype.slice.call(arguments, 0);
46263                                 args.unshift(storage);
46264                                 // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
46265                                 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
46266                                 storageOwner.appendChild(storage);
46267                                 storage.addBehavior('#default#userData');
46268                                 storage.load(localStorageName);
46269                                 var result = storeFunction.apply(store, args);
46270                                 storageOwner.removeChild(storage);
46271                                 return result
46272                         }
46273                 };
46274
46275                 // In IE7, keys cannot start with a digit or contain certain chars.
46276                 // See https://github.com/marcuswestin/store.js/issues/40
46277                 // See https://github.com/marcuswestin/store.js/issues/83
46278                 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
46279                 var ieKeyFix = function(key) {
46280                         return key.replace(/^d/, '___$&').replace(forbiddenCharsRegex, '___')
46281                 };
46282                 store.set = withIEStorage(function(storage, key, val) {
46283                         key = ieKeyFix(key);
46284                         if (val === undefined) { return store.remove(key) }
46285                         storage.setAttribute(key, store.serialize(val));
46286                         storage.save(localStorageName);
46287                         return val
46288                 });
46289                 store.get = withIEStorage(function(storage, key, defaultVal) {
46290                         key = ieKeyFix(key);
46291                         var val = store.deserialize(storage.getAttribute(key));
46292                         return (val === undefined ? defaultVal : val)
46293                 });
46294                 store.remove = withIEStorage(function(storage, key) {
46295                         key = ieKeyFix(key);
46296                         storage.removeAttribute(key);
46297                         storage.save(localStorageName);
46298                 });
46299                 store.clear = withIEStorage(function(storage) {
46300                         var attributes = storage.XMLDocument.documentElement.attributes;
46301                         storage.load(localStorageName);
46302                         for (var i=attributes.length-1; i>=0; i--) {
46303                                 storage.removeAttribute(attributes[i].name);
46304                         }
46305                         storage.save(localStorageName);
46306                 });
46307                 store.getAll = function(storage) {
46308                         var ret = {};
46309                         store.forEach(function(key, val) {
46310                                 ret[key] = val;
46311                         });
46312                         return ret
46313                 };
46314                 store.forEach = withIEStorage(function(storage, callback) {
46315                         var attributes = storage.XMLDocument.documentElement.attributes;
46316                         for (var i=0, attr; attr=attributes[i]; ++i) {
46317                                 callback(attr.name, store.deserialize(storage.getAttribute(attr.name)));
46318                         }
46319                 });
46320         }
46321
46322         try {
46323                 var testKey = '__storejs__';
46324                 store.set(testKey, testKey);
46325                 if (store.get(testKey) != testKey) { store.disabled = true; }
46326                 store.remove(testKey);
46327         } catch(e) {
46328                 store.disabled = true;
46329         }
46330         store.enabled = !store.disabled;
46331         
46332         return store
46333 }));
46334 });
46335
46336 // # osm-auth
46337 //
46338 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
46339 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
46340 // does not support custom headers, which this uses everywhere.
46341 var index$12 = function(o) {
46342
46343     var oauth = {};
46344
46345     // authenticated users will also have a request token secret, but it's
46346     // not used in transactions with the server
46347     oauth.authenticated = function() {
46348         return !!(token('oauth_token') && token('oauth_token_secret'));
46349     };
46350
46351     oauth.logout = function() {
46352         token('oauth_token', '');
46353         token('oauth_token_secret', '');
46354         token('oauth_request_token_secret', '');
46355         return oauth;
46356     };
46357
46358     // TODO: detect lack of click event
46359     oauth.authenticate = function(callback) {
46360         if (oauth.authenticated()) return callback();
46361
46362         oauth.logout();
46363
46364         // ## Getting a request token
46365         var params = timenonce(getAuth(o)),
46366             url = o.url + '/oauth/request_token';
46367
46368         params.oauth_signature = index$13.signature(
46369             o.oauth_secret, '',
46370             index$13.baseString('POST', url, params));
46371
46372         if (!o.singlepage) {
46373             // Create a 600x550 popup window in the center of the screen
46374             var w = 600, h = 550,
46375                 settings = [
46376                     ['width', w], ['height', h],
46377                     ['left', screen.width / 2 - w / 2],
46378                     ['top', screen.height / 2 - h / 2]].map(function(x) {
46379                         return x.join('=');
46380                     }).join(','),
46381                 popup = window.open('about:blank', 'oauth_window', settings);
46382         }
46383
46384         // Request a request token. When this is complete, the popup
46385         // window is redirected to OSM's authorization page.
46386         index$13.xhr('POST', url, params, null, {}, reqTokenDone);
46387         o.loading();
46388
46389         function reqTokenDone(err, xhr) {
46390             o.done();
46391             if (err) return callback(err);
46392             var resp = index$13.stringQs(xhr.response);
46393             token('oauth_request_token_secret', resp.oauth_token_secret);
46394             var authorize_url = o.url + '/oauth/authorize?' + index$13.qsString({
46395                 oauth_token: resp.oauth_token,
46396                 oauth_callback: location.href.replace('index.html', '')
46397                     .replace(/#.*/, '').replace(location.search, '') + o.landing
46398             });
46399
46400             if (o.singlepage) {
46401                 location.href = authorize_url;
46402             } else {
46403                 popup.location = authorize_url;
46404             }
46405         }
46406
46407         // Called by a function in a landing page, in the popup window. The
46408         // window closes itself.
46409         window.authComplete = function(token) {
46410             var oauth_token = index$13.stringQs(token.split('?')[1]);
46411             get_access_token(oauth_token.oauth_token);
46412             delete window.authComplete;
46413         };
46414
46415         // ## Getting an request token
46416         //
46417         // At this point we have an `oauth_token`, brought in from a function
46418         // call on a landing page popup.
46419         function get_access_token(oauth_token) {
46420             var url = o.url + '/oauth/access_token',
46421                 params = timenonce(getAuth(o)),
46422                 request_token_secret = token('oauth_request_token_secret');
46423             params.oauth_token = oauth_token;
46424             params.oauth_signature = index$13.signature(
46425                 o.oauth_secret,
46426                 request_token_secret,
46427                 index$13.baseString('POST', url, params));
46428
46429             // ## Getting an access token
46430             //
46431             // The final token required for authentication. At this point
46432             // we have a `request token secret`
46433             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
46434             o.loading();
46435         }
46436
46437         function accessTokenDone(err, xhr) {
46438             o.done();
46439             if (err) return callback(err);
46440             var access_token = index$13.stringQs(xhr.response);
46441             token('oauth_token', access_token.oauth_token);
46442             token('oauth_token_secret', access_token.oauth_token_secret);
46443             callback(null, oauth);
46444         }
46445     };
46446
46447     oauth.bootstrapToken = function(oauth_token, callback) {
46448         // ## Getting an request token
46449         // At this point we have an `oauth_token`, brought in from a function
46450         // call on a landing page popup.
46451         function get_access_token(oauth_token) {
46452             var url = o.url + '/oauth/access_token',
46453                 params = timenonce(getAuth(o)),
46454                 request_token_secret = token('oauth_request_token_secret');
46455             params.oauth_token = oauth_token;
46456             params.oauth_signature = index$13.signature(
46457                 o.oauth_secret,
46458                 request_token_secret,
46459                 index$13.baseString('POST', url, params));
46460
46461             // ## Getting an access token
46462             // The final token required for authentication. At this point
46463             // we have a `request token secret`
46464             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
46465             o.loading();
46466         }
46467
46468         function accessTokenDone(err, xhr) {
46469             o.done();
46470             if (err) return callback(err);
46471             var access_token = index$13.stringQs(xhr.response);
46472             token('oauth_token', access_token.oauth_token);
46473             token('oauth_token_secret', access_token.oauth_token_secret);
46474             callback(null, oauth);
46475         }
46476
46477         get_access_token(oauth_token);
46478     };
46479
46480     // # xhr
46481     //
46482     // A single XMLHttpRequest wrapper that does authenticated calls if the
46483     // user has logged in.
46484     oauth.xhr = function(options, callback) {
46485         if (!oauth.authenticated()) {
46486             if (o.auto) {
46487                 return oauth.authenticate(run);
46488             } else {
46489                 callback('not authenticated', null);
46490                 return;
46491             }
46492         } else {
46493             return run();
46494         }
46495
46496         function run() {
46497             var params = timenonce(getAuth(o)),
46498                 oauth_token_secret = token('oauth_token_secret'),
46499                 url = (options.prefix !== false) ? o.url + options.path : options.path,
46500                 url_parts = url.replace(/#.*$/, '').split('?', 2),
46501                 base_url = url_parts[0],
46502                 query = (url_parts.length === 2) ? url_parts[1] : '';
46503
46504             // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
46505             if ((!options.options || !options.options.header ||
46506                 options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') &&
46507                 options.content) {
46508                 params = immutable(params, index$13.stringQs(options.content));
46509             }
46510
46511             params.oauth_token = token('oauth_token');
46512             params.oauth_signature = index$13.signature(
46513                 o.oauth_secret,
46514                 oauth_token_secret,
46515                 index$13.baseString(options.method, base_url, immutable(params, index$13.stringQs(query)))
46516             );
46517
46518             return index$13.xhr(options.method, url, params, options.content, options.options, done);
46519         }
46520
46521         function done(err, xhr) {
46522             if (err) return callback(err);
46523             else if (xhr.responseXML) return callback(err, xhr.responseXML);
46524             else return callback(err, xhr.response);
46525         }
46526     };
46527
46528     // pre-authorize this object, if we can just get a token and token_secret
46529     // from the start
46530     oauth.preauth = function(c) {
46531         if (!c) return;
46532         if (c.oauth_token) token('oauth_token', c.oauth_token);
46533         if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
46534         return oauth;
46535     };
46536
46537     oauth.options = function(_) {
46538         if (!arguments.length) return o;
46539
46540         o = _;
46541         o.url = o.url || 'http://www.openstreetmap.org';
46542         o.landing = o.landing || 'land.html';
46543         o.singlepage = o.singlepage || false;
46544
46545         // Optional loading and loading-done functions for nice UI feedback.
46546         // by default, no-ops
46547         o.loading = o.loading || function() {};
46548         o.done = o.done || function() {};
46549
46550         return oauth.preauth(o);
46551     };
46552
46553     // 'stamp' an authentication object from `getAuth()`
46554     // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
46555     // and timestamp
46556     function timenonce(o) {
46557         o.oauth_timestamp = index$13.timestamp();
46558         o.oauth_nonce = index$13.nonce();
46559         return o;
46560     }
46561
46562     // get/set tokens. These are prefixed with the base URL so that `osm-auth`
46563     // can be used with multiple APIs and the keys in `localStorage`
46564     // will not clash
46565     var token;
46566
46567     if (store.enabled) {
46568         token = function (x, y) {
46569             if (arguments.length === 1) return store.get(o.url + x);
46570             else if (arguments.length === 2) return store.set(o.url + x, y);
46571         };
46572     } else {
46573         var storage = {};
46574         token = function (x, y) {
46575             if (arguments.length === 1) return storage[o.url + x];
46576             else if (arguments.length === 2) return storage[o.url + x] = y;
46577         };
46578     }
46579
46580     // Get an authentication object. If you just add and remove properties
46581     // from a single object, you'll need to use `delete` to make sure that
46582     // it doesn't contain undesired properties for authentication
46583     function getAuth(o) {
46584         return {
46585             oauth_consumer_key: o.oauth_consumer_key,
46586             oauth_signature_method: 'HMAC-SHA1'
46587         };
46588     }
46589
46590     // potentially pre-authorize
46591     oauth.options(o);
46592
46593     return oauth;
46594 };
46595
46596 var JXON = new (function () {
46597   var
46598     sValueProp = 'keyValue', sAttributesProp = 'keyAttributes', sAttrPref = '@', /* you can customize these values */
46599     aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
46600
46601   function parseText (sValue) {
46602     if (rIsNull.test(sValue)) { return null; }
46603     if (rIsBool.test(sValue)) { return sValue.toLowerCase() === 'true'; }
46604     if (isFinite(sValue)) { return parseFloat(sValue); }
46605     if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
46606     return sValue;
46607   }
46608
46609   function EmptyTree () { }
46610   EmptyTree.prototype.toString = function () { return 'null'; };
46611   EmptyTree.prototype.valueOf = function () { return null; };
46612
46613   function objectify (vValue) {
46614     return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
46615   }
46616
46617   function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) {
46618     var
46619       nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(),
46620       bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
46621
46622     var
46623       sProp, vContent, nLength = 0, sCollectedTxt = '',
46624       vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
46625
46626     if (bChildren) {
46627       for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
46628         oNode = oParentNode.childNodes.item(nItem);
46629         if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is 'CDATASection' (4) */
46630         else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is 'Text' (3) */
46631         else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is 'Element' (1) */
46632       }
46633     }
46634
46635     var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
46636
46637     if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; }
46638
46639     for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
46640       sProp = aCache[nElId].nodeName.toLowerCase();
46641       vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
46642       if (vResult.hasOwnProperty(sProp)) {
46643         if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; }
46644         vResult[sProp].push(vContent);
46645       } else {
46646         vResult[sProp] = vContent;
46647         nLength++;
46648       }
46649     }
46650
46651     if (bAttributes) {
46652       var
46653         nAttrLen = oParentNode.attributes.length,
46654         sAPrefix = bNesteAttr ? '' : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
46655
46656       for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
46657         oAttrib = oParentNode.attributes.item(nAttrib);
46658         oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
46659       }
46660
46661       if (bNesteAttr) {
46662         if (bFreeze) { Object.freeze(oAttrParent); }
46663         vResult[sAttributesProp] = oAttrParent;
46664         nLength -= nAttrLen - 1;
46665       }
46666     }
46667
46668     if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
46669       vResult[sValueProp] = vBuiltVal;
46670     } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
46671       vResult = vBuiltVal;
46672     }
46673
46674     if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); }
46675
46676     aCache.length = nLevelStart;
46677
46678     return vResult;
46679   }
46680
46681   function loadObjTree (oXMLDoc, oParentEl, oParentObj) {
46682     var vValue, oChild;
46683
46684     if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
46685       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
46686     } else if (oParentObj.constructor === Date) {
46687       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));    
46688     }
46689
46690     for (var sName in oParentObj) {
46691       vValue = oParentObj[sName];
46692       if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */
46693       if (sName === sValueProp) {
46694         if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); }
46695       } else if (sName === sAttributesProp) { /* verbosity level is 3 */
46696         for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); }
46697       } else if (sName.charAt(0) === sAttrPref) {
46698         oParentEl.setAttribute(sName.slice(1), vValue);
46699       } else if (vValue.constructor === Array) {
46700         for (var nItem = 0; nItem < vValue.length; nItem++) {
46701           oChild = oXMLDoc.createElement(sName);
46702           loadObjTree(oXMLDoc, oChild, vValue[nItem]);
46703           oParentEl.appendChild(oChild);
46704         }
46705       } else {
46706         oChild = oXMLDoc.createElement(sName);
46707         if (vValue instanceof Object) {
46708           loadObjTree(oXMLDoc, oChild, vValue);
46709         } else if (vValue !== null && vValue !== true) {
46710           oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
46711         }
46712         oParentEl.appendChild(oChild);
46713      }
46714    }
46715   }
46716
46717   this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
46718     var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 : /* put here the default verbosity level: */ 1;
46719     return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);    
46720   };
46721
46722   this.unbuild = function (oObjTree) {    
46723     var oNewDoc = document.implementation.createDocument('', '', null);
46724     loadObjTree(oNewDoc, oNewDoc, oObjTree);
46725     return oNewDoc;
46726   };
46727
46728   this.stringify = function (oObjTree) {
46729     return (new XMLSerializer()).serializeToString(JXON.unbuild(oObjTree));
46730   };
46731 })();
46732
46733 // var myObject = JXON.build(doc);
46734 // we got our javascript object! try: alert(JSON.stringify(myObject));
46735
46736 // var newDoc = JXON.unbuild(myObject);
46737 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
46738
46739 var dispatch$3 = dispatch('authLoading', 'authDone', 'change', 'loading', 'loaded');
46740 var urlroot = 'https://www.openstreetmap.org';
46741 var blacklists = ['.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*'];
46742 var inflight$1 = {};
46743 var loadedTiles = {};
46744 var tileZoom$1 = 16;
46745 var oauth = index$12({
46746         url: urlroot,
46747         oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
46748         oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
46749         loading: authLoading,
46750         done: authDone
46751     });
46752 var rateLimitError;
46753 var userChangesets;
46754 var userDetails;
46755 var off;
46756
46757
46758 function authLoading() {
46759     dispatch$3.call('authLoading');
46760 }
46761
46762
46763 function authDone() {
46764     dispatch$3.call('authDone');
46765 }
46766
46767
46768 function abortRequest$1(i) {
46769     if (i) {
46770         i.abort();
46771     }
46772 }
46773
46774
46775 function getLoc(attrs) {
46776     var lon = attrs.lon && attrs.lon.value,
46777         lat = attrs.lat && attrs.lat.value;
46778     return [parseFloat(lon), parseFloat(lat)];
46779 }
46780
46781
46782 function getNodes(obj) {
46783     var elems = obj.getElementsByTagName('nd'),
46784         nodes = new Array(elems.length);
46785     for (var i = 0, l = elems.length; i < l; i++) {
46786         nodes[i] = 'n' + elems[i].attributes.ref.value;
46787     }
46788     return nodes;
46789 }
46790
46791
46792 function getTags(obj) {
46793     var elems = obj.getElementsByTagName('tag'),
46794         tags = {};
46795     for (var i = 0, l = elems.length; i < l; i++) {
46796         var attrs = elems[i].attributes;
46797         tags[attrs.k.value] = attrs.v.value;
46798     }
46799
46800     return tags;
46801 }
46802
46803
46804 function getMembers(obj) {
46805     var elems = obj.getElementsByTagName('member'),
46806         members = new Array(elems.length);
46807     for (var i = 0, l = elems.length; i < l; i++) {
46808         var attrs = elems[i].attributes;
46809         members[i] = {
46810             id: attrs.type.value[0] + attrs.ref.value,
46811             type: attrs.type.value,
46812             role: attrs.role.value
46813         };
46814     }
46815     return members;
46816 }
46817
46818
46819 function getVisible(attrs) {
46820     return (!attrs.visible || attrs.visible.value !== 'false');
46821 }
46822
46823
46824 var parsers = {
46825     node: function nodeData(obj) {
46826         var attrs = obj.attributes;
46827         return new osmNode({
46828             id: osmEntity$$1.id.fromOSM('node', attrs.id.value),
46829             loc: getLoc(attrs),
46830             version: attrs.version.value,
46831             user: attrs.user && attrs.user.value,
46832             tags: getTags(obj),
46833             visible: getVisible(attrs)
46834         });
46835     },
46836
46837     way: function wayData(obj) {
46838         var attrs = obj.attributes;
46839         return new osmWay({
46840             id: osmEntity$$1.id.fromOSM('way', attrs.id.value),
46841             version: attrs.version.value,
46842             user: attrs.user && attrs.user.value,
46843             tags: getTags(obj),
46844             nodes: getNodes(obj),
46845             visible: getVisible(attrs)
46846         });
46847     },
46848
46849     relation: function relationData(obj) {
46850         var attrs = obj.attributes;
46851         return new osmRelation({
46852             id: osmEntity$$1.id.fromOSM('relation', attrs.id.value),
46853             version: attrs.version.value,
46854             user: attrs.user && attrs.user.value,
46855             tags: getTags(obj),
46856             members: getMembers(obj),
46857             visible: getVisible(attrs)
46858         });
46859     }
46860 };
46861
46862
46863 function parse(xml$$1) {
46864     if (!xml$$1 || !xml$$1.childNodes) return;
46865
46866     var root = xml$$1.childNodes[0],
46867         children = root.childNodes,
46868         entities = [];
46869
46870     for (var i = 0, l = children.length; i < l; i++) {
46871         var child = children[i],
46872             parser = parsers[child.nodeName];
46873         if (parser) {
46874             entities.push(parser(child));
46875         }
46876     }
46877
46878     return entities;
46879 }
46880
46881
46882 var serviceOsm = {
46883
46884     init: function() {
46885         utilRebind(this, dispatch$3, 'on');
46886     },
46887
46888
46889     reset: function() {
46890         userChangesets = undefined;
46891         userDetails = undefined;
46892         rateLimitError = undefined;
46893         lodash.forEach(inflight$1, abortRequest$1);
46894         loadedTiles = {};
46895         inflight$1 = {};
46896         return this;
46897     },
46898
46899
46900     changesetURL: function(changesetId) {
46901         return urlroot + '/changeset/' + changesetId;
46902     },
46903
46904
46905     changesetsURL: function(center, zoom$$1) {
46906         var precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2));
46907         return urlroot + '/history#map=' +
46908             Math.floor(zoom$$1) + '/' +
46909             center[1].toFixed(precision) + '/' +
46910             center[0].toFixed(precision);
46911     },
46912
46913
46914     entityURL: function(entity) {
46915         return urlroot + '/' + entity.type + '/' + entity.osmId();
46916     },
46917
46918
46919     userURL: function(username) {
46920         return urlroot + '/user/' + username;
46921     },
46922
46923
46924     loadFromAPI: function(path$$1, callback) {
46925         var that = this;
46926
46927         function done(err, xml$$1) {
46928             var isAuthenticated = that.authenticated();
46929
46930             // 400 Bad Request, 401 Unauthorized, 403 Forbidden
46931             // Logout and retry the request..
46932             if (isAuthenticated && err &&
46933                     (err.status === 400 || err.status === 401 || err.status === 403)) {
46934                 that.logout();
46935                 that.loadFromAPI(path$$1, callback);
46936
46937             // else, no retry..
46938             } else {
46939                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
46940                 // Set the rateLimitError flag and trigger a warning..
46941                 if (!isAuthenticated && !rateLimitError && err &&
46942                         (err.status === 509 || err.status === 429)) {
46943                     rateLimitError = err;
46944                     dispatch$3.call('change');
46945                 }
46946
46947                 if (callback) {
46948                     callback(err, parse(xml$$1));
46949                 }
46950             }
46951         }
46952
46953         if (this.authenticated()) {
46954             return oauth.xhr({ method: 'GET', path: path$$1 }, done);
46955         } else {
46956             var url = urlroot + path$$1;
46957             return xml(url).get(done);
46958         }
46959     },
46960
46961
46962     loadEntity: function(id, callback) {
46963         var type = osmEntity$$1.id.type(id),
46964             osmID = osmEntity$$1.id.toOSM(id);
46965
46966         this.loadFromAPI(
46967             '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
46968             function(err, entities) {
46969                 if (callback) callback(err, { data: entities });
46970             }
46971         );
46972     },
46973
46974
46975     loadEntityVersion: function(id, version$$1, callback) {
46976         var type = osmEntity$$1.id.type(id),
46977             osmID = osmEntity$$1.id.toOSM(id);
46978
46979         this.loadFromAPI(
46980             '/api/0.6/' + type + '/' + osmID + '/' + version$$1,
46981             function(err, entities) {
46982                 if (callback) callback(err, { data: entities });
46983             }
46984         );
46985     },
46986
46987
46988     loadMultiple: function(ids, callback) {
46989         var that = this;
46990         lodash.each(lodash.groupBy(lodash.uniq(ids), osmEntity$$1.id.type), function(v, k) {
46991             var type = k + 's',
46992                 osmIDs = lodash.map(v, osmEntity$$1.id.toOSM);
46993
46994             lodash.each(lodash.chunk(osmIDs, 150), function(arr) {
46995                 that.loadFromAPI(
46996                     '/api/0.6/' + type + '?' + type + '=' + arr.join(),
46997                     function(err, entities) {
46998                         if (callback) callback(err, { data: entities });
46999                     }
47000                 );
47001             });
47002         });
47003     },
47004
47005
47006     authenticated: function() {
47007         return oauth.authenticated();
47008     },
47009
47010
47011     putChangeset: function(changeset, changes, callback) {
47012
47013         // Create the changeset..
47014         oauth.xhr({
47015             method: 'PUT',
47016             path: '/api/0.6/changeset/create',
47017             options: { header: { 'Content-Type': 'text/xml' } },
47018             content: JXON.stringify(changeset.asJXON())
47019         }, createdChangeset);
47020
47021
47022         function createdChangeset(err, changeset_id) {
47023             if (err) return callback(err);
47024             changeset = changeset.update({ id: changeset_id });
47025
47026             // Upload the changeset..
47027             oauth.xhr({
47028                 method: 'POST',
47029                 path: '/api/0.6/changeset/' + changeset_id + '/upload',
47030                 options: { header: { 'Content-Type': 'text/xml' } },
47031                 content: JXON.stringify(changeset.osmChangeJXON(changes))
47032             }, uploadedChangeset);
47033         }
47034
47035
47036         function uploadedChangeset(err) {
47037             if (err) return callback(err);
47038
47039             // Upload was successful, safe to call the callback.
47040             // Add delay to allow for postgres replication #1646 #2678
47041             window.setTimeout(function() {
47042                 callback(null, changeset);
47043             }, 2500);
47044
47045             // Still attempt to close changeset, but ignore response because #2667
47046             oauth.xhr({
47047                 method: 'PUT',
47048                 path: '/api/0.6/changeset/' + changeset.id + '/close',
47049                 options: { header: { 'Content-Type': 'text/xml' } }
47050             }, function() { return true; });
47051         }
47052     },
47053
47054
47055     userDetails: function(callback) {
47056         if (userDetails) {
47057             callback(undefined, userDetails);
47058             return;
47059         }
47060
47061         function done(err, user_details) {
47062             if (err) return callback(err);
47063
47064             var u = user_details.getElementsByTagName('user')[0],
47065                 img = u.getElementsByTagName('img'),
47066                 image_url = '';
47067
47068             if (img && img[0] && img[0].getAttribute('href')) {
47069                 image_url = img[0].getAttribute('href');
47070             }
47071
47072             userDetails = {
47073                 display_name: u.attributes.display_name.value,
47074                 image_url: image_url,
47075                 id: u.attributes.id.value
47076             };
47077
47078             callback(undefined, userDetails);
47079         }
47080
47081         oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
47082     },
47083
47084
47085     userChangesets: function(callback) {
47086         if (userChangesets) {
47087             callback(undefined, userChangesets);
47088             return;
47089         }
47090
47091         this.userDetails(function(err, user) {
47092             if (err) {
47093                 callback(err);
47094                 return;
47095             }
47096
47097             function done(err, changesets) {
47098                 if (err) {
47099                     callback(err);
47100                 } else {
47101                     userChangesets = Array.prototype.map.call(
47102                         changesets.getElementsByTagName('changeset'),
47103                         function (changeset) {
47104                             return { tags: getTags(changeset) };
47105                         }
47106                     ).filter(function (changeset) {
47107                         var comment = changeset.tags.comment;
47108                         return comment && comment !== '';
47109                     });
47110                     callback(undefined, userChangesets);
47111                 }
47112             }
47113
47114             oauth.xhr({ method: 'GET', path: '/api/0.6/changesets?user=' + user.id }, done);
47115         });
47116     },
47117
47118
47119     status: function(callback) {
47120         function done(xml$$1) {
47121             // update blacklists
47122             var elements = xml$$1.getElementsByTagName('blacklist'),
47123                 regexes = [];
47124             for (var i = 0; i < elements.length; i++) {
47125                 var regex = elements[i].getAttribute('regex');  // needs unencode?
47126                 if (regex) {
47127                     regexes.push(regex);
47128                 }
47129             }
47130             if (regexes.length) {
47131                 blacklists = regexes;
47132             }
47133
47134
47135             if (rateLimitError) {
47136                 callback(rateLimitError, 'rateLimited');
47137             } else {
47138                 var apiStatus = xml$$1.getElementsByTagName('status'),
47139                     val = apiStatus[0].getAttribute('api');
47140
47141                 callback(undefined, val);
47142             }
47143         }
47144
47145         xml(urlroot + '/api/capabilities').get()
47146             .on('load', done)
47147             .on('error', callback);
47148     },
47149
47150
47151     imageryBlacklists: function() {
47152         return blacklists;
47153     },
47154
47155
47156     tileZoom: function(_) {
47157         if (!arguments.length) return tileZoom$1;
47158         tileZoom$1 = _;
47159         return this;
47160     },
47161
47162
47163     loadTiles: function(projection, dimensions, callback) {
47164         if (off) return;
47165
47166         var that = this,
47167             s = projection.scale() * 2 * Math.PI,
47168             z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
47169             ts = 256 * Math.pow(2, z - tileZoom$1),
47170             origin = [
47171                 s / 2 - projection.translate()[0],
47172                 s / 2 - projection.translate()[1]
47173             ];
47174
47175         var tiles = d3geoTile()
47176             .scaleExtent([tileZoom$1, tileZoom$1])
47177             .scale(s)
47178             .size(dimensions)
47179             .translate(projection.translate())()
47180             .map(function(tile) {
47181                 var x = tile[0] * ts - origin[0],
47182                     y = tile[1] * ts - origin[1];
47183
47184                 return {
47185                     id: tile.toString(),
47186                     extent: geoExtent$$1(
47187                         projection.invert([x, y + ts]),
47188                         projection.invert([x + ts, y]))
47189                 };
47190             });
47191
47192         lodash.filter(inflight$1, function(v, i) {
47193             var wanted = lodash.find(tiles, function(tile) {
47194                 return i === tile.id;
47195             });
47196             if (!wanted) delete inflight$1[i];
47197             return !wanted;
47198         }).map(abortRequest$1);
47199
47200         tiles.forEach(function(tile) {
47201             var id = tile.id;
47202
47203             if (loadedTiles[id] || inflight$1[id]) return;
47204
47205             if (lodash.isEmpty(inflight$1)) {
47206                 dispatch$3.call('loading');
47207             }
47208
47209             inflight$1[id] = that.loadFromAPI(
47210                 '/api/0.6/map?bbox=' + tile.extent.toParam(),
47211                 function(err, parsed) {
47212                     delete inflight$1[id];
47213                     if (!err) {
47214                         loadedTiles[id] = true;
47215                     }
47216
47217                     if (callback) {
47218                         callback(err, lodash.extend({ data: parsed }, tile));
47219                     }
47220
47221                     if (lodash.isEmpty(inflight$1)) {
47222                         dispatch$3.call('loaded');
47223                     }
47224                 }
47225             );
47226         });
47227     },
47228
47229
47230     switch: function(options) {
47231         urlroot = options.urlroot;
47232
47233         oauth.options(lodash.extend({
47234             url: urlroot,
47235             loading: authLoading,
47236             done: authDone
47237         }, options));
47238
47239         dispatch$3.call('change');
47240         this.reset();
47241         this.userChangesets(function() {});  // eagerly load user details/changesets
47242         return this;
47243     },
47244
47245
47246     toggle: function(_) {
47247         off = !_;
47248         return this;
47249     },
47250
47251
47252     loadedTiles: function(_) {
47253         if (!arguments.length) return loadedTiles;
47254         loadedTiles = _;
47255         return this;
47256     },
47257
47258
47259     logout: function() {
47260         userChangesets = undefined;
47261         userDetails = undefined;
47262         oauth.logout();
47263         dispatch$3.call('change');
47264         return this;
47265     },
47266
47267
47268     authenticate: function(callback) {
47269         var that = this;
47270         userChangesets = undefined;
47271         userDetails = undefined;
47272
47273         function done(err, res) {
47274             rateLimitError = undefined;
47275             dispatch$3.call('change');
47276             if (callback) callback(err, res);
47277             that.userChangesets(function() {});  // eagerly load user details/changesets
47278         }
47279
47280         return oauth.authenticate(done);
47281     }
47282 };
47283
47284 var apibase$2 = 'https://taginfo.openstreetmap.org/api/4/';
47285 var inflight$2 = {};
47286 var popularKeys = {};
47287 var taginfoCache = {};
47288 var tag_sorts = {
47289         point: 'count_nodes',
47290         vertex: 'count_nodes',
47291         area: 'count_ways',
47292         line: 'count_ways'
47293     };
47294 var tag_sort_members = {
47295         point: 'count_node_members',
47296         vertex: 'count_node_members',
47297         area: 'count_way_members',
47298         line: 'count_way_members',
47299         relation: 'count_relation_members'
47300     };
47301 var tag_filters = {
47302         point: 'nodes',
47303         vertex: 'nodes',
47304         area: 'ways',
47305         line: 'ways'
47306     };
47307 var tag_members_fractions = {
47308         point: 'count_node_members_fraction',
47309         vertex: 'count_node_members_fraction',
47310         area: 'count_way_members_fraction',
47311         line: 'count_way_members_fraction',
47312         relation: 'count_relation_members_fraction'
47313     };
47314
47315
47316 function sets(params, n, o) {
47317     if (params.geometry && o[params.geometry]) {
47318         params[n] = o[params.geometry];
47319     }
47320     return params;
47321 }
47322
47323
47324 function setFilter(params) {
47325     return sets(params, 'filter', tag_filters);
47326 }
47327
47328
47329 function setSort(params) {
47330     return sets(params, 'sortname', tag_sorts);
47331 }
47332
47333
47334 function setSortMembers(params) {
47335     return sets(params, 'sortname', tag_sort_members);
47336 }
47337
47338
47339 function clean(params) {
47340     return lodash.omit(params, ['geometry', 'debounce']);
47341 }
47342
47343
47344 function filterKeys(type) {
47345     var count_type = type ? 'count_' + type : 'count_all';
47346     return function(d) {
47347         return parseFloat(d[count_type]) > 2500 || d.in_wiki;
47348     };
47349 }
47350
47351
47352 function filterMultikeys(prefix) {
47353     return function(d) {
47354         // d.key begins with prefix, and d.key contains no additional ':'s
47355         var re = new RegExp('^' + prefix + '(.*)$');
47356         var matches = d.key.match(re) || [];
47357         return (matches.length === 2 && matches[1].indexOf(':') === -1);
47358     };
47359 }
47360
47361
47362 function filterValues(allowUpperCase) {
47363     return function(d) {
47364         if (d.value.match(/[;,]/) !== null) return false;  // exclude some punctuation
47365         if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false;  // exclude uppercase letters
47366         return parseFloat(d.fraction) > 0.0 || d.in_wiki;
47367     };
47368 }
47369
47370
47371 function filterRoles(geometry) {
47372     return function(d) {
47373         if (d.role === '') return false; // exclude empty role
47374         if (d.role.match(/[A-Z*;,]/) !== null) return false;  // exclude uppercase letters and some punctuation
47375         return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
47376     };
47377 }
47378
47379
47380 function valKey(d) {
47381     return {
47382         value: d.key,
47383         title: d.key
47384     };
47385 }
47386
47387
47388 function valKeyDescription(d) {
47389     return {
47390         value: d.value,
47391         title: d.description || d.value
47392     };
47393 }
47394
47395
47396 function roleKey(d) {
47397     return {
47398         value: d.role,
47399         title: d.role
47400     };
47401 }
47402
47403
47404 // sort keys with ':' lower than keys without ':'
47405 function sortKeys(a, b) {
47406     return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
47407         : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
47408         : 0;
47409 }
47410
47411
47412 var debouncedRequest = lodash.debounce(request$1, 500, { leading: false });
47413
47414 function request$1(url, params, exactMatch, callback, loaded) {
47415     if (inflight$2[url]) return;
47416
47417     if (checkCache(url, params, exactMatch, callback)) return;
47418
47419     inflight$2[url] = json(url, function (err, data) {
47420         delete inflight$2[url];
47421         loaded(err, data);
47422     });
47423 }
47424
47425
47426 function checkCache(url, params, exactMatch, callback) {
47427     var rp = params.rp || 25,
47428         testQuery = params.query || '',
47429         testUrl = url;
47430
47431     do {
47432         var hit = taginfoCache[testUrl];
47433
47434         // exact match, or shorter match yielding fewer than max results (rp)
47435         if (hit && (url === testUrl || hit.length < rp)) {
47436             callback(null, hit);
47437             return true;
47438         }
47439
47440         // don't try to shorten the query
47441         if (exactMatch || !testQuery.length) return false;
47442
47443         // do shorten the query to see if we already have a cached result
47444         // that has returned fewer than max results (rp)
47445         testQuery = testQuery.slice(0, -1);
47446         testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
47447     } while (testQuery.length >= 0);
47448
47449     return false;
47450 }
47451
47452
47453 var serviceTaginfo = {
47454
47455     init: function() {
47456         inflight$2 = {};
47457         taginfoCache = {};
47458         popularKeys = {};
47459
47460         // Fetch popular keys.  We'll exclude these from `values`
47461         // lookups because they stress taginfo, and they aren't likely
47462         // to yield meaningful autocomplete results.. see #3955
47463         var params = { rp: 100, sortname: 'values_all', sortorder: 'desc', page: 1, debounce: false };
47464         this.keys(params, function(err, data) {
47465             if (err) return;
47466             data.forEach(function(d) {
47467                 if (d.value === 'opening_hours') return;  // exception
47468                 popularKeys[d.value] = true;
47469             });
47470         });
47471     },
47472
47473
47474     reset: function() {
47475         lodash.forEach(inflight$2, function(req) { req.abort(); });
47476         inflight$2 = {};
47477     },
47478
47479
47480     keys: function(params, callback) {
47481         var doRequest = params.debounce ? debouncedRequest : request$1;
47482         params = clean(setSort(params));
47483         params = lodash.extend({ rp: 10, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
47484
47485         var url = apibase$2 + 'keys/all?' + utilQsString(params);
47486         doRequest(url, params, false, callback, function(err, d) {
47487             if (err) {
47488                 callback(err);
47489             } else {
47490                 var f = filterKeys(params.filter);
47491                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
47492                 taginfoCache[url] = result;
47493                 callback(null, result);
47494             }
47495         });
47496     },
47497
47498
47499     multikeys: function(params, callback) {
47500         var doRequest = params.debounce ? debouncedRequest : request$1;
47501         params = clean(setSort(params));
47502         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
47503         var prefix = params.query;
47504
47505         var url = apibase$2 + 'keys/all?' + utilQsString(params);
47506         doRequest(url, params, true, callback, function(err, d) {
47507             if (err) {
47508                 callback(err);
47509             } else {
47510                 var f = filterMultikeys(prefix);
47511                 var result = d.data.filter(f).map(valKey);
47512                 taginfoCache[url] = result;
47513                 callback(null, result);
47514             }
47515         });
47516     },
47517
47518
47519     values: function(params, callback) {
47520         // Exclude popular keys from values lookups.. see #3955
47521         var key = params.key;
47522         if (key && popularKeys[key]) {
47523             callback(null, []);
47524             return;
47525         }
47526
47527         var doRequest = params.debounce ? debouncedRequest : request$1;
47528         params = clean(setSort(setFilter(params)));
47529         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
47530
47531         var url = apibase$2 + 'key/values?' + utilQsString(params);
47532         doRequest(url, params, false, callback, function(err, d) {
47533             if (err) {
47534                 callback(err);
47535             } else {
47536                 // In most cases we prefer taginfo value results with lowercase letters.
47537                 // A few OSM keys expect values to contain uppercase values (see #3377).
47538                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
47539                 // but these are the fields where taginfo value lookup is most useful.
47540                 var re = /network|taxon|genus|species|brand|grape_variety|_hours|_times/;
47541                 var allowUpperCase = (params.key.match(re) !== null);
47542                 var f = filterValues(allowUpperCase);
47543
47544                 var result = d.data.filter(f).map(valKeyDescription);
47545                 taginfoCache[url] = result;
47546                 callback(null, result);
47547             }
47548         });
47549     },
47550
47551
47552     roles: function(params, callback) {
47553         var doRequest = params.debounce ? debouncedRequest : request$1;
47554         var geometry = params.geometry;
47555         params = clean(setSortMembers(params));
47556         params = lodash.extend({ rp: 25, sortname: 'count_all_members', sortorder: 'desc', page: 1 }, params);
47557
47558         var url = apibase$2 + 'relation/roles?' + utilQsString(params);
47559         doRequest(url, params, true, callback, function(err, d) {
47560             if (err) {
47561                 callback(err);
47562             } else {
47563                 var f = filterRoles(geometry);
47564                 var result = d.data.filter(f).map(roleKey);
47565                 taginfoCache[url] = result;
47566                 callback(null, result);
47567             }
47568         });
47569     },
47570
47571
47572     docs: function(params, callback) {
47573         var doRequest = params.debounce ? debouncedRequest : request$1;
47574         params = clean(setSort(params));
47575
47576         var path$$1 = 'key/wiki_pages?';
47577         if (params.value) path$$1 = 'tag/wiki_pages?';
47578         else if (params.rtype) path$$1 = 'relation/wiki_pages?';
47579
47580         var url = apibase$2 + path$$1 + utilQsString(params);
47581         doRequest(url, params, true, callback, function(err, d) {
47582             if (err) {
47583                 callback(err);
47584             } else {
47585                 taginfoCache[url] = d.data;
47586                 callback(null, d.data);
47587             }
47588         });
47589     },
47590
47591
47592     apibase: function(_) {
47593         if (!arguments.length) return apibase$2;
47594         apibase$2 = _;
47595         return this;
47596     }
47597
47598 };
47599
47600 var jsonpCache = {};
47601 window.jsonpCache = jsonpCache;
47602
47603 function jsonpRequest(url, callback) {
47604
47605   if (window.JSONP_FIX) {
47606     if (window.JSONP_DELAY === 0) {
47607       callback(window.JSONP_FIX);
47608     } else {
47609       setTimeout(function() {
47610         callback(window.JSONP_FIX);
47611       }, window.JSONP_DELAY || 0);
47612     }
47613     return;
47614   }
47615
47616   function rand() {
47617     var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
47618       c = '', i = -1;
47619     while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
47620     return c;
47621   }
47622
47623   function create(url) {
47624     var e = url.match(/callback=(\w+)/),
47625       c = e ? e[1] : rand();
47626     jsonpCache[c] = function(data) {
47627       callback(data);
47628       delete jsonpCache[c];
47629       script.remove();
47630     };
47631     return 'jsonpCache.' + c;
47632   }
47633
47634   var cb = create(url),
47635     script = select('head')
47636     .append('script')
47637     .attr('type', 'text/javascript')
47638     .attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
47639 }
47640
47641 var endpoint = 'https://www.wikidata.org/w/api.php?';
47642
47643 var serviceWikidata = {
47644
47645     init: function() {},
47646     reset: function() {},
47647
47648
47649     // Given a Wikipedia language and article title, return an array of
47650     // corresponding Wikidata entities.
47651     itemsByTitle: function(lang, title, callback) {
47652         if (!title) {
47653             callback('', {});
47654             return;
47655         }
47656
47657         lang = lang || 'en';
47658         jsonpRequest(endpoint + utilQsString({
47659             action: 'wbgetentities',
47660             format: 'json',
47661             sites: lang.replace(/-/g, '_') + 'wiki',
47662             titles: title,
47663             languages: 'en', // shrink response by filtering to one language
47664             callback: '{callback}'
47665         }), function(data) {
47666             if (!data || data.error) {
47667                 callback('', {});
47668             } else {
47669                 callback(title, data.entities || {});
47670             }
47671         });
47672     }
47673
47674 };
47675
47676 var endpoint$1 = 'https://en.wikipedia.org/w/api.php?';
47677
47678 var serviceWikipedia = {
47679
47680     init: function() {},
47681     reset: function() {},
47682
47683
47684     search: function(lang, query, callback) {
47685         if (!query) {
47686             callback('', []);
47687             return;
47688         }
47689
47690         lang = lang || 'en';
47691         jsonpRequest(endpoint$1.replace('en', lang) +
47692             utilQsString({
47693                 action: 'query',
47694                 list: 'search',
47695                 srlimit: '10',
47696                 srinfo: 'suggestion',
47697                 format: 'json',
47698                 callback: '{callback}',
47699                 srsearch: query
47700             }), function(data) {
47701                 if (!data || !data.query || !data.query.search || data.error) {
47702                     callback('', []);
47703                 } else {
47704                     var results = data.query.search.map(function(d) { return d.title; });
47705                     callback(query, results);
47706                 }
47707             }
47708         );
47709     },
47710
47711
47712     suggestions: function(lang, query, callback) {
47713         if (!query) {
47714             callback('', []);
47715             return;
47716         }
47717
47718         lang = lang || 'en';
47719         jsonpRequest(endpoint$1.replace('en', lang) +
47720             utilQsString({
47721                 action: 'opensearch',
47722                 namespace: 0,
47723                 suggest: '',
47724                 format: 'json',
47725                 callback: '{callback}',
47726                 search: query
47727             }), function(data) {
47728                 if (!data || data.error) {
47729                     callback('', []);
47730                 } else {
47731                     callback(data[0], data[1] || []);
47732                 }
47733             }
47734         );
47735     },
47736
47737
47738     translations: function(lang, title, callback) {
47739         if (!title) {
47740             callback({});
47741             return;
47742         }
47743
47744         jsonpRequest(endpoint$1.replace('en', lang) +
47745             utilQsString({
47746                 action: 'query',
47747                 prop: 'langlinks',
47748                 format: 'json',
47749                 callback: '{callback}',
47750                 lllimit: 500,
47751                 titles: title
47752             }), function(data) {
47753                 if (!data || !data.query || !data.query.pages || data.error) {
47754                     callback({});
47755                 } else {
47756                     var list = data.query.pages[Object.keys(data.query.pages)[0]],
47757                         translations = {};
47758                     if (list && list.langlinks) {
47759                         list.langlinks.forEach(function(d) {
47760                             translations[d.lang] = d['*'];
47761                         });
47762                     }
47763                     callback(translations);
47764                 }
47765             }
47766         );
47767     }
47768
47769 };
47770
47771 var services = {
47772     mapillary: serviceMapillary,
47773     geocoder: serviceNominatim,
47774     osm: serviceOsm,
47775     taginfo: serviceTaginfo,
47776     wikidata: serviceWikidata,
47777     wikipedia: serviceWikipedia
47778 };
47779
47780 function svgMapillaryImages(projection, context, dispatch$$1) {
47781     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
47782         minZoom = 12,
47783         minViewfieldZoom = 17,
47784         layer = select(null),
47785         _mapillary;
47786
47787
47788     function init() {
47789         if (svgMapillaryImages.initialized) return;  // run once
47790         svgMapillaryImages.enabled = false;
47791         svgMapillaryImages.initialized = true;
47792     }
47793
47794
47795     function getMapillary() {
47796         if (services.mapillary && !_mapillary) {
47797             _mapillary = services.mapillary;
47798             _mapillary.event.on('loadedImages', throttledRedraw);
47799         } else if (!services.mapillary && _mapillary) {
47800             _mapillary = null;
47801         }
47802
47803         return _mapillary;
47804     }
47805
47806
47807     function showLayer() {
47808         var mapillary = getMapillary();
47809         if (!mapillary) return;
47810
47811         mapillary.loadViewer(context);
47812         editOn();
47813
47814         layer
47815             .style('opacity', 0)
47816             .transition()
47817             .duration(500)
47818             .style('opacity', 1)
47819             .on('end', function () { dispatch$$1.call('change'); });
47820     }
47821
47822
47823     function hideLayer() {
47824         var mapillary = getMapillary();
47825         if (mapillary) {
47826             mapillary.hideViewer();
47827         }
47828
47829         throttledRedraw.cancel();
47830
47831         layer
47832             .transition()
47833             .duration(500)
47834             .style('opacity', 0)
47835             .on('end', editOff);
47836     }
47837
47838
47839     function editOn() {
47840         layer.style('display', 'block');
47841     }
47842
47843
47844     function editOff() {
47845         layer.selectAll('.viewfield-group').remove();
47846         layer.style('display', 'none');
47847     }
47848
47849
47850     function click(d) {
47851         var mapillary = getMapillary();
47852         if (!mapillary) return;
47853
47854         context.map().centerEase(d.loc);
47855
47856         mapillary
47857             .selectedImage(d.key, true)
47858             .updateViewer(d.key, context)
47859             .showViewer();
47860     }
47861
47862
47863     function transform(d) {
47864         var t = svgPointTransform(projection)(d);
47865         if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
47866         return t;
47867     }
47868
47869
47870     function update() {
47871         var mapillary = getMapillary(),
47872             data = (mapillary ? mapillary.images(projection) : []),
47873             imageKey = mapillary ? mapillary.selectedImage() : null;
47874
47875         var markers = layer.selectAll('.viewfield-group')
47876             .data(data, function(d) { return d.key; });
47877
47878         markers.exit()
47879             .remove();
47880
47881         var enter = markers.enter()
47882             .append('g')
47883             .attr('class', 'viewfield-group')
47884             .classed('selected', function(d) { return d.key === imageKey; })
47885             .on('click', click);
47886
47887         markers = markers
47888             .merge(enter)
47889             .attr('transform', transform);
47890
47891
47892        var viewfields = markers.selectAll('.viewfield')
47893             .data(~~context.map().zoom() >= minViewfieldZoom ? [0] : []);
47894
47895         viewfields.exit()
47896             .remove();
47897
47898         viewfields.enter()
47899             .append('path')
47900             .attr('class', 'viewfield')
47901             .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
47902             .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');
47903
47904         markers.selectAll('circle')
47905             .data([0])
47906             .enter()
47907             .append('circle')
47908             .attr('dx', '0')
47909             .attr('dy', '0')
47910             .attr('r', '6');
47911     }
47912
47913
47914     function drawImages(selection$$1) {
47915         var enabled = svgMapillaryImages.enabled,
47916             mapillary = getMapillary();
47917
47918         layer = selection$$1.selectAll('.layer-mapillary-images')
47919             .data(mapillary ? [0] : []);
47920
47921         layer.exit()
47922             .remove();
47923
47924         layer = layer.enter()
47925             .append('g')
47926             .attr('class', 'layer-mapillary-images')
47927             .style('display', enabled ? 'block' : 'none')
47928             .merge(layer);
47929
47930         if (enabled) {
47931             if (mapillary && ~~context.map().zoom() >= minZoom) {
47932                 editOn();
47933                 update();
47934                 mapillary.loadImages(projection);
47935             } else {
47936                 editOff();
47937             }
47938         }
47939     }
47940
47941
47942     drawImages.enabled = function(_) {
47943         if (!arguments.length) return svgMapillaryImages.enabled;
47944         svgMapillaryImages.enabled = _;
47945         if (svgMapillaryImages.enabled) {
47946             showLayer();
47947         } else {
47948             hideLayer();
47949         }
47950         dispatch$$1.call('change');
47951         return this;
47952     };
47953
47954
47955     drawImages.supported = function() {
47956         return !!getMapillary();
47957     };
47958
47959
47960     init();
47961     return drawImages;
47962 }
47963
47964 function svgMapillarySigns(projection, context, dispatch$$1) {
47965     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
47966         minZoom = 12,
47967         layer = select(null),
47968         _mapillary;
47969
47970
47971     function init() {
47972         if (svgMapillarySigns.initialized) return;  // run once
47973         svgMapillarySigns.enabled = false;
47974         svgMapillarySigns.initialized = true;
47975     }
47976
47977
47978     function getMapillary() {
47979         if (services.mapillary && !_mapillary) {
47980             _mapillary = services.mapillary;
47981             _mapillary.event.on('loadedSigns', throttledRedraw);
47982         } else if (!services.mapillary && _mapillary) {
47983             _mapillary = null;
47984         }
47985         return _mapillary;
47986     }
47987
47988
47989     function showLayer() {
47990         editOn();
47991     }
47992
47993
47994     function hideLayer() {
47995         throttledRedraw.cancel();
47996         editOff();
47997     }
47998
47999
48000     function editOn() {
48001         layer.style('display', 'block');
48002     }
48003
48004
48005     function editOff() {
48006         layer.selectAll('.icon-sign').remove();
48007         layer.style('display', 'none');
48008     }
48009
48010
48011     function click(d) {
48012         var mapillary = getMapillary();
48013         if (!mapillary) return;
48014
48015         context.map().centerEase(d.loc);
48016
48017         mapillary
48018             .selectedImage(d.key, true)
48019             .updateViewer(d.key, context)
48020             .showViewer();
48021     }
48022
48023
48024     function update() {
48025         var mapillary = getMapillary(),
48026             data = (mapillary ? mapillary.signs(projection) : []),
48027             imageKey = mapillary ? mapillary.selectedImage() : null;
48028
48029         var signs = layer.selectAll('.icon-sign')
48030             .data(data, function(d) { return d.key; });
48031
48032         signs.exit()
48033             .remove();
48034
48035         var enter = signs.enter()
48036             .append('foreignObject')
48037             .attr('class', 'icon-sign')
48038             .attr('width', '32px')      // for Firefox
48039             .attr('height', '32px')     // for Firefox
48040             .classed('selected', function(d) { return d.key === imageKey; })
48041             .on('click', click);
48042
48043         enter
48044             .append('xhtml:body')
48045             .attr('class', 'icon-sign-body')
48046             .html(mapillary.signHTML);
48047
48048         signs
48049             .merge(enter)
48050             .attr('x', function(d) { return projection(d.loc)[0] - 16; })   // offset by -16px to
48051             .attr('y', function(d) { return projection(d.loc)[1] - 16; });  // center signs on loc
48052     }
48053
48054
48055     function drawSigns(selection$$1) {
48056         var enabled = svgMapillarySigns.enabled,
48057             mapillary = getMapillary();
48058
48059         layer = selection$$1.selectAll('.layer-mapillary-signs')
48060             .data(mapillary ? [0] : []);
48061
48062         layer.exit()
48063             .remove();
48064
48065         layer = layer.enter()
48066             .append('g')
48067             .attr('class', 'layer-mapillary-signs')
48068             .style('display', enabled ? 'block' : 'none')
48069             .merge(layer);
48070
48071         if (enabled) {
48072             if (mapillary && ~~context.map().zoom() >= minZoom) {
48073                 editOn();
48074                 update();
48075                 mapillary.loadSigns(context, projection);
48076             } else {
48077                 editOff();
48078             }
48079         }
48080     }
48081
48082
48083     drawSigns.enabled = function(_) {
48084         if (!arguments.length) return svgMapillarySigns.enabled;
48085         svgMapillarySigns.enabled = _;
48086         if (svgMapillarySigns.enabled) {
48087             showLayer();
48088         } else {
48089             hideLayer();
48090         }
48091         dispatch$$1.call('change');
48092         return this;
48093     };
48094
48095
48096     drawSigns.supported = function() {
48097         var mapillary = getMapillary();
48098         return (mapillary && mapillary.signsSupported());
48099     };
48100
48101
48102     init();
48103     return drawSigns;
48104 }
48105
48106 function svgOsm() {
48107     return function drawOsm(selection) {
48108         var layers = selection.selectAll('.layer-osm')
48109             .data(['areas', 'lines', 'hit', 'halo', 'label']);
48110
48111         layers.enter()
48112             .append('g')
48113             .attr('class', function(d) { return 'layer-osm layer-' + d; });
48114     };
48115 }
48116
48117 function svgLayers(projection, context) {
48118     var dispatch$$1 = dispatch('change'),
48119         svg = select(null),
48120         layers = [
48121             { id: 'osm', layer: svgOsm(projection, context, dispatch$$1) },
48122             { id: 'gpx', layer: svgGpx(projection, context, dispatch$$1) },
48123             { id: 'mapillary-images', layer: svgMapillaryImages(projection, context, dispatch$$1) },
48124             { id: 'mapillary-signs',  layer: svgMapillarySigns(projection, context, dispatch$$1) },
48125             { id: 'debug', layer: svgDebug(projection, context, dispatch$$1) }
48126         ];
48127
48128
48129     function drawLayers(selection$$1) {
48130         svg = selection$$1.selectAll('.surface')
48131             .data([0]);
48132
48133         svg = svg.enter()
48134             .append('svg')
48135             .attr('class', 'surface')
48136             .merge(svg);
48137
48138         var defs = svg.selectAll('.surface-defs')
48139             .data([0]);
48140
48141         defs.enter()
48142             .append('defs')
48143             .attr('class', 'surface-defs');
48144
48145         var groups = svg.selectAll('.data-layer')
48146             .data(layers);
48147
48148         groups.exit()
48149             .remove();
48150
48151         groups.enter()
48152             .append('g')
48153             .attr('class', function(d) { return 'data-layer data-layer-' + d.id; })
48154             .merge(groups)
48155             .each(function(d) { select(this).call(d.layer); });
48156     }
48157
48158
48159     drawLayers.all = function() {
48160         return layers;
48161     };
48162
48163
48164     drawLayers.layer = function(id) {
48165         var obj = lodash.find(layers, function(o) {return o.id === id;});
48166         return obj && obj.layer;
48167     };
48168
48169
48170     drawLayers.only = function(what) {
48171         var arr = [].concat(what);
48172         drawLayers.remove(lodash.difference(lodash.map(layers, 'id'), arr));
48173         return this;
48174     };
48175
48176
48177     drawLayers.remove = function(what) {
48178         var arr = [].concat(what);
48179         arr.forEach(function(id) {
48180             layers = lodash.reject(layers, function(o) {return o.id === id;});
48181         });
48182         dispatch$$1.call('change');
48183         return this;
48184     };
48185
48186
48187     drawLayers.add = function(what) {
48188         var arr = [].concat(what);
48189         arr.forEach(function(obj) {
48190             if ('id' in obj && 'layer' in obj) {
48191                 layers.push(obj);
48192             }
48193         });
48194         dispatch$$1.call('change');
48195         return this;
48196     };
48197
48198
48199     drawLayers.dimensions = function(_) {
48200         if (!arguments.length) return utilGetDimensions(svg);
48201         utilSetDimensions(svg, _);
48202         return this;
48203     };
48204
48205
48206     return utilRebind(drawLayers, dispatch$$1, 'on');
48207 }
48208
48209 function svgLines$$1(projection, context) {
48210     var detected = utilDetect();
48211
48212     var highway_stack = {
48213         motorway: 0,
48214         motorway_link: 1,
48215         trunk: 2,
48216         trunk_link: 3,
48217         primary: 4,
48218         primary_link: 5,
48219         secondary: 6,
48220         tertiary: 7,
48221         unclassified: 8,
48222         residential: 9,
48223         service: 10,
48224         footway: 11
48225     };
48226
48227
48228     function drawLines(selection$$1, graph, entities, filter) {
48229
48230
48231         function waystack(a, b) {
48232             var selected = context.selectedIDs(),
48233                 scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0,
48234                 scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
48235
48236             if (a.tags.highway) { scoreA -= highway_stack[a.tags.highway]; }
48237             if (b.tags.highway) { scoreB -= highway_stack[b.tags.highway]; }
48238             return scoreA - scoreB;
48239         }
48240
48241
48242         function drawLineGroup(selection$$1, klass, isSelected) {
48243             var lines = selection$$1
48244                 .selectAll('path')
48245                 .filter(filter)
48246                 .data(getPathData(isSelected), osmEntity$$1.key);
48247
48248             lines.exit()
48249                 .remove();
48250
48251             // Optimization: call simple TagClasses only on enter selection. This
48252             // works because osmEntity.key is defined to include the entity v attribute.
48253             lines.enter()
48254                 .append('path')
48255                 .attr('class', function(d) {
48256                     return 'way line ' + klass + ' ' + d.id + (isSelected ? ' selected' : '') +
48257                         (oldMultiPolygonOuters[d.id] ? ' old-multipolygon' : '');
48258                 })
48259                 .call(svgTagClasses())
48260                 .merge(lines)
48261                 .sort(waystack)
48262                 .attr('d', getPath)
48263                 .call(svgTagClasses().tags(svgRelationMemberTags(graph)));
48264
48265             return selection$$1;
48266         }
48267
48268
48269         function getPathData(isSelected) {
48270             return function() {
48271                 var layer = this.parentNode.__data__;
48272                 var data = pathdata[layer] || [];
48273                 return data.filter(function(d) {
48274                     if (isSelected)
48275                         return context.selectedIDs().indexOf(d.id) !== -1;
48276                     else
48277                         return context.selectedIDs().indexOf(d.id) === -1;
48278                 });
48279             };
48280         }
48281
48282
48283         var getPath = svgPath(projection, graph),
48284             ways = [],
48285             pathdata = {},
48286             onewaydata = {},
48287             oldMultiPolygonOuters = {};
48288
48289         for (var i = 0; i < entities.length; i++) {
48290             var entity = entities[i],
48291                 outer = osmSimpleMultipolygonOuterMember(entity, graph);
48292             if (outer) {
48293                 ways.push(entity.mergeTags(outer.tags));
48294                 oldMultiPolygonOuters[outer.id] = true;
48295             } else if (entity.geometry(graph) === 'line') {
48296                 ways.push(entity);
48297             }
48298         }
48299
48300         ways = ways.filter(getPath);
48301         pathdata = lodash.groupBy(ways, function(way) { return way.layer(); });
48302
48303         lodash.forOwn(pathdata, function(v, k) {
48304             onewaydata[k] = lodash(v)
48305                 .filter(function(d) { return d.isOneWay(); })
48306                 .map(svgOneWaySegments(projection, graph, 35))
48307                 .flatten()
48308                 .valueOf();
48309         });
48310
48311
48312         var layer = selection$$1.selectAll('.layer-lines');
48313
48314         var layergroup = layer
48315             .selectAll('g.layergroup')
48316             .data(sequence(-10, 11));
48317
48318         layergroup = layergroup.enter()
48319             .append('g')
48320             .attr('class', function(d) { return 'layergroup layer' + String(d); })
48321             .merge(layergroup);
48322
48323         layergroup
48324             .selectAll('g.linegroup')
48325             .data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted'])
48326             .enter()
48327             .append('g')
48328             .attr('class', function(d) { return 'linegroup line-' + d; });
48329
48330
48331         layergroup.selectAll('g.line-shadow')
48332             .call(drawLineGroup, 'shadow', false);
48333         layergroup.selectAll('g.line-casing')
48334             .call(drawLineGroup, 'casing', false);
48335         layergroup.selectAll('g.line-stroke')
48336             .call(drawLineGroup, 'stroke', false);
48337
48338         layergroup.selectAll('g.line-shadow-highlighted')
48339             .call(drawLineGroup, 'shadow', true);
48340         layergroup.selectAll('g.line-casing-highlighted')
48341             .call(drawLineGroup, 'casing', true);
48342         layergroup.selectAll('g.line-stroke-highlighted')
48343             .call(drawLineGroup, 'stroke', true);
48344
48345
48346         var onewaygroup = layergroup
48347             .selectAll('g.onewaygroup')
48348             .data(['oneway']);
48349
48350         onewaygroup = onewaygroup.enter()
48351             .append('g')
48352             .attr('class', 'onewaygroup')
48353             .merge(onewaygroup);
48354
48355         var oneways = onewaygroup
48356             .selectAll('path')
48357             .filter(filter)
48358             .data(
48359                 function() { return onewaydata[this.parentNode.__data__] || []; },
48360                 function(d) { return [d.id, d.index]; }
48361             );
48362
48363         oneways.exit()
48364             .remove();
48365
48366         oneways = oneways.enter()
48367             .append('path')
48368             .attr('class', 'oneway')
48369             .attr('marker-mid', 'url(#oneway-marker)')
48370             .merge(oneways)
48371             .attr('d', function(d) { return d.d; });
48372
48373         if (detected.ie) {
48374             oneways.each(function() { this.parentNode.insertBefore(this, this); });
48375         }
48376     }
48377
48378
48379     return drawLines;
48380 }
48381
48382 function svgMidpoints$$1(projection, context) {
48383
48384     return function drawMidpoints(selection, graph, entities, filter, extent) {
48385         var layer = selection.selectAll('.layer-hit');
48386
48387         var mode = context.mode();
48388         if (mode && mode.id !== 'select') {
48389             layer.selectAll('g.midpoint').remove();
48390             return;
48391         }
48392
48393         var poly = extent.polygon(),
48394             midpoints = {};
48395
48396         for (var i = 0; i < entities.length; i++) {
48397             var entity = entities[i];
48398
48399             if (entity.type !== 'way')
48400                 continue;
48401             if (!filter(entity))
48402                 continue;
48403             if (context.selectedIDs().indexOf(entity.id) < 0)
48404                 continue;
48405
48406             var nodes = graph.childNodes(entity);
48407             for (var j = 0; j < nodes.length - 1; j++) {
48408
48409                 var a = nodes[j],
48410                     b = nodes[j + 1],
48411                     id = [a.id, b.id].sort().join('-');
48412
48413                 if (midpoints[id]) {
48414                     midpoints[id].parents.push(entity);
48415                 } else {
48416                     if (geoEuclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
48417                         var point = geoInterp(a.loc, b.loc, 0.5),
48418                             loc = null;
48419
48420                         if (extent.intersects(point)) {
48421                             loc = point;
48422                         } else {
48423                             for (var k = 0; k < 4; k++) {
48424                                 point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
48425                                 if (point &&
48426                                     geoEuclideanDistance(projection(a.loc), projection(point)) > 20 &&
48427                                     geoEuclideanDistance(projection(b.loc), projection(point)) > 20)
48428                                 {
48429                                     loc = point;
48430                                     break;
48431                                 }
48432                             }
48433                         }
48434
48435                         if (loc) {
48436                             midpoints[id] = {
48437                                 type: 'midpoint',
48438                                 id: id,
48439                                 loc: loc,
48440                                 edge: [a.id, b.id],
48441                                 parents: [entity]
48442                             };
48443                         }
48444                     }
48445                 }
48446             }
48447         }
48448
48449
48450         function midpointFilter(d) {
48451             if (midpoints[d.id])
48452                 return true;
48453
48454             for (var i = 0; i < d.parents.length; i++) {
48455                 if (filter(d.parents[i])) {
48456                     return true;
48457                 }
48458             }
48459
48460             return false;
48461         }
48462
48463
48464         var groups = layer
48465             .selectAll('g.midpoint')
48466             .filter(midpointFilter)
48467             .data(lodash.values(midpoints), function(d) { return d.id; });
48468
48469         groups.exit()
48470             .remove();
48471
48472         var enter = groups.enter()
48473             .insert('g', ':first-child')
48474             .attr('class', 'midpoint');
48475
48476         enter.append('polygon')
48477             .attr('points', '-6,8 10,0 -6,-8')
48478             .attr('class', 'shadow');
48479
48480         enter.append('polygon')
48481             .attr('points', '-3,4 5,0 -3,-4')
48482             .attr('class', 'fill');
48483
48484         groups = groups
48485             .merge(enter)
48486             .attr('transform', function(d) {
48487                 var translate = svgPointTransform(projection),
48488                     a = graph.entity(d.edge[0]),
48489                     b = graph.entity(d.edge[1]),
48490                     angleVal = Math.round(geoAngle(a, b, projection) * (180 / Math.PI));
48491                 return translate(d) + ' rotate(' + angleVal + ')';
48492             })
48493             .call(svgTagClasses().tags(
48494                 function(d) { return d.parents[0].tags; }
48495             ));
48496
48497         // Propagate data bindings.
48498         groups.select('polygon.shadow');
48499         groups.select('polygon.fill');
48500
48501     };
48502 }
48503
48504 function svgOneWaySegments(projection, graph, dt) {
48505     return function(entity) {
48506         var a,
48507             b,
48508             i = 0,
48509             offset = dt,
48510             segments = [],
48511             clip = identity$5().clipExtent(projection.clipExtent()).stream,
48512             coordinates = graph.childNodes(entity).map(function(n) {
48513                 return n.loc;
48514             });
48515
48516         if (entity.tags.oneway === '-1') coordinates.reverse();
48517
48518         geoStream({
48519             type: 'LineString',
48520             coordinates: coordinates
48521         }, projection.stream(clip({
48522             lineStart: function() {},
48523             lineEnd: function() {
48524                 a = null;
48525             },
48526             point: function(x, y) {
48527                 b = [x, y];
48528
48529                 if (a) {
48530                     var span = geoEuclideanDistance(a, b) - offset;
48531
48532                     if (span >= 0) {
48533                         var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
48534                             dx = dt * Math.cos(angle),
48535                             dy = dt * Math.sin(angle),
48536                             p = [a[0] + offset * Math.cos(angle),
48537                                  a[1] + offset * Math.sin(angle)];
48538
48539                         var segment = 'M' + a[0] + ',' + a[1] +
48540                                       'L' + p[0] + ',' + p[1];
48541
48542                         for (span -= dt; span >= 0; span -= dt) {
48543                             p[0] += dx;
48544                             p[1] += dy;
48545                             segment += 'L' + p[0] + ',' + p[1];
48546                         }
48547
48548                         segment += 'L' + b[0] + ',' + b[1];
48549                         segments.push({id: entity.id, index: i, d: segment});
48550                     }
48551
48552                     offset = -span;
48553                     i++;
48554                 }
48555
48556                 a = b;
48557             }
48558         })));
48559
48560         return segments;
48561     };
48562 }
48563
48564 function svgPath(projection, graph, isArea) {
48565
48566     // Explanation of magic numbers:
48567     // "padding" here allows space for strokes to extend beyond the viewport,
48568     // so that the stroke isn't drawn along the edge of the viewport when
48569     // the shape is clipped.
48570     //
48571     // When drawing lines, pad viewport by 5px.
48572     // When drawing areas, pad viewport by 65px in each direction to allow
48573     // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
48574
48575     var cache = {},
48576         padding = isArea ? 65 : 5,
48577         viewport = projection.clipExtent(),
48578         paddedExtent = [
48579             [viewport[0][0] - padding, viewport[0][1] - padding],
48580             [viewport[1][0] + padding, viewport[1][1] + padding]
48581         ],
48582         clip = identity$5().clipExtent(paddedExtent).stream,
48583         project = projection.stream,
48584         path$$1 = index$4()
48585             .projection({stream: function(output) { return project(clip(output)); }});
48586
48587     return function(entity) {
48588         if (entity.id in cache) {
48589             return cache[entity.id];
48590         } else {
48591             return cache[entity.id] = path$$1(entity.asGeoJSON(graph));
48592         }
48593     };
48594 }
48595
48596 function svgPoints$$1(projection, context) {
48597
48598     function markerPath(selection, klass) {
48599         selection
48600             .attr('class', klass)
48601             .attr('transform', 'translate(-8, -23)')
48602             .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');
48603     }
48604
48605     function sortY(a, b) {
48606         return b.loc[1] - a.loc[1];
48607     }
48608
48609
48610     return function drawPoints(selection, graph, entities, filter) {
48611         var wireframe = context.surface().classed('fill-wireframe'),
48612             points = wireframe ? [] : lodash.filter(entities, function(e) {
48613                 return e.geometry(graph) === 'point';
48614             });
48615
48616         points.sort(sortY);
48617
48618         var layer = selection.selectAll('.layer-hit');
48619
48620         var groups = layer.selectAll('g.point')
48621             .filter(filter)
48622             .data(points, osmEntity$$1.key);
48623
48624         groups.exit()
48625             .remove();
48626
48627         var enter = groups.enter()
48628             .append('g')
48629             .attr('class', function(d) { return 'node point ' + d.id; })
48630             .order();
48631
48632         enter.append('path')
48633             .call(markerPath, 'shadow');
48634
48635         enter.append('ellipse')
48636             .attr('cx', 0.5)
48637             .attr('cy', 1)
48638             .attr('rx', 6.5)
48639             .attr('ry', 3)
48640             .attr('class', 'stroke');
48641
48642         enter.append('path')
48643             .call(markerPath, 'stroke');
48644
48645         enter.append('use')
48646             .attr('transform', 'translate(-5, -19)')
48647             .attr('class', 'icon')
48648             .attr('width', '11px')
48649             .attr('height', '11px');
48650
48651         groups = groups
48652             .merge(enter)
48653             .attr('transform', svgPointTransform(projection))
48654             .call(svgTagClasses());
48655
48656         // Selecting the following implicitly
48657         // sets the data (point entity) on the element
48658         groups.select('.shadow');
48659         groups.select('.stroke');
48660         groups.select('.icon')
48661             .attr('xlink:href', function(entity) {
48662                 var preset = context.presets().match(entity, graph),
48663                     picon = preset && preset.icon;
48664
48665                 if (!picon)
48666                     return '';
48667                 else {
48668                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
48669                     return '#' + picon + (isMaki ? '-11' : '');
48670                 }
48671             });
48672     };
48673 }
48674
48675 function svgRelationMemberTags(graph) {
48676     return function(entity) {
48677         var tags = entity.tags;
48678         graph.parentRelations(entity).forEach(function(relation) {
48679             var type = relation.tags.type;
48680             if (type === 'multipolygon' || type === 'boundary') {
48681                 tags = lodash.extend({}, relation.tags, tags);
48682             }
48683         });
48684         return tags;
48685     };
48686 }
48687
48688 function svgTagClasses() {
48689     var primaries = [
48690             'building', 'highway', 'railway', 'waterway', 'aeroway',
48691             'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
48692             'leisure', 'military', 'place'
48693         ],
48694         statuses = [
48695             'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
48696             'razed', 'demolished', 'obliterated'
48697         ],
48698         secondaries = [
48699             'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
48700             'surface', 'tracktype', 'crossing'
48701         ],
48702         tagClassRe = /^tag-/,
48703         tags = function(entity) { return entity.tags; };
48704
48705
48706     var tagClasses = function(selection$$1) {
48707         selection$$1.each(function tagClassesEach(entity) {
48708             var value = this.className,
48709                 classes, primary, status;
48710
48711             if (value.baseVal !== undefined) value = value.baseVal;
48712
48713             classes = value.trim().split(/\s+/).filter(function(name) {
48714                 return name.length && !tagClassRe.test(name);
48715             }).join(' ');
48716
48717             var t = tags(entity), i, k, v;
48718
48719             // pick at most one primary classification tag..
48720             for (i = 0; i < primaries.length; i++) {
48721                 k = primaries[i];
48722                 v = t[k];
48723                 if (!v || v === 'no') continue;
48724
48725                 primary = k;
48726                 if (statuses.indexOf(v) !== -1) {   // e.g. `railway=abandoned`
48727                     status = v;
48728                     classes += ' tag-' + k;
48729                 } else {
48730                     classes += ' tag-' + k + ' tag-' + k + '-' + v;
48731                 }
48732
48733                 break;
48734             }
48735
48736             // add at most one status tag, only if relates to primary tag..
48737             if (!status) {
48738                 for (i = 0; i < statuses.length; i++) {
48739                     k = statuses[i];
48740                     v = t[k];
48741                     if (!v || v === 'no') continue;
48742
48743                     if (v === 'yes') {   // e.g. `railway=rail + abandoned=yes`
48744                         status = k;
48745                     }
48746                     else if (primary && primary === v) {  // e.g. `railway=rail + abandoned=railway`
48747                         status = k;
48748                     } else if (!primary && primaries.indexOf(v) !== -1) {  // e.g. `abandoned=railway`
48749                         status = k;
48750                         primary = v;
48751                         classes += ' tag-' + v;
48752                     }  // else ignore e.g.  `highway=path + abandoned=railway`
48753
48754                     if (status) break;
48755                 }
48756             }
48757
48758             if (status) {
48759                 classes += ' tag-status tag-status-' + status;
48760             }
48761
48762             // add any secondary (structure) tags
48763             for (i = 0; i < secondaries.length; i++) {
48764                 k = secondaries[i];
48765                 v = t[k];
48766                 if (!v || v === 'no') continue;
48767                 classes += ' tag-' + k + ' tag-' + k + '-' + v;
48768             }
48769
48770             // For highways, look for surface tagging..
48771             if (primary === 'highway') {
48772                 var paved = (t.highway !== 'track');
48773                 for (k in t) {
48774                     v = t[k];
48775                     if (k in osmPavedTags) {
48776                         paved = !!osmPavedTags[k][v];
48777                         break;
48778                     }
48779                 }
48780                 if (!paved) {
48781                     classes += ' tag-unpaved';
48782                 }
48783             }
48784
48785             classes = classes.trim();
48786
48787             if (classes !== value) {
48788                 select(this).attr('class', classes);
48789             }
48790         });
48791     };
48792
48793
48794     tagClasses.tags = function(_) {
48795         if (!arguments.length) return tags;
48796         tags = _;
48797         return tagClasses;
48798     };
48799
48800     return tagClasses;
48801 }
48802
48803 function svgTurns(projection) {
48804
48805     return function drawTurns(selection, graph, turns) {
48806
48807         function key(turn) {
48808             return [turn.from.node + turn.via.node + turn.to.node].join('-');
48809         }
48810
48811         function icon(turn) {
48812             var u = turn.u ? '-u' : '';
48813             if (!turn.restriction)
48814                 return '#turn-yes' + u;
48815             var restriction = graph.entity(turn.restriction).tags.restriction;
48816             return '#turn-' +
48817                 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
48818         }
48819
48820         var groups = selection.selectAll('.layer-hit').selectAll('g.turn')
48821             .data(turns, key);
48822
48823         groups.exit()
48824             .remove();
48825
48826
48827         var enter = groups.enter()
48828             .append('g')
48829             .attr('class', 'turn');
48830
48831         var nEnter = enter
48832             .filter(function (turn) { return !turn.u; });
48833
48834         nEnter.append('rect')
48835             .attr('transform', 'translate(-22, -12)')
48836             .attr('width', '44')
48837             .attr('height', '24');
48838
48839         nEnter.append('use')
48840             .attr('transform', 'translate(-22, -12)')
48841             .attr('width', '44')
48842             .attr('height', '24');
48843
48844
48845         var uEnter = enter
48846             .filter(function (turn) { return turn.u; });
48847
48848         uEnter.append('circle')
48849             .attr('r', '16');
48850
48851         uEnter.append('use')
48852             .attr('transform', 'translate(-16, -16)')
48853             .attr('width', '32')
48854             .attr('height', '32');
48855
48856
48857         groups = groups
48858             .merge(enter);
48859
48860         groups
48861             .attr('transform', function (turn) {
48862                 var v = graph.entity(turn.via.node),
48863                     t = graph.entity(turn.to.node),
48864                     a = geoAngle(v, t, projection),
48865                     p = projection(v.loc),
48866                     r = turn.u ? 0 : 60;
48867
48868                 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
48869                     'rotate(' + a * 180 / Math.PI + ')';
48870             });
48871
48872         groups.select('use')
48873             .attr('xlink:href', icon);
48874
48875         groups.select('rect');
48876         groups.select('circle');
48877
48878         return this;
48879     };
48880 }
48881
48882 function svgVertices$$1(projection, context) {
48883     var radiuses = {
48884         //       z16-, z17, z18+, tagged
48885         shadow: [6,    7.5,   7.5,  11.5],
48886         stroke: [2.5,  3.5,   3.5,  7],
48887         fill:   [1,    1.5,   1.5,  1.5]
48888     };
48889
48890     var hover;
48891
48892
48893     function siblingAndChildVertices(ids, graph, extent$$1) {
48894         var vertices = {};
48895
48896         function addChildVertices(entity) {
48897             if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
48898                 var i;
48899                 if (entity.type === 'way') {
48900                     for (i = 0; i < entity.nodes.length; i++) {
48901                         addChildVertices(graph.entity(entity.nodes[i]));
48902                     }
48903                 } else if (entity.type === 'relation') {
48904                     for (i = 0; i < entity.members.length; i++) {
48905                         var member = context.hasEntity(entity.members[i].id);
48906                         if (member) {
48907                             addChildVertices(member);
48908                         }
48909                     }
48910                 } else if (entity.intersects(extent$$1, graph)) {
48911                     vertices[entity.id] = entity;
48912                 }
48913             }
48914         }
48915
48916         ids.forEach(function(id) {
48917             var entity = context.hasEntity(id);
48918             if (entity && entity.type === 'node') {
48919                 vertices[entity.id] = entity;
48920                 context.graph().parentWays(entity).forEach(function(entity) {
48921                     addChildVertices(entity);
48922                 });
48923             } else if (entity) {
48924                 addChildVertices(entity);
48925             }
48926         });
48927
48928         return vertices;
48929     }
48930
48931
48932     function draw(selection$$1, vertices, klass, graph, zoom$$1, siblings) {
48933
48934         function icon(entity) {
48935             if (entity.id in icons) return icons[entity.id];
48936             icons[entity.id] =
48937                 entity.hasInterestingTags() &&
48938                 context.presets().match(entity, graph).icon;
48939             return icons[entity.id];
48940         }
48941
48942         function setClass(klass) {
48943             return function(entity) {
48944                 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
48945             };
48946         }
48947
48948         function setAttributes(selection$$1) {
48949             ['shadow','stroke','fill'].forEach(function(klass) {
48950                 var rads = radiuses[klass];
48951                 selection$$1.selectAll('.' + klass)
48952                     .each(function(entity) {
48953                         var i = z && icon(entity),
48954                             c = i ? 0.5 : 0,
48955                             r = rads[i ? 3 : z];
48956
48957                         // slightly increase the size of unconnected endpoints #3775
48958                         if (entity.isEndpoint(graph) && !entity.isConnected(graph)) {
48959                             r += 1.5;
48960                         }
48961
48962                         this.setAttribute('cx', c);
48963                         this.setAttribute('cy', -c);
48964                         this.setAttribute('r', r);
48965                         if (i && klass === 'fill') {
48966                             this.setAttribute('visibility', 'hidden');
48967                         } else {
48968                             this.removeAttribute('visibility');
48969                         }
48970                     });
48971             });
48972
48973             selection$$1.selectAll('use')
48974                 .each(function() {
48975                     if (z) {
48976                         this.removeAttribute('visibility');
48977                     } else {
48978                         this.setAttribute('visibility', 'hidden');
48979                     }
48980                 });
48981         }
48982
48983
48984         siblings = siblings || {};
48985
48986         var icons = {},
48987             z = (zoom$$1 < 17 ? 0 : zoom$$1 < 18 ? 1 : 2);
48988
48989         var groups = selection$$1
48990             .data(vertices, osmEntity$$1.key);
48991
48992         groups.exit()
48993             .remove();
48994
48995         var enter = groups.enter()
48996             .append('g')
48997             .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
48998
48999         enter.append('circle')
49000             .each(setClass('shadow'));
49001
49002         enter.append('circle')
49003             .each(setClass('stroke'));
49004
49005         // Vertices with icons get a `use`.
49006         enter.filter(function(d) { return icon(d); })
49007             .append('use')
49008             .attr('transform', 'translate(-5, -6)')
49009             .attr('xlink:href', function(d) {
49010                 var picon = icon(d),
49011                     isMaki = dataFeatureIcons.indexOf(picon) !== -1;
49012                 return '#' + picon + (isMaki ? '-11' : '');
49013             })
49014             .attr('width', '11px')
49015             .attr('height', '11px')
49016             .each(setClass('icon'));
49017
49018         // Vertices with tags get a fill.
49019         enter.filter(function(d) { return d.hasInterestingTags(); })
49020             .append('circle')
49021             .each(setClass('fill'));
49022
49023         groups
49024             .merge(enter)
49025             .attr('transform', svgPointTransform(projection))
49026             .classed('sibling', function(entity) { return entity.id in siblings; })
49027             .classed('shared', function(entity) { return graph.isShared(entity); })
49028             .classed('endpoint', function(entity) { return entity.isEndpoint(graph); })
49029             .call(setAttributes);
49030     }
49031
49032
49033     function drawVertices(selection$$1, graph, entities, filter, extent$$1, zoom$$1) {
49034         var siblings = siblingAndChildVertices(context.selectedIDs(), graph, extent$$1),
49035             wireframe = context.surface().classed('fill-wireframe'),
49036             vertices = [];
49037
49038         for (var i = 0; i < entities.length; i++) {
49039             var entity = entities[i],
49040                 geometry = entity.geometry(graph);
49041
49042             if (wireframe && geometry === 'point') {
49043                 vertices.push(entity);
49044                 continue;
49045             }
49046
49047             if (geometry !== 'vertex')
49048                 continue;
49049
49050             if (entity.id in siblings ||
49051                 entity.hasInterestingTags() ||
49052                 entity.isEndpoint(graph) ||
49053                 entity.isConnected(graph)) {
49054                 vertices.push(entity);
49055             }
49056         }
49057
49058         var layer = selection$$1.selectAll('.layer-hit');
49059         layer.selectAll('g.vertex.vertex-persistent')
49060             .filter(filter)
49061             .call(draw, vertices, 'vertex-persistent', graph, zoom$$1, siblings);
49062
49063         drawHover(selection$$1, graph, extent$$1, zoom$$1);
49064     }
49065
49066
49067     function drawHover(selection$$1, graph, extent$$1, zoom$$1) {
49068         var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent$$1) : {};
49069         var layer = selection$$1.selectAll('.layer-hit');
49070
49071         layer.selectAll('g.vertex.vertex-hover')
49072             .call(draw, values(hovered), 'vertex-hover', graph, zoom$$1);
49073     }
49074
49075
49076     drawVertices.drawHover = function(selection$$1, graph, target, extent$$1, zoom$$1) {
49077         if (target === hover) return;
49078         hover = target;
49079         drawHover(selection$$1, graph, extent$$1, zoom$$1);
49080     };
49081
49082     return drawVertices;
49083 }
49084
49085 function behaviorEdit(context) {
49086
49087     function edit() {
49088         context.map()
49089             .minzoom(context.minEditableZoom());
49090     }
49091
49092
49093     edit.off = function() {
49094         context.map()
49095             .minzoom(0);
49096     };
49097
49098
49099     return edit;
49100 }
49101
49102 /*
49103    The hover behavior adds the `.hover` class on mouseover to all elements to which
49104    the identical datum is bound, and removes it on mouseout.
49105
49106    The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
49107    representation may consist of several elements scattered throughout the DOM hierarchy.
49108    Only one of these elements can have the :hover pseudo-class, but all of them will
49109    have the .hover class.
49110  */
49111 function behaviorHover(context) {
49112     var dispatch$$1 = dispatch('hover'),
49113         _selection = select(null),
49114         newId = null,
49115         buttonDown,
49116         altDisables,
49117         target;
49118
49119
49120     function keydown() {
49121         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
49122             _selection.selectAll('.hover')
49123                 .classed('hover-suppressed', true)
49124                 .classed('hover', false);
49125
49126             _selection
49127                 .classed('hover-disabled', true);
49128
49129             dispatch$$1.call('hover', this, null);
49130         }
49131     }
49132
49133
49134     function keyup() {
49135         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
49136             _selection.selectAll('.hover-suppressed')
49137                 .classed('hover-suppressed', false)
49138                 .classed('hover', true);
49139
49140             _selection
49141                 .classed('hover-disabled', false);
49142
49143             dispatch$$1.call('hover', this, target ? target.id : null);
49144         }
49145     }
49146
49147
49148     var hover = function(selection$$1) {
49149         _selection = selection$$1;
49150         newId = null;
49151
49152         _selection
49153             .on('mouseover.hover', mouseover)
49154             .on('mouseout.hover', mouseout)
49155             .on('mousedown.hover', mousedown);
49156
49157         select(window)
49158             .on('keydown.hover', keydown)
49159             .on('keyup.hover', keyup);
49160
49161
49162         function mouseover() {
49163             if (buttonDown) return;
49164             var target = event.target;
49165             enter(target ? target.__data__ : null);
49166         }
49167
49168
49169         function mouseout() {
49170             if (buttonDown) return;
49171             var target = event.relatedTarget;
49172             enter(target ? target.__data__ : null);
49173         }
49174
49175
49176         function mousedown() {
49177             buttonDown = true;
49178             select(window)
49179                 .on('mouseup.hover', mouseup, true);
49180         }
49181
49182
49183         function mouseup() {
49184             buttonDown = false;
49185             select(window)
49186                 .on('mouseup.hover', null, true);
49187         }
49188
49189
49190         function enter(d) {
49191             if (d === target) return;
49192             target = d;
49193
49194             _selection.selectAll('.hover')
49195                 .classed('hover', false);
49196             _selection.selectAll('.hover-suppressed')
49197                 .classed('hover-suppressed', false);
49198
49199             if (target instanceof osmEntity$$1 && target.id !== newId) {
49200
49201                 // If drawing a way, don't hover on a node that was just placed. #3974
49202                 var mode = context.mode() && context.mode().id;
49203                 if ((mode === 'draw-line' || mode === 'draw-area') && !newId && target.type === 'node') {
49204                     newId = target.id;
49205                     return;
49206                 }
49207
49208                 var selector$$1 = '.' + target.id;
49209
49210                 if (target.type === 'relation') {
49211                     target.members.forEach(function(member) {
49212                         selector$$1 += ', .' + member.id;
49213                     });
49214                 }
49215
49216                 var suppressed = altDisables && event && event.altKey;
49217
49218                 _selection.selectAll(selector$$1)
49219                     .classed(suppressed ? 'hover-suppressed' : 'hover', true);
49220
49221                 dispatch$$1.call('hover', this, !suppressed && target.id);
49222
49223             } else {
49224                 dispatch$$1.call('hover', this, null);
49225             }
49226         }
49227
49228     };
49229
49230
49231     hover.off = function(selection$$1) {
49232         selection$$1.selectAll('.hover')
49233             .classed('hover', false);
49234         selection$$1.selectAll('.hover-suppressed')
49235             .classed('hover-suppressed', false);
49236         selection$$1
49237             .classed('hover-disabled', false);
49238
49239
49240         selection$$1
49241             .on('mouseover.hover', null)
49242             .on('mouseout.hover', null)
49243             .on('mousedown.hover', null);
49244
49245         select(window)
49246             .on('keydown.hover', null)
49247             .on('keyup.hover', null);
49248     };
49249
49250
49251     hover.altDisables = function(_) {
49252         if (!arguments.length) return altDisables;
49253         altDisables = _;
49254         return hover;
49255     };
49256
49257
49258     return utilRebind(hover, dispatch$$1, 'on');
49259 }
49260
49261 function behaviorTail() {
49262     var text$$1,
49263         container,
49264         xmargin = 25,
49265         tooltipSize = [0, 0],
49266         selectionSize = [0, 0];
49267
49268
49269     function tail(selection$$1) {
49270         if (!text$$1) return;
49271
49272         select(window)
49273             .on('resize.tail', function() { selectionSize = utilGetDimensions(selection$$1); });
49274
49275         container = select(document.body)
49276             .append('div')
49277             .style('display', 'none')
49278             .attr('class', 'tail tooltip-inner');
49279
49280         container.append('div')
49281             .text(text$$1);
49282
49283         selection$$1
49284             .on('mousemove.tail', mousemove)
49285             .on('mouseenter.tail', mouseenter)
49286             .on('mouseleave.tail', mouseleave);
49287
49288         container
49289             .on('mousemove.tail', mousemove);
49290
49291         tooltipSize = utilGetDimensions(container);
49292         selectionSize = utilGetDimensions(selection$$1);
49293
49294
49295         function show() {
49296             container.style('display', 'block');
49297             tooltipSize = utilGetDimensions(container);
49298         }
49299
49300
49301         function mousemove() {
49302             if (container.style('display') === 'none') show();
49303             var xoffset = ((event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
49304                 -tooltipSize[0] - xmargin : xmargin;
49305             container.classed('left', xoffset > 0);
49306             utilSetTransform(container, event.clientX + xoffset, event.clientY);
49307         }
49308
49309
49310         function mouseleave() {
49311             if (event.relatedTarget !== container.node()) {
49312                 container.style('display', 'none');
49313             }
49314         }
49315
49316
49317         function mouseenter() {
49318             if (event.relatedTarget !== container.node()) {
49319                 show();
49320             }
49321         }
49322     }
49323
49324
49325     tail.off = function(selection$$1) {
49326         if (!text$$1) return;
49327
49328         container
49329             .on('mousemove.tail', null)
49330             .remove();
49331
49332         selection$$1
49333             .on('mousemove.tail', null)
49334             .on('mouseenter.tail', null)
49335             .on('mouseleave.tail', null);
49336
49337         select(window)
49338             .on('resize.tail', null);
49339     };
49340
49341
49342     tail.text = function(_) {
49343         if (!arguments.length) return text$$1;
49344         text$$1 = _;
49345         return tail;
49346     };
49347
49348
49349     return tail;
49350 }
49351
49352 var usedTails = {};
49353 var disableSpace = false;
49354 var lastSpace = null;
49355
49356
49357 function behaviorDraw(context) {
49358     var dispatch$$1 = dispatch('move', 'click', 'clickWay',
49359             'clickNode', 'undo', 'cancel', 'finish'),
49360         keybinding = d3keybinding('draw'),
49361         hover = behaviorHover(context)
49362             .altDisables(true)
49363             .on('hover', context.ui().sidebar.hover),
49364         tail = behaviorTail(),
49365         edit = behaviorEdit(context),
49366         closeTolerance = 4,
49367         tolerance = 12,
49368         mouseLeave = false,
49369         lastMouse = null;
49370
49371
49372     function datum() {
49373         if (event.altKey) return {};
49374
49375         if (event.type === 'keydown') {
49376             return (lastMouse && lastMouse.target.__data__) || {};
49377         } else {
49378             return event.target.__data__ || {};
49379         }
49380     }
49381
49382
49383     function mousedown() {
49384
49385         function point() {
49386             var p = context.container().node();
49387             return touchId !== null ? touches(p).filter(function(p) {
49388                 return p.identifier === touchId;
49389             })[0] : mouse(p);
49390         }
49391
49392         var element = select(this),
49393             touchId = event.touches ? event.changedTouches[0].identifier : null,
49394             t1 = +new Date(),
49395             p1 = point();
49396
49397         element.on('mousemove.draw', null);
49398
49399         select(window).on('mouseup.draw', function() {
49400             var t2 = +new Date(),
49401                 p2 = point(),
49402                 dist = geoEuclideanDistance(p1, p2);
49403
49404             element.on('mousemove.draw', mousemove);
49405             select(window).on('mouseup.draw', null);
49406
49407             if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
49408                 // Prevent a quick second click
49409                 select(window).on('click.draw-block', function() {
49410                     event.stopPropagation();
49411                 }, true);
49412
49413                 context.map().dblclickEnable(false);
49414
49415                 window.setTimeout(function() {
49416                     context.map().dblclickEnable(true);
49417                     select(window).on('click.draw-block', null);
49418                 }, 500);
49419
49420                 click();
49421             }
49422         }, true);
49423     }
49424
49425
49426     function mousemove() {
49427         lastMouse = event;
49428         dispatch$$1.call('move', this, datum());
49429     }
49430
49431
49432     function mouseenter() {
49433         mouseLeave = false;
49434     }
49435
49436
49437     function mouseleave() {
49438         mouseLeave = true;
49439     }
49440
49441
49442     function click() {
49443         var d = datum();
49444         if (d.type === 'way') {
49445             var dims = context.map().dimensions(),
49446                 mouse$$1 = context.mouse(),
49447                 pad = 5,
49448                 trySnap = mouse$$1[0] > pad && mouse$$1[0] < dims[0] - pad &&
49449                     mouse$$1[1] > pad && mouse$$1[1] < dims[1] - pad;
49450
49451             if (trySnap) {
49452                 var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection),
49453                     edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
49454                 dispatch$$1.call('clickWay', this, choice.loc, edge);
49455             } else {
49456                 dispatch$$1.call('click', this, context.map().mouseCoordinates());
49457             }
49458
49459         } else if (d.type === 'node') {
49460             dispatch$$1.call('clickNode', this, d);
49461
49462         } else {
49463             dispatch$$1.call('click', this, context.map().mouseCoordinates());
49464         }
49465     }
49466
49467
49468     function space() {
49469         event.preventDefault();
49470         event.stopPropagation();
49471
49472         var currSpace = context.mouse();
49473         if (disableSpace && lastSpace) {
49474             var dist = geoEuclideanDistance(lastSpace, currSpace);
49475             if (dist > tolerance) {
49476                 disableSpace = false;
49477             }
49478         }
49479
49480         if (disableSpace || mouseLeave || !lastMouse) return;
49481
49482         // user must move mouse or release space bar to allow another click
49483         lastSpace = currSpace;
49484         disableSpace = true;
49485
49486         select(window).on('keyup.space-block', function() {
49487             event.preventDefault();
49488             event.stopPropagation();
49489             disableSpace = false;
49490             select(window).on('keyup.space-block', null);
49491         });
49492
49493         click();
49494     }
49495
49496
49497     function backspace() {
49498         event.preventDefault();
49499         dispatch$$1.call('undo');
49500     }
49501
49502
49503     function del() {
49504         event.preventDefault();
49505         dispatch$$1.call('cancel');
49506     }
49507
49508
49509     function ret() {
49510         event.preventDefault();
49511         dispatch$$1.call('finish');
49512     }
49513
49514
49515     function draw(selection$$1) {
49516         context.install(hover);
49517         context.install(edit);
49518
49519         if (!context.inIntro() && !usedTails[tail.text()]) {
49520             context.install(tail);
49521         }
49522
49523         keybinding
49524             .on('⌫', backspace)
49525             .on('⌦', del)
49526             .on('⎋', ret)
49527             .on('↩', ret)
49528             .on('space', space)
49529             .on('⌥space', space);
49530
49531         selection$$1
49532             .on('mouseenter.draw', mouseenter)
49533             .on('mouseleave.draw', mouseleave)
49534             .on('mousedown.draw', mousedown)
49535             .on('mousemove.draw', mousemove);
49536
49537         select(document)
49538             .call(keybinding);
49539
49540         return draw;
49541     }
49542
49543
49544     draw.off = function(selection$$1) {
49545         context.ui().sidebar.hover.cancel();
49546         context.uninstall(hover);
49547         context.uninstall(edit);
49548
49549         if (!context.inIntro() && !usedTails[tail.text()]) {
49550             context.uninstall(tail);
49551             usedTails[tail.text()] = true;
49552         }
49553
49554         selection$$1
49555             .on('mouseenter.draw', null)
49556             .on('mouseleave.draw', null)
49557             .on('mousedown.draw', null)
49558             .on('mousemove.draw', null);
49559
49560         select(window)
49561             .on('mouseup.draw', null);
49562             // note: keyup.space-block, click.draw-block should remain
49563
49564         select(document)
49565             .call(keybinding.off);
49566     };
49567
49568
49569     draw.tail = function(_) {
49570         tail.text(_);
49571         return draw;
49572     };
49573
49574
49575     return utilRebind(draw, dispatch$$1, 'on');
49576 }
49577
49578 function behaviorAddWay(context) {
49579     var dispatch$$1 = dispatch('start', 'startFromWay', 'startFromNode'),
49580         draw = behaviorDraw(context);
49581
49582     var addWay = function(surface) {
49583         draw.on('click', function() { dispatch$$1.apply('start', this, arguments); })
49584             .on('clickWay', function() { dispatch$$1.apply('startFromWay', this, arguments); })
49585             .on('clickNode', function() { dispatch$$1.apply('startFromNode', this, arguments); })
49586             .on('cancel', addWay.cancel)
49587             .on('finish', addWay.cancel);
49588
49589         context.map()
49590             .dblclickEnable(false);
49591
49592         surface.call(draw);
49593     };
49594
49595
49596     addWay.off = function(surface) {
49597         surface.call(draw.off);
49598     };
49599
49600
49601     addWay.cancel = function() {
49602         window.setTimeout(function() {
49603             context.map().dblclickEnable(true);
49604         }, 1000);
49605
49606         context.enter(modeBrowse(context));
49607     };
49608
49609
49610     addWay.tail = function(text$$1) {
49611         draw.tail(text$$1);
49612         return addWay;
49613     };
49614
49615
49616     return utilRebind(addWay, dispatch$$1, 'on');
49617 }
49618
49619 function behaviorBreathe() {
49620     var duration = 800,
49621         steps = 4,
49622         selector$$1 = '.selected.shadow, .selected .shadow',
49623         selected = select(null),
49624         classed = '',
49625         params = {},
49626         done = false,
49627         timer$$1;
49628
49629
49630     function ratchetyInterpolator(a, b, steps, units) {
49631         a = parseFloat(a);
49632         b = parseFloat(b);
49633         var sample = quantize$1()
49634             .domain([0, 1])
49635             .range(quantize(reinterpolate(a, b), steps));
49636
49637         return function(t) {
49638             return String(sample(t)) + (units || '');
49639         };
49640     }
49641
49642
49643     function reset(selection$$1) {
49644         selection$$1
49645             .style('stroke-opacity', null)
49646             .style('stroke-width', null)
49647             .style('fill-opacity', null)
49648             .style('r', null);
49649     }
49650
49651
49652     function setAnimationParams(transition$$1, fromTo) {
49653         var toFrom = (fromTo === 'from' ? 'to' : 'from');
49654
49655         transition$$1
49656             .styleTween('stroke-opacity', function(d) {
49657                 return ratchetyInterpolator(
49658                     params[d.id][toFrom].opacity,
49659                     params[d.id][fromTo].opacity,
49660                     steps
49661                 );
49662             })
49663             .styleTween('stroke-width', function(d) {
49664                 return ratchetyInterpolator(
49665                     params[d.id][toFrom].width,
49666                     params[d.id][fromTo].width,
49667                     steps,
49668                     'px'
49669                 );
49670             })
49671             .styleTween('fill-opacity', function(d) {
49672                 return ratchetyInterpolator(
49673                     params[d.id][toFrom].opacity,
49674                     params[d.id][fromTo].opacity,
49675                     steps
49676                 );
49677             })
49678             .styleTween('r', function(d) {
49679                 return ratchetyInterpolator(
49680                     params[d.id][toFrom].width,
49681                     params[d.id][fromTo].width,
49682                     steps,
49683                     'px'
49684                 );
49685             });
49686     }
49687
49688
49689     function calcAnimationParams(selection$$1) {
49690         selection$$1
49691             .call(reset)
49692             .each(function(d) {
49693                 var s = select(this),
49694                     tag = s.node().tagName,
49695                     p = {'from': {}, 'to': {}},
49696                     opacity, width;
49697
49698                 // determine base opacity and width
49699                 if (tag === 'circle') {
49700                     opacity = parseFloat(s.style('fill-opacity') || 0.5);
49701                     width = parseFloat(s.style('r') || 15.5);
49702                 } else {
49703                     opacity = parseFloat(s.style('stroke-opacity') || 0.7);
49704                     width = parseFloat(s.style('stroke-width') || 10);
49705                 }
49706
49707                 // calculate from/to interpolation params..
49708                 p.tag = tag;
49709                 p.from.opacity = opacity * 0.6;
49710                 p.to.opacity = opacity * 1.25;
49711                 p.from.width = width * 0.7;
49712                 p.to.width = width * (tag === 'circle' ? 1.5 : 1);
49713                 params[d.id] = p;
49714             });
49715     }
49716
49717
49718     function run(surface, fromTo) {
49719         var toFrom = (fromTo === 'from' ? 'to' : 'from'),
49720             currSelected = surface.selectAll(selector$$1),
49721             currClassed = surface.attr('class');
49722
49723         if (done || currSelected.empty()) {
49724             selected.call(reset);
49725             return;
49726         }
49727
49728         if (!lodash.isEqual(currSelected.data(), selected.data()) || currClassed !== classed) {
49729             selected.call(reset);
49730             classed = currClassed;
49731             selected = currSelected.call(calcAnimationParams);
49732         }
49733
49734         selected
49735             .transition()
49736             .duration(duration)
49737             .call(setAnimationParams, fromTo)
49738             .on('end', function() {
49739                 surface.call(run, toFrom);
49740             });
49741     }
49742
49743
49744     var breathe = function(surface) {
49745         done = false;
49746         timer$$1 = timer(function() {
49747             // wait for elements to actually become selected
49748             if (surface.selectAll(selector$$1).empty()) {
49749                 return false;
49750             }
49751
49752             surface.call(run, 'from');
49753             timer$$1.stop();
49754             return true;
49755         }, 20);
49756     };
49757
49758
49759     breathe.off = function() {
49760         done = true;
49761         if (timer$$1) {
49762             timer$$1.stop();
49763         }
49764         selected
49765             .interrupt()
49766             .call(reset);
49767     };
49768
49769
49770     return breathe;
49771 }
49772
49773 function behaviorCopy(context) {
49774     var keybinding = d3keybinding('copy');
49775
49776
49777     function groupEntities(ids, graph) {
49778         var entities = ids.map(function (id) { return graph.entity(id); });
49779         return lodash.extend({relation: [], way: [], node: []},
49780             lodash.groupBy(entities, function(entity) { return entity.type; }));
49781     }
49782
49783
49784     function getDescendants(id, graph, descendants) {
49785         var entity = graph.entity(id),
49786             i, children;
49787
49788         descendants = descendants || {};
49789
49790         if (entity.type === 'relation') {
49791             children = lodash.map(entity.members, 'id');
49792         } else if (entity.type === 'way') {
49793             children = entity.nodes;
49794         } else {
49795             children = [];
49796         }
49797
49798         for (i = 0; i < children.length; i++) {
49799             if (!descendants[children[i]]) {
49800                 descendants[children[i]] = true;
49801                 descendants = getDescendants(children[i], graph, descendants);
49802             }
49803         }
49804
49805         return descendants;
49806     }
49807
49808
49809     function doCopy() {
49810         event.preventDefault();
49811
49812         var graph = context.graph(),
49813             selected = groupEntities(context.selectedIDs(), graph),
49814             canCopy = [],
49815             skip = {},
49816             i, entity;
49817
49818         for (i = 0; i < selected.relation.length; i++) {
49819             entity = selected.relation[i];
49820             if (!skip[entity.id] && entity.isComplete(graph)) {
49821                 canCopy.push(entity.id);
49822                 skip = getDescendants(entity.id, graph, skip);
49823             }
49824         }
49825         for (i = 0; i < selected.way.length; i++) {
49826             entity = selected.way[i];
49827             if (!skip[entity.id]) {
49828                 canCopy.push(entity.id);
49829                 skip = getDescendants(entity.id, graph, skip);
49830             }
49831         }
49832         for (i = 0; i < selected.node.length; i++) {
49833             entity = selected.node[i];
49834             if (!skip[entity.id]) {
49835                 canCopy.push(entity.id);
49836             }
49837         }
49838
49839         context.copyIDs(canCopy);
49840     }
49841
49842
49843     function copy() {
49844         keybinding.on(uiCmd('⌘C'), doCopy);
49845         select(document).call(keybinding);
49846         return copy;
49847     }
49848
49849
49850     copy.off = function() {
49851         select(document).call(keybinding.off);
49852     };
49853
49854
49855     return copy;
49856 }
49857
49858 /*
49859     `behaviorDrag` is like `d3.behavior.drag`, with the following differences:
49860
49861     * The `origin` function is expected to return an [x, y] tuple rather than an
49862       {x, y} object.
49863     * The events are `start`, `move`, and `end`.
49864       (https://github.com/mbostock/d3/issues/563)
49865     * The `start` event is not dispatched until the first cursor movement occurs.
49866       (https://github.com/mbostock/d3/pull/368)
49867     * The `move` event has a `point` and `delta` [x, y] tuple properties rather
49868       than `x`, `y`, `dx`, and `dy` properties.
49869     * The `end` event is not dispatched if no movement occurs.
49870     * An `off` function is available that unbinds the drag's internal event handlers.
49871  */
49872
49873 function behaviorDrag() {
49874     var event$$1 = dispatch('start', 'move', 'end'),
49875         origin = null,
49876         selector$$1 = '',
49877         filter = null,
49878         event_, target, surface;
49879
49880
49881     var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect'),
49882         d3_event_userSelectSuppress = function() {
49883             var selection$$1 = selection(),
49884                 select$$1 = selection$$1.style(d3_event_userSelectProperty);
49885             selection$$1.style(d3_event_userSelectProperty, 'none');
49886             return function() {
49887                 selection$$1.style(d3_event_userSelectProperty, select$$1);
49888             };
49889         };
49890
49891
49892     function d3_eventCancel() {
49893         event.stopPropagation();
49894         event.preventDefault();
49895     }
49896
49897
49898     function eventOf(thiz, argumentz) {
49899         return function(e1) {
49900             e1.target = drag$$1;
49901             customEvent(e1, event$$1.apply, event$$1, [e1.type, thiz, argumentz]);
49902         };
49903     }
49904
49905
49906     function dragstart() {
49907         target = this;
49908         event_ = eventOf(target, arguments);
49909
49910         var eventTarget = event.target,
49911             touchId = event.touches ? event.changedTouches[0].identifier : null,
49912             offset,
49913             origin_ = point(),
49914             started = false,
49915             selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
49916
49917         select(window)
49918             .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
49919             .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
49920
49921         if (origin) {
49922             offset = origin.apply(target, arguments);
49923             offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
49924         } else {
49925             offset = [0, 0];
49926         }
49927
49928         if (touchId === null) {
49929             event.stopPropagation();
49930         }
49931
49932
49933         function point() {
49934             var p = surface || target.parentNode;
49935             return touchId !== null ? touches(p).filter(function(p) {
49936                 return p.identifier === touchId;
49937             })[0] : mouse(p);
49938         }
49939
49940
49941         function dragmove() {
49942             var p = point(),
49943                 dx = p[0] - origin_[0],
49944                 dy = p[1] - origin_[1];
49945
49946             if (dx === 0 && dy === 0)
49947                 return;
49948
49949             if (!started) {
49950                 started = true;
49951                 event_({ type: 'start' });
49952             }
49953
49954             origin_ = p;
49955             d3_eventCancel();
49956
49957             event_({
49958                 type: 'move',
49959                 point: [p[0] + offset[0],  p[1] + offset[1]],
49960                 delta: [dx, dy]
49961             });
49962         }
49963
49964
49965         function dragend() {
49966             if (started) {
49967                 event_({ type: 'end' });
49968
49969                 d3_eventCancel();
49970                 if (event.target === eventTarget) {
49971                     select(window)
49972                         .on('click.drag', click, true);
49973                 }
49974             }
49975
49976             select(window)
49977                 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
49978                 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
49979
49980             selectEnable();
49981         }
49982
49983
49984         function click() {
49985             d3_eventCancel();
49986             select(window)
49987                 .on('click.drag', null);
49988         }
49989     }
49990
49991
49992     function drag$$1(selection$$1) {
49993         var matchesSelector = utilPrefixDOMProperty('matchesSelector'),
49994             delegate = dragstart;
49995
49996         if (selector$$1) {
49997             delegate = function() {
49998                 var root = this,
49999                     target = event.target;
50000                 for (; target && target !== root; target = target.parentNode) {
50001                     if (target[matchesSelector](selector$$1) &&
50002                             (!filter || filter(target.__data__))) {
50003                         return dragstart.call(target, target.__data__);
50004                     }
50005                 }
50006             };
50007         }
50008
50009         selection$$1
50010             .on('mousedown.drag' + selector$$1, delegate)
50011             .on('touchstart.drag' + selector$$1, delegate);
50012     }
50013
50014
50015     drag$$1.off = function(selection$$1) {
50016         selection$$1
50017             .on('mousedown.drag' + selector$$1, null)
50018             .on('touchstart.drag' + selector$$1, null);
50019     };
50020
50021
50022     drag$$1.selector = function(_) {
50023         if (!arguments.length) return selector$$1;
50024         selector$$1 = _;
50025         return drag$$1;
50026     };
50027
50028
50029     drag$$1.filter = function(_) {
50030         if (!arguments.length) return origin;
50031         filter = _;
50032         return drag$$1;
50033     };
50034
50035
50036     drag$$1.origin = function (_) {
50037         if (!arguments.length) return origin;
50038         origin = _;
50039         return drag$$1;
50040     };
50041
50042
50043     drag$$1.cancel = function() {
50044         select(window)
50045             .on('mousemove.drag', null)
50046             .on('mouseup.drag', null);
50047         return drag$$1;
50048     };
50049
50050
50051     drag$$1.target = function() {
50052         if (!arguments.length) return target;
50053         target = arguments[0];
50054         event_ = eventOf(target, Array.prototype.slice.call(arguments, 1));
50055         return drag$$1;
50056     };
50057
50058
50059     drag$$1.surface = function() {
50060         if (!arguments.length) return surface;
50061         surface = arguments[0];
50062         return drag$$1;
50063     };
50064
50065
50066     return utilRebind(drag$$1, event$$1, 'on');
50067 }
50068
50069 function behaviorDrawWay(context, wayId, index, mode, startGraph) {
50070
50071     var origWay = context.entity(wayId),
50072         isArea = context.geometry(wayId) === 'area',
50073         tempEdits = 0,
50074         annotation = t((origWay.isDegenerate() ?
50075             'operations.start.annotation.' :
50076             'operations.continue.annotation.') + context.geometry(wayId)),
50077         draw = behaviorDraw(context),
50078         startIndex,
50079         start,
50080         end,
50081         segment;
50082
50083
50084     // initialize the temporary drawing entities
50085     if (!isArea) {
50086         startIndex = typeof index === 'undefined' ? origWay.nodes.length - 1 : 0;
50087         start = osmNode({ id: 'nStart', loc: context.entity(origWay.nodes[startIndex]).loc });
50088         end = osmNode({ id: 'nEnd', loc: context.map().mouseCoordinates() });
50089         segment = osmWay({ id: 'wTemp',
50090             nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
50091             tags: lodash.clone(origWay.tags)
50092         });
50093     } else {
50094         end = osmNode({ loc: context.map().mouseCoordinates() });
50095     }
50096
50097     // Push an annotated state for undo to return back to.
50098     // We must make sure to remove this edit later.
50099     context.perform(actionNoop(), annotation);
50100     tempEdits++;
50101
50102     // Add the temporary drawing entities to the graph.
50103     // We must make sure to remove this edit later.
50104     context.perform(AddDrawEntities());
50105     tempEdits++;
50106
50107
50108     function move(datum) {
50109         var loc;
50110
50111         if (datum.type === 'node' && datum.id !== end.id) {
50112             loc = datum.loc;
50113
50114         } else if (datum.type === 'way') {
50115             var dims = context.map().dimensions(),
50116                 mouse = context.mouse(),
50117                 pad = 5,
50118                 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
50119                     mouse[1] > pad && mouse[1] < dims[1] - pad;
50120
50121             if (trySnap) {
50122                 loc = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
50123             }
50124         }
50125
50126         if (!loc) {
50127             loc = context.map().mouseCoordinates();
50128         }
50129
50130         context.replace(actionMoveNode(end.id, loc));
50131         end = context.entity(end.id);
50132     }
50133
50134
50135     function undone() {
50136         // Undo popped the history back to the initial annotated no-op edit.
50137         // Remove initial no-op edit and whatever edit happened immediately before it.
50138         context.pop(2);
50139         tempEdits = 0;
50140
50141         if (context.hasEntity(wayId)) {
50142             context.enter(mode);
50143         } else {
50144             context.enter(modeBrowse(context));
50145         }
50146     }
50147
50148
50149     function setActiveElements() {
50150         var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
50151         context.surface().selectAll(utilEntitySelector(active))
50152             .classed('active', true);
50153     }
50154
50155
50156     var drawWay = function(surface) {
50157         draw.on('move', move)
50158             .on('click', drawWay.add)
50159             .on('clickWay', drawWay.addWay)
50160             .on('clickNode', drawWay.addNode)
50161             .on('undo', context.undo)
50162             .on('cancel', drawWay.cancel)
50163             .on('finish', drawWay.finish);
50164
50165         context.map()
50166             .dblclickEnable(false)
50167             .on('drawn.draw', setActiveElements);
50168
50169         setActiveElements();
50170
50171         surface.call(draw);
50172
50173         context.history()
50174             .on('undone.draw', undone);
50175     };
50176
50177
50178     drawWay.off = function(surface) {
50179         // Drawing was interrupted unexpectedly.
50180         // This can happen if the user changes modes,
50181         // clicks geolocate button, a hashchange event occurs, etc.
50182         if (tempEdits) {
50183             context.pop(tempEdits);
50184             while (context.graph() !== startGraph) {
50185                 context.pop();
50186             }
50187         }
50188
50189         context.map()
50190             .on('drawn.draw', null);
50191
50192         surface.call(draw.off)
50193             .selectAll('.active')
50194             .classed('active', false);
50195
50196         context.history()
50197             .on('undone.draw', null);
50198     };
50199
50200
50201     function AddDrawEntities() {
50202         return function(graph) {
50203             if (isArea) {
50204                 // For area drawing, there is no need for a temporary node.
50205                 // `end` gets inserted into the way as the penultimate node.
50206                 return graph
50207                     .replace(end)
50208                     .replace(origWay.addNode(end.id));
50209             } else {
50210                 // For line drawing, add a temporary start, end, and segment to the graph.
50211                 // This allows us to class the new segment as `active`, but still
50212                 // connect it back to parts of the way that have already been drawn.
50213                 return graph
50214                     .replace(start)
50215                     .replace(end)
50216                     .replace(segment);
50217             }
50218         };
50219     }
50220
50221
50222     function ReplaceDrawEntities(newNode) {
50223         return function(graph) {
50224             if (isArea) {
50225                 // For area drawing, we didn't create a temporary node.
50226                 // `newNode` gets inserted into the _original_ way as the penultimate node.
50227                 return graph
50228                     .replace(origWay.addNode(newNode.id))
50229                     .remove(end);
50230             } else {
50231                 // For line drawing, add the `newNode` to the way at specified index,
50232                 // and remove the temporary start, end, and segment.
50233                 return graph
50234                     .replace(origWay.addNode(newNode.id, index))
50235                     .remove(end)
50236                     .remove(segment)
50237                     .remove(start);
50238             }
50239         };
50240     }
50241
50242
50243     // Accept the current position of the temporary node and continue drawing.
50244     drawWay.add = function(loc) {
50245         // prevent duplicate nodes
50246         var last = context.hasEntity(origWay.nodes[origWay.nodes.length - (isArea ? 2 : 1)]);
50247         if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
50248
50249         context.pop(tempEdits);
50250
50251         if (isArea) {
50252             context.perform(
50253                 AddDrawEntities(),
50254                 annotation
50255             );
50256         } else {
50257             var newNode = osmNode({loc: loc});
50258             context.perform(
50259                 actionAddEntity(newNode),
50260                 ReplaceDrawEntities(newNode),
50261                 annotation
50262             );
50263         }
50264
50265         tempEdits = 0;
50266         context.enter(mode);
50267     };
50268
50269
50270     // Connect the way to an existing way.
50271     drawWay.addWay = function(loc, edge) {
50272         if (isArea) {
50273             context.pop(tempEdits);
50274
50275             context.perform(
50276                 AddDrawEntities(),
50277                 actionAddMidpoint({ loc: loc, edge: edge}, end),
50278                 annotation
50279             );
50280         } else {
50281             var previousEdge = startIndex ?
50282                 [origWay.nodes[startIndex], origWay.nodes[startIndex - 1]] :
50283                 [origWay.nodes[0], origWay.nodes[1]];
50284
50285             // Avoid creating duplicate segments
50286             if (geoEdgeEqual(edge, previousEdge))
50287                 return;
50288
50289             context.pop(tempEdits);
50290
50291             var newNode = osmNode({ loc: loc });
50292             context.perform(
50293                 actionAddMidpoint({ loc: loc, edge: edge}, newNode),
50294                 ReplaceDrawEntities(newNode),
50295                 annotation
50296             );
50297         }
50298
50299         tempEdits = 0;
50300         context.enter(mode);
50301     };
50302
50303
50304     // Connect the way to an existing node and continue drawing.
50305     drawWay.addNode = function(node) {
50306         // Avoid creating duplicate segments
50307         if (origWay.areAdjacent(node.id, origWay.nodes[origWay.nodes.length - 1])) return;
50308
50309         // Clicks should not occur on the drawing node, however a space keypress can
50310         // sometimes grab that node's datum (before it gets classed as `active`?)  #4016
50311         if (node.id === end.id) {
50312             drawWay.add(node.loc);
50313             return;
50314         }
50315
50316         context.pop(tempEdits);
50317
50318         context.perform(
50319             ReplaceDrawEntities(node),
50320             annotation
50321         );
50322
50323         tempEdits = 0;
50324         context.enter(mode);
50325     };
50326
50327
50328     // Finish the draw operation, removing the temporary edits.
50329     // If the way has enough nodes to be valid, it's selected.
50330     // Otherwise, delete everything and return to browse mode.
50331     drawWay.finish = function() {
50332         context.pop(tempEdits);
50333         tempEdits = 0;
50334
50335         var way = context.hasEntity(wayId);
50336         if (!way || way.isDegenerate()) {
50337             drawWay.cancel();
50338             return;
50339         }
50340
50341         window.setTimeout(function() {
50342             context.map().dblclickEnable(true);
50343         }, 1000);
50344
50345         context.enter(modeSelect(context, [wayId]).newFeature(true));
50346     };
50347
50348
50349     // Cancel the draw operation, delete everything, and return to browse mode.
50350     drawWay.cancel = function() {
50351         context.pop(tempEdits);
50352         tempEdits = 0;
50353
50354         while (context.graph() !== startGraph) {
50355             context.pop();
50356         }
50357
50358         window.setTimeout(function() {
50359             context.map().dblclickEnable(true);
50360         }, 1000);
50361
50362         context.enter(modeBrowse(context));
50363     };
50364
50365
50366     drawWay.tail = function(text) {
50367         draw.tail(text);
50368         return drawWay;
50369     };
50370
50371
50372     return drawWay;
50373 }
50374
50375 function behaviorHash(context) {
50376     var s0 = null, // cached window.location.hash
50377         lat = 90 - 1e-8; // allowable latitude range
50378
50379
50380     var parser = function(map$$1, s) {
50381         var q = utilStringQs(s);
50382         var args = (q.map || '').split('/').map(Number);
50383         if (args.length < 3 || args.some(isNaN)) {
50384             return true; // replace bogus hash
50385         } else if (s !== formatter(map$$1).slice(1)) {
50386             var mode = context.mode();
50387             if (mode && mode.id.match(/^draw/) !== null) {
50388                 context.enter(modeBrowse(context));
50389             }
50390             map$$1.centerZoom([args[2], Math.min(lat, Math.max(-lat, args[1]))], args[0]);
50391         }
50392     };
50393
50394
50395     var formatter = function(map$$1) {
50396         var center = map$$1.center(),
50397             zoom$$1 = map$$1.zoom(),
50398             precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2)),
50399             q = lodash.omit(utilStringQs(window.location.hash.substring(1)), 'comment'),
50400             newParams = {};
50401
50402         delete q.id;
50403         var selected = context.selectedIDs().filter(function(id) {
50404             return !context.entity(id).isNew();
50405         });
50406         if (selected.length) {
50407             newParams.id = selected.join(',');
50408         }
50409
50410         newParams.map = zoom$$1.toFixed(2) +
50411             '/' + center[1].toFixed(precision) +
50412             '/' + center[0].toFixed(precision);
50413
50414         return '#' + utilQsString(lodash.assign(q, newParams), true);
50415     };
50416
50417
50418     function update() {
50419         if (context.inIntro()) return;
50420         var s1 = formatter(context.map());
50421         if (s0 !== s1) {
50422             window.location.replace(s0 = s1);  // don't recenter the map!
50423         }
50424     }
50425
50426
50427     var throttledUpdate = lodash.throttle(update, 500);
50428
50429
50430     function hashchange() {
50431         if (window.location.hash === s0) return;  // ignore spurious hashchange events
50432         if (parser(context.map(), (s0 = window.location.hash).substring(1))) {
50433             update(); // replace bogus hash
50434         }
50435     }
50436
50437
50438     function hash() {
50439         context.map()
50440             .on('move.hash', throttledUpdate);
50441
50442         context
50443             .on('enter.hash', throttledUpdate);
50444
50445         select(window)
50446             .on('hashchange.hash', hashchange);
50447
50448         if (window.location.hash) {
50449             var q = utilStringQs(window.location.hash.substring(1));
50450             if (q.id) {
50451                 context.zoomToEntity(q.id.split(',')[0], !q.map);
50452             }
50453             if (q.comment) {
50454                 context.storage('comment', q.comment);
50455                 context.storage('commentDate', Date.now());
50456             }
50457             hashchange();
50458             if (q.map) hash.hadHash = true;
50459         }
50460     }
50461
50462
50463     hash.off = function() {
50464         throttledUpdate.cancel();
50465
50466         context.map()
50467             .on('move.hash', null);
50468
50469         context
50470             .on('enter.hash', null);
50471
50472         select(window)
50473             .on('hashchange.hash', null);
50474
50475         window.location.hash = '';
50476     };
50477
50478
50479     return hash;
50480 }
50481
50482 function behaviorLasso(context) {
50483
50484     var behavior = function(selection$$1) {
50485         var lasso;
50486
50487
50488         function mousedown() {
50489             var button = 0;  // left
50490             if (event.button === button && event.shiftKey === true) {
50491                 lasso = null;
50492
50493                 select(window)
50494                     .on('mousemove.lasso', mousemove)
50495                     .on('mouseup.lasso', mouseup);
50496
50497                 event.stopPropagation();
50498             }
50499         }
50500
50501
50502         function mousemove() {
50503             if (!lasso) {
50504                 lasso = uiLasso(context);
50505                 context.surface().call(lasso);
50506             }
50507
50508             lasso.p(context.mouse());
50509         }
50510
50511
50512         function normalize(a, b) {
50513             return [
50514                 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
50515                 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
50516         }
50517
50518
50519         function lassoed() {
50520             if (!lasso) return [];
50521
50522             var graph = context.graph(),
50523                 bounds = lasso.extent().map(context.projection.invert),
50524                 extent$$1 = geoExtent$$1(normalize(bounds[0], bounds[1]));
50525
50526             return lodash.map(context.intersects(extent$$1).filter(function(entity) {
50527                 return entity.type === 'node' &&
50528                     geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
50529                     !context.features().isHidden(entity, graph, entity.geometry(graph));
50530             }), 'id');
50531         }
50532
50533
50534         function mouseup() {
50535             select(window)
50536                 .on('mousemove.lasso', null)
50537                 .on('mouseup.lasso', null);
50538
50539             if (!lasso) return;
50540
50541             var ids = lassoed();
50542             lasso.close();
50543
50544             if (ids.length) {
50545                 context.enter(modeSelect(context, ids));
50546             }
50547         }
50548
50549         selection$$1
50550             .on('mousedown.lasso', mousedown);
50551     };
50552
50553
50554     behavior.off = function(selection$$1) {
50555         selection$$1.on('mousedown.lasso', null);
50556     };
50557
50558
50559     return behavior;
50560 }
50561
50562 /* Creates a keybinding behavior for an operation */
50563 function behaviorOperation() {
50564     var which, keybinding;
50565
50566
50567     function drawIcon(selection$$1) {
50568         var button = selection$$1
50569             .append('svg')
50570             .attr('class', 'operation-icon')
50571             .append('g')
50572             .attr('class', 'radial-menu-item radial-menu-item-' + which.id)
50573             .attr('transform', 'translate(10,10)')
50574             .classed('disabled', which.disabled());
50575
50576         button
50577             .append('circle')
50578             .attr('r', 9);
50579
50580         button
50581             .append('use')
50582             .attr('transform', 'translate(-7,-7)')
50583             .attr('width', '14')
50584             .attr('height', '14')
50585             .attr('xlink:href', '#operation-' + which.id);
50586
50587         return selection$$1;
50588     }
50589
50590
50591     var behavior = function () {
50592         if (which && which.available()) {
50593             keybinding = d3keybinding('behavior.key.' + which.id);
50594             keybinding.on(which.keys, function() {
50595                 event.preventDefault();
50596                 var disabled = which.disabled();
50597
50598                 if (disabled) {
50599                     uiFlash(3000)
50600                         .html('')
50601                         .call(drawIcon)
50602                         .append('div')
50603                         .attr('class', 'operation-tip')
50604                         .text(which.tooltip);
50605
50606                 } else {
50607                     uiFlash(1500)
50608                         .html('')
50609                         .call(drawIcon)
50610                         .append('div')
50611                         .attr('class', 'operation-tip')
50612                         .text(which.annotation() || which.title);
50613
50614                     which();
50615                 }
50616             });
50617             select(document).call(keybinding);
50618         }
50619         return behavior;
50620     };
50621
50622
50623     behavior.off = function() {
50624         if (keybinding) {
50625             select(document).call(keybinding.off);
50626         }
50627     };
50628
50629
50630     behavior.which = function (_) {
50631         if (!arguments.length) return which;
50632         which = _;
50633         return behavior;
50634     };
50635
50636
50637     return behavior;
50638 }
50639
50640 function behaviorPaste(context) {
50641     var keybinding = d3keybinding('paste');
50642
50643     function omitTag(v, k) {
50644         return (
50645             k === 'phone' ||
50646             k === 'fax' ||
50647             k === 'email' ||
50648             k === 'website' ||
50649             k === 'url' ||
50650             k === 'note' ||
50651             k === 'description' ||
50652             k.indexOf('name') !== -1 ||
50653             k.indexOf('wiki') === 0 ||
50654             k.indexOf('addr:') === 0 ||
50655             k.indexOf('contact:') === 0
50656         );
50657     }
50658
50659
50660     function doPaste() {
50661         event.preventDefault();
50662
50663         var baseGraph = context.graph(),
50664             mouse$$1 = context.mouse(),
50665             projection = context.projection,
50666             viewport = geoExtent$$1(projection.clipExtent()).polygon();
50667
50668         if (!geoPointInPolygon(mouse$$1, viewport)) return;
50669
50670         var extent$$1 = geoExtent$$1(),
50671             oldIDs = context.copyIDs(),
50672             oldGraph = context.copyGraph(),
50673             newIDs = [];
50674
50675         if (!oldIDs.length) return;
50676
50677         var action = actionCopyEntities(oldIDs, oldGraph);
50678         context.perform(action);
50679
50680         var copies = action.copies();
50681         var originals = lodash.invert(lodash.mapValues(copies, 'id'));
50682         for (var id in copies) {
50683             var oldEntity = oldGraph.entity(id),
50684                 newEntity = copies[id];
50685
50686             extent$$1._extend(oldEntity.extent(oldGraph));
50687             context.perform(
50688                 actionChangeTags(newEntity.id, lodash.omitBy(newEntity.tags, omitTag))
50689             );
50690
50691             // Exclude child nodes from newIDs if their parent way was also copied.
50692             var parents = context.graph().parentWays(newEntity),
50693                 parentCopied = false;
50694             for (var i = 0; i < parents.length; i++) {
50695                 if (originals[parents[i].id]) {
50696                     parentCopied = true;
50697                     break;
50698                 }
50699             }
50700
50701             if (!parentCopied) {
50702                 newIDs.push(newEntity.id);
50703             }
50704         }
50705
50706         // Put pasted objects where mouse pointer is..
50707         var center = projection(extent$$1.center()),
50708             delta = [ mouse$$1[0] - center[0], mouse$$1[1] - center[1] ];
50709
50710         context.perform(actionMove(newIDs, delta, projection));
50711         context.enter(modeMove$$1(context, newIDs, baseGraph));
50712     }
50713
50714
50715     function paste() {
50716         keybinding.on(uiCmd('⌘V'), doPaste);
50717         select(document).call(keybinding);
50718         return paste;
50719     }
50720
50721
50722     paste.off = function() {
50723         select(document).call(keybinding.off);
50724     };
50725
50726
50727     return paste;
50728 }
50729
50730 function behaviorSelect(context) {
50731     var lastMouse = null,
50732         suppressMenu = true,
50733         tolerance = 4,
50734         p1 = null;
50735
50736
50737     function point() {
50738         return mouse(context.container().node());
50739     }
50740
50741
50742     function keydown() {
50743         var e = event;
50744         if (e && e.shiftKey) {
50745             context.surface()
50746                 .classed('behavior-multiselect', true);
50747         }
50748
50749         if (e && e.keyCode === 93) {  // context menu
50750             e.preventDefault();
50751             e.stopPropagation();
50752         }
50753     }
50754
50755
50756     function keyup() {
50757         var e = event;
50758         if (!e || !e.shiftKey) {
50759             context.surface()
50760                 .classed('behavior-multiselect', false);
50761         }
50762
50763
50764         if (e && e.keyCode === 93) {  // context menu
50765             e.preventDefault();
50766             e.stopPropagation();
50767             contextmenu();
50768         }
50769     }
50770
50771
50772     function mousedown() {
50773         if (!p1) p1 = point();
50774         select(window)
50775             .on('mouseup.select', mouseup, true);
50776
50777         var isShowAlways = +context.storage('edit-menu-show-always') === 1;
50778         suppressMenu = !isShowAlways;
50779     }
50780
50781
50782     function mousemove() {
50783         if (event) lastMouse = event;
50784     }
50785
50786
50787     function mouseup() {
50788         click();
50789     }
50790
50791
50792     function contextmenu() {
50793         var e = event;
50794         e.preventDefault();
50795         e.stopPropagation();
50796
50797         if (!+e.clientX && !+e.clientY) {
50798             if (lastMouse) {
50799                 e.sourceEvent = lastMouse;
50800             } else {
50801                 return;
50802             }
50803         }
50804
50805         if (!p1) p1 = point();
50806         suppressMenu = false;
50807         click();
50808     }
50809
50810
50811     function click() {
50812         select(window)
50813             .on('mouseup.select', null, true);
50814
50815         if (!p1) return;
50816         var p2 = point(),
50817             dist = geoEuclideanDistance(p1, p2);
50818
50819         p1 = null;
50820         if (dist > tolerance) {
50821             return;
50822         }
50823
50824         var isMultiselect = event.shiftKey || select('#surface .lasso').node(),
50825             isShowAlways = +context.storage('edit-menu-show-always') === 1,
50826             datum = event.target.__data__ || (lastMouse && lastMouse.target.__data__),
50827             mode = context.mode();
50828
50829
50830         if (datum && datum.type === 'midpoint') {
50831             datum = datum.parents[0];
50832         }
50833
50834         if (!(datum instanceof osmEntity$$1)) {
50835             // clicked nothing..
50836             if (!isMultiselect && mode.id !== 'browse') {
50837                 context.enter(modeBrowse(context));
50838             }
50839
50840         } else {
50841             // clicked an entity..
50842             var selectedIDs = context.selectedIDs();
50843
50844             if (!isMultiselect) {
50845                 if (selectedIDs.length > 1 && (!suppressMenu && !isShowAlways)) {
50846                     // multiple things already selected, just show the menu...
50847                     mode.suppressMenu(false).reselect();
50848                 } else {
50849                     // select a single thing..
50850                     context.enter(modeSelect(context, [datum.id]).suppressMenu(suppressMenu));
50851                 }
50852
50853             } else {
50854                 if (selectedIDs.indexOf(datum.id) !== -1) {
50855                     // clicked entity is already in the selectedIDs list..
50856                     if (!suppressMenu && !isShowAlways) {
50857                         // don't deselect clicked entity, just show the menu.
50858                         mode.suppressMenu(false).reselect();
50859                     } else {
50860                         // deselect clicked entity, then reenter select mode or return to browse mode..
50861                         selectedIDs = lodash.without(selectedIDs, datum.id);
50862                         context.enter(selectedIDs.length ? modeSelect(context, selectedIDs) : modeBrowse(context));
50863                     }
50864                 } else {
50865                     // clicked entity is not in the selected list, add it..
50866                     selectedIDs = selectedIDs.concat([datum.id]);
50867                     context.enter(modeSelect(context, selectedIDs).suppressMenu(suppressMenu));
50868                 }
50869             }
50870         }
50871
50872         // reset for next time..
50873         suppressMenu = true;
50874     }
50875
50876
50877     var behavior = function(selection$$1) {
50878         lastMouse = null;
50879         suppressMenu = true;
50880         p1 = null;
50881
50882         select(window)
50883             .on('keydown.select', keydown)
50884             .on('keyup.select', keyup)
50885             .on('contextmenu.select-window', function() {
50886                 // Edge and IE really like to show the contextmenu on the
50887                 // menubar when user presses a keyboard menu button
50888                 // even after we've already preventdefaulted the key event.
50889                 event.preventDefault();
50890                 event.stopPropagation();
50891             });
50892
50893         selection$$1
50894             .on('mousedown.select', mousedown)
50895             .on('mousemove.select', mousemove)
50896             .on('contextmenu.select', contextmenu);
50897
50898         if (event && event.shiftKey) {
50899             context.surface()
50900                 .classed('behavior-multiselect', true);
50901         }
50902     };
50903
50904
50905     behavior.off = function(selection$$1) {
50906         select(window)
50907             .on('keydown.select', null)
50908             .on('keyup.select', null)
50909             .on('contextmenu.select-window', null)
50910             .on('mouseup.select', null, true);
50911
50912         selection$$1
50913             .on('mousedown.select', null)
50914             .on('mousemove.select', null)
50915             .on('contextmenu.select', null);
50916
50917         context.surface()
50918             .classed('behavior-multiselect', false);
50919     };
50920
50921
50922     return behavior;
50923 }
50924
50925 function modeAddArea$$1(context) {
50926     var mode = {
50927         id: 'add-area',
50928         button: 'area',
50929         title: t('modes.add_area.title'),
50930         description: t('modes.add_area.description'),
50931         key: '3'
50932     };
50933
50934     var behavior = behaviorAddWay(context)
50935             .tail(t('modes.add_area.tail'))
50936             .on('start', start)
50937             .on('startFromWay', startFromWay)
50938             .on('startFromNode', startFromNode),
50939         defaultTags = { area: 'yes' };
50940
50941
50942     function actionClose(wayId) {
50943         return function (graph) {
50944             return graph.replace(graph.entity(wayId).close());
50945         };
50946     }
50947
50948
50949     function start(loc) {
50950         var startGraph = context.graph(),
50951             node = osmNode({ loc: loc }),
50952             way = osmWay({ tags: defaultTags });
50953
50954         context.perform(
50955             actionAddEntity(node),
50956             actionAddEntity(way),
50957             actionAddVertex(way.id, node.id),
50958             actionClose(way.id)
50959         );
50960
50961         context.enter(modeDrawArea(context, way.id, startGraph));
50962     }
50963
50964
50965     function startFromWay(loc, edge) {
50966         var startGraph = context.graph(),
50967             node = osmNode({ loc: loc }),
50968             way = osmWay({ tags: defaultTags });
50969
50970         context.perform(
50971             actionAddEntity(node),
50972             actionAddEntity(way),
50973             actionAddVertex(way.id, node.id),
50974             actionClose(way.id),
50975             actionAddMidpoint({ loc: loc, edge: edge }, node)
50976         );
50977
50978         context.enter(modeDrawArea(context, way.id, startGraph));
50979     }
50980
50981
50982     function startFromNode(node) {
50983         var startGraph = context.graph(),
50984             way = osmWay({ tags: defaultTags });
50985
50986         context.perform(
50987             actionAddEntity(way),
50988             actionAddVertex(way.id, node.id),
50989             actionClose(way.id)
50990         );
50991
50992         context.enter(modeDrawArea(context, way.id, startGraph));
50993     }
50994
50995
50996     mode.enter = function() {
50997         context.install(behavior);
50998     };
50999
51000
51001     mode.exit = function() {
51002         context.uninstall(behavior);
51003     };
51004
51005
51006     return mode;
51007 }
51008
51009 function modeAddLine$$1(context) {
51010     var mode = {
51011         id: 'add-line',
51012         button: 'line',
51013         title: t('modes.add_line.title'),
51014         description: t('modes.add_line.description'),
51015         key: '2'
51016     };
51017
51018     var behavior = behaviorAddWay(context)
51019         .tail(t('modes.add_line.tail'))
51020         .on('start', start)
51021         .on('startFromWay', startFromWay)
51022         .on('startFromNode', startFromNode);
51023
51024
51025     function start(loc) {
51026         var startGraph = context.graph(),
51027             node = osmNode({ loc: loc }),
51028             way = osmWay();
51029
51030         context.perform(
51031             actionAddEntity(node),
51032             actionAddEntity(way),
51033             actionAddVertex(way.id, node.id)
51034         );
51035
51036         context.enter(modeDrawLine(context, way.id, startGraph));
51037     }
51038
51039
51040     function startFromWay(loc, edge) {
51041         var startGraph = context.graph(),
51042             node = osmNode({ loc: loc }),
51043             way = osmWay();
51044
51045         context.perform(
51046             actionAddEntity(node),
51047             actionAddEntity(way),
51048             actionAddVertex(way.id, node.id),
51049             actionAddMidpoint({ loc: loc, edge: edge }, node)
51050         );
51051
51052         context.enter(modeDrawLine(context, way.id, startGraph));
51053     }
51054
51055
51056     function startFromNode(node) {
51057         var startGraph = context.graph(),
51058             way = osmWay();
51059
51060         context.perform(
51061             actionAddEntity(way),
51062             actionAddVertex(way.id, node.id)
51063         );
51064
51065         context.enter(modeDrawLine(context, way.id, startGraph));
51066     }
51067
51068
51069     mode.enter = function() {
51070         context.install(behavior);
51071     };
51072
51073
51074     mode.exit = function() {
51075         context.uninstall(behavior);
51076     };
51077
51078     return mode;
51079 }
51080
51081 function modeAddPoint$$1(context) {
51082     var mode = {
51083         id: 'add-point',
51084         button: 'point',
51085         title: t('modes.add_point.title'),
51086         description: t('modes.add_point.description'),
51087         key: '1'
51088     };
51089
51090     var behavior = behaviorDraw(context)
51091         .tail(t('modes.add_point.tail'))
51092         .on('click', add)
51093         .on('clickWay', addWay)
51094         .on('clickNode', addNode)
51095         .on('cancel', cancel)
51096         .on('finish', cancel);
51097
51098
51099     function add(loc) {
51100         var node = osmNode({ loc: loc });
51101
51102         context.perform(
51103             actionAddEntity(node),
51104             t('operations.add.annotation.point')
51105         );
51106
51107         context.enter(
51108             modeSelect(context, [node.id]).newFeature(true)
51109         );
51110     }
51111
51112
51113     function addWay(loc) {
51114         add(loc);
51115     }
51116
51117
51118     function addNode(node) {
51119         add(node.loc);
51120     }
51121
51122
51123     function cancel() {
51124         context.enter(modeBrowse(context));
51125     }
51126
51127
51128     mode.enter = function() {
51129         context.install(behavior);
51130     };
51131
51132
51133     mode.exit = function() {
51134         context.uninstall(behavior);
51135     };
51136
51137
51138     return mode;
51139 }
51140
51141 function modeDragNode$$1(context) {
51142     var mode = {
51143         id: 'drag-node',
51144         button: 'browse'
51145     };
51146
51147     var nudgeInterval,
51148         activeIDs,
51149         wasMidpoint,
51150         isCancelled,
51151         lastLoc,
51152         selectedIDs = [],
51153         hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover),
51154         edit = behaviorEdit(context);
51155
51156
51157     function vecSub(a, b) {
51158         return [a[0] - b[0], a[1] - b[1]];
51159     }
51160
51161     function edge(point, size) {
51162         var pad = [80, 20, 50, 20],   // top, right, bottom, left
51163             x = 0,
51164             y = 0;
51165
51166         if (point[0] > size[0] - pad[1])
51167             x = -10;
51168         if (point[0] < pad[3])
51169             x = 10;
51170         if (point[1] > size[1] - pad[2])
51171             y = -10;
51172         if (point[1] < pad[0])
51173             y = 10;
51174
51175         if (x || y) {
51176             return [x, y];
51177         } else {
51178             return null;
51179         }
51180     }
51181
51182
51183     function startNudge(entity, nudge) {
51184         if (nudgeInterval) window.clearInterval(nudgeInterval);
51185         nudgeInterval = window.setInterval(function() {
51186             context.pan(nudge);
51187             doMove(entity, nudge);
51188         }, 50);
51189     }
51190
51191
51192     function stopNudge() {
51193         if (nudgeInterval) {
51194             window.clearInterval(nudgeInterval);
51195             nudgeInterval = null;
51196         }
51197     }
51198
51199
51200     function moveAnnotation(entity) {
51201         return t('operations.move.annotation.' + entity.geometry(context.graph()));
51202     }
51203
51204
51205     function connectAnnotation(entity) {
51206         return t('operations.connect.annotation.' + entity.geometry(context.graph()));
51207     }
51208
51209
51210     function origin(entity) {
51211         return context.projection(entity.loc);
51212     }
51213
51214
51215     function start(entity) {
51216         wasMidpoint = entity.type === 'midpoint';
51217
51218         isCancelled = event.sourceEvent.shiftKey ||
51219             context.features().hasHiddenConnections(entity, context.graph());
51220
51221         if (isCancelled) {
51222             return behavior.cancel();
51223         }
51224
51225         if (wasMidpoint) {
51226             var midpoint = entity;
51227             entity = osmNode();
51228             context.perform(actionAddMidpoint(midpoint, entity));
51229
51230             var vertex = context.surface().selectAll('.' + entity.id);
51231             behavior.target(vertex.node(), entity);
51232
51233         } else {
51234             context.perform(actionNoop());
51235         }
51236
51237         // activeIDs generate no pointer events.  This prevents the node or vertex
51238         // being dragged from trying to connect to itself or its parent element.
51239         activeIDs = lodash.map(context.graph().parentWays(entity), 'id');
51240         activeIDs.push(entity.id);
51241         setActiveElements();
51242
51243         context.enter(mode);
51244     }
51245
51246
51247     function datum() {
51248         var event$$1 = event && event.sourceEvent;
51249         if (!event$$1 || event$$1.altKey) {
51250             return {};
51251         } else {
51252             return event$$1.target.__data__ || {};
51253         }
51254     }
51255
51256
51257     function doMove(entity, nudge) {
51258         nudge = nudge || [0, 0];
51259
51260         var currPoint = (event && event.point) || context.projection(lastLoc),
51261             currMouse = vecSub(currPoint, nudge),
51262             loc = context.projection.invert(currMouse),
51263             d = datum();
51264
51265         if (!nudgeInterval) {
51266             if (d.type === 'node' && d.id !== entity.id) {
51267                 loc = d.loc;
51268             } else if (d.type === 'way' && !select(event.sourceEvent.target).classed('fill')) {
51269                 loc = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
51270             }
51271         }
51272
51273         context.replace(
51274             actionMoveNode(entity.id, loc),
51275             moveAnnotation(entity)
51276         );
51277
51278         lastLoc = loc;
51279     }
51280
51281
51282     function move(entity) {
51283         if (isCancelled) return;
51284         event.sourceEvent.stopPropagation();
51285         lastLoc = context.projection.invert(event.point);
51286
51287         doMove(entity);
51288         var nudge = edge(event.point, context.map().dimensions());
51289         if (nudge) {
51290             startNudge(entity, nudge);
51291         } else {
51292             stopNudge();
51293         }
51294     }
51295
51296
51297     function end(entity) {
51298         if (isCancelled) return;
51299
51300         var d = datum();
51301
51302         if (d.type === 'way') {
51303             var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection);
51304             context.replace(
51305                 actionAddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
51306                 connectAnnotation(d)
51307             );
51308
51309         } else if (d.type === 'node' && d.id !== entity.id) {
51310             context.replace(
51311                 actionConnect([d.id, entity.id]),
51312                 connectAnnotation(d)
51313             );
51314
51315         } else if (wasMidpoint) {
51316             context.replace(
51317                 actionNoop(),
51318                 t('operations.add.annotation.vertex')
51319             );
51320
51321         } else {
51322             context.replace(
51323                 actionNoop(),
51324                 moveAnnotation(entity)
51325             );
51326         }
51327
51328         var reselection = selectedIDs.filter(function(id) {
51329             return context.graph().hasEntity(id);
51330         });
51331
51332         if (reselection.length) {
51333             context.enter(modeSelect(context, reselection));
51334         } else {
51335             context.enter(modeBrowse(context));
51336         }
51337     }
51338
51339
51340     function cancel() {
51341         behavior.cancel();
51342         context.enter(modeBrowse(context));
51343     }
51344
51345
51346     function setActiveElements() {
51347         context.surface().selectAll(utilEntitySelector(activeIDs))
51348             .classed('active', true);
51349     }
51350
51351
51352     var behavior = behaviorDrag()
51353         .selector('g.node, g.point, g.midpoint')
51354         .surface(select('#map').node())
51355         .origin(origin)
51356         .on('start', start)
51357         .on('move', move)
51358         .on('end', end);
51359
51360
51361     mode.enter = function() {
51362         context.install(hover);
51363         context.install(edit);
51364
51365         context.history()
51366             .on('undone.drag-node', cancel);
51367
51368         context.map()
51369             .on('drawn.drag-node', setActiveElements);
51370
51371         setActiveElements();
51372     };
51373
51374
51375     mode.exit = function() {
51376         context.ui().sidebar.hover.cancel();
51377         context.uninstall(hover);
51378         context.uninstall(edit);
51379
51380         context.history()
51381             .on('undone.drag-node', null);
51382
51383         context.map()
51384             .on('drawn.drag-node', null);
51385
51386         context.surface()
51387             .selectAll('.active')
51388             .classed('active', false);
51389
51390         stopNudge();
51391     };
51392
51393
51394     mode.selectedIDs = function(_) {
51395         if (!arguments.length) return selectedIDs;
51396         selectedIDs = _;
51397         return mode;
51398     };
51399
51400
51401     mode.behavior = behavior;
51402
51403
51404     return mode;
51405 }
51406
51407 function modeBrowse(context) {
51408     var mode = {
51409         button: 'browse',
51410         id: 'browse',
51411         title: t('modes.browse.title'),
51412         description: t('modes.browse.description')
51413     }, sidebar;
51414
51415     var behaviors = [
51416         behaviorPaste(context),
51417         behaviorHover(context).on('hover', context.ui().sidebar.hover),
51418         behaviorSelect(context),
51419         behaviorLasso(context),
51420         modeDragNode$$1(context).behavior
51421     ];
51422
51423
51424     mode.enter = function() {
51425         behaviors.forEach(function(behavior) {
51426             context.install(behavior);
51427         });
51428
51429         // Get focus on the body.
51430         if (document.activeElement && document.activeElement.blur) {
51431             document.activeElement.blur();
51432         }
51433
51434         if (sidebar) {
51435             context.ui().sidebar.show(sidebar);
51436         } else {
51437             context.ui().sidebar.select(null);
51438         }
51439     };
51440
51441
51442     mode.exit = function() {
51443         context.ui().sidebar.hover.cancel();
51444         behaviors.forEach(function(behavior) {
51445             context.uninstall(behavior);
51446         });
51447
51448         if (sidebar) {
51449             context.ui().sidebar.hide();
51450         }
51451     };
51452
51453
51454     mode.sidebar = function(_) {
51455         if (!arguments.length) return sidebar;
51456         sidebar = _;
51457         return mode;
51458     };
51459
51460
51461     return mode;
51462 }
51463
51464 function modeDrawArea(context, wayId, startGraph) {
51465     var mode = {
51466         button: 'area',
51467         id: 'draw-area'
51468     };
51469
51470     var behavior;
51471
51472
51473     mode.enter = function() {
51474         var way = context.entity(wayId);
51475
51476         behavior = behaviorDrawWay(context, wayId, undefined, mode, startGraph)
51477             .tail(t('modes.draw_area.tail'));
51478
51479         var addNode = behavior.addNode;
51480
51481         behavior.addNode = function(node) {
51482             var length = way.nodes.length,
51483                 penultimate = length > 2 ? way.nodes[length - 2] : null;
51484
51485             if (node.id === way.first() || node.id === penultimate) {
51486                 behavior.finish();
51487             } else {
51488                 addNode(node);
51489             }
51490         };
51491
51492         context.install(behavior);
51493     };
51494
51495
51496     mode.exit = function() {
51497         context.uninstall(behavior);
51498     };
51499
51500
51501     mode.selectedIDs = function() {
51502         return [wayId];
51503     };
51504
51505
51506     return mode;
51507 }
51508
51509 function modeDrawLine(context, wayId, startGraph, affix) {
51510     var mode = {
51511         button: 'line',
51512         id: 'draw-line'
51513     };
51514
51515     var behavior;
51516
51517
51518     mode.enter = function() {
51519         var way = context.entity(wayId),
51520             index = (affix === 'prefix') ? 0 : undefined,
51521             headId = (affix === 'prefix') ? way.first() : way.last();
51522
51523         behavior = behaviorDrawWay(context, wayId, index, mode, startGraph)
51524             .tail(t('modes.draw_line.tail'));
51525
51526         var addNode = behavior.addNode;
51527
51528         behavior.addNode = function(node) {
51529             if (node.id === headId) {
51530                 behavior.finish();
51531             } else {
51532                 addNode(node);
51533             }
51534         };
51535
51536         context.install(behavior);
51537     };
51538
51539
51540     mode.exit = function() {
51541         context.uninstall(behavior);
51542     };
51543
51544
51545     mode.selectedIDs = function() {
51546         return [wayId];
51547     };
51548
51549
51550     return mode;
51551 }
51552
51553 function operationCircularize(selectedIDs, context) {
51554     var entityId = selectedIDs[0],
51555         entity = context.entity(entityId),
51556         extent = entity.extent(context.graph()),
51557         geometry = context.geometry(entityId),
51558         action = actionCircularize(entityId, context.projection);
51559
51560
51561     var operation = function() {
51562         context.perform(action, operation.annotation());
51563     };
51564
51565
51566     operation.available = function() {
51567         return selectedIDs.length === 1 &&
51568             entity.type === 'way' &&
51569             lodash.uniq(entity.nodes).length > 1;
51570     };
51571
51572
51573     operation.disabled = function() {
51574         var reason;
51575         if (extent.percentContainedIn(context.extent()) < 0.8) {
51576             reason = 'too_large';
51577         } else if (context.hasHiddenConnections(entityId)) {
51578             reason = 'connected_to_hidden';
51579         }
51580         return action.disabled(context.graph()) || reason;
51581     };
51582
51583
51584     operation.tooltip = function() {
51585         var disable = operation.disabled();
51586         return disable ?
51587             t('operations.circularize.' + disable) :
51588             t('operations.circularize.description.' + geometry);
51589     };
51590
51591
51592     operation.annotation = function() {
51593         return t('operations.circularize.annotation.' + geometry);
51594     };
51595
51596
51597     operation.id = 'circularize';
51598     operation.keys = [t('operations.circularize.key')];
51599     operation.title = t('operations.circularize.title');
51600     operation.behavior = behaviorOperation(context).which(operation);
51601
51602     return operation;
51603 }
51604
51605 function operationContinue(selectedIDs, context) {
51606     var graph = context.graph(),
51607         entities = selectedIDs.map(function(id) { return graph.entity(id); }),
51608         geometries = lodash.extend({ line: [], vertex: [] },
51609             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); })),
51610         vertex = geometries.vertex[0];
51611
51612
51613     function candidateWays() {
51614         return graph.parentWays(vertex).filter(function(parent) {
51615             return parent.geometry(graph) === 'line' &&
51616                 !parent.isClosed() &&
51617                 parent.affix(vertex.id) &&
51618                 (geometries.line.length === 0 || geometries.line[0] === parent);
51619         });
51620     }
51621
51622
51623     var operation = function() {
51624         var candidate = candidateWays()[0];
51625         context.enter(
51626             modeDrawLine(context, candidate.id, context.graph(), candidate.affix(vertex.id))
51627         );
51628     };
51629
51630
51631     operation.available = function() {
51632         return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
51633             !context.features().hasHiddenConnections(vertex, context.graph());
51634     };
51635
51636
51637     operation.disabled = function() {
51638         var candidates = candidateWays();
51639         if (candidates.length === 0)
51640             return 'not_eligible';
51641         if (candidates.length > 1)
51642             return 'multiple';
51643     };
51644
51645
51646     operation.tooltip = function() {
51647         var disable = operation.disabled();
51648         return disable ?
51649             t('operations.continue.' + disable) :
51650             t('operations.continue.description');
51651     };
51652
51653
51654     operation.annotation = function() {
51655         return t('operations.continue.annotation.line');
51656     };
51657
51658
51659     operation.id = 'continue';
51660     operation.keys = [t('operations.continue.key')];
51661     operation.title = t('operations.continue.title');
51662     operation.behavior = behaviorOperation(context).which(operation);
51663
51664     return operation;
51665 }
51666
51667 function operationDelete(selectedIDs, context) {
51668     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
51669         action = actionDeleteMultiple(selectedIDs),
51670         extent = selectedIDs.reduce(function(extent, id) {
51671                 return extent.extend(context.entity(id).extent(context.graph()));
51672             }, geoExtent$$1());
51673
51674
51675     var operation = function() {
51676         var nextSelectedID;
51677
51678         if (selectedIDs.length === 1) {
51679             var id = selectedIDs[0],
51680                 entity = context.entity(id),
51681                 geometry = context.geometry(id),
51682                 parents = context.graph().parentWays(entity),
51683                 parent = parents[0];
51684
51685             // Select the next closest node in the way.
51686             if (geometry === 'vertex' && parent.nodes.length > 2) {
51687                 var nodes = parent.nodes,
51688                     i = nodes.indexOf(id);
51689
51690                 if (i === 0) {
51691                     i++;
51692                 } else if (i === nodes.length - 1) {
51693                     i--;
51694                 } else {
51695                     var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
51696                         b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
51697                     i = a < b ? i - 1 : i + 1;
51698                 }
51699
51700                 nextSelectedID = nodes[i];
51701             }
51702         }
51703
51704         context.perform(action, operation.annotation());
51705
51706         if (nextSelectedID && context.hasEntity(nextSelectedID)) {
51707             context.enter(modeSelect(context, [nextSelectedID]).follow(true));
51708         } else {
51709             context.enter(modeBrowse(context));
51710         }
51711
51712     };
51713
51714
51715     operation.available = function() {
51716         return true;
51717     };
51718
51719
51720     operation.disabled = function() {
51721         var reason;
51722         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
51723             reason = 'too_large';
51724         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
51725             reason = 'connected_to_hidden';
51726         } else if (lodash.some(selectedIDs, protectedMember)) {
51727             reason = 'part_of_relation';
51728         } else if (lodash.some(selectedIDs, incompleteRelation)) {
51729             reason = 'incomplete_relation';
51730         }
51731         return reason;
51732
51733         function incompleteRelation(id) {
51734             var entity = context.entity(id);
51735             return entity.type === 'relation' && !entity.isComplete(context.graph());
51736         }
51737
51738         function protectedMember(id) {
51739             var entity = context.entity(id);
51740             if (entity.type !== 'way') return false;
51741
51742             var parents = context.graph().parentRelations(entity);
51743             for (var i = 0; i < parents.length; i++) {
51744                 var parent = parents[i],
51745                     type = parent.tags.type,
51746                     role = parent.memberById(id).role || 'outer';
51747                 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
51748                     return true;
51749                 }
51750             }
51751             return false;
51752         }
51753
51754     };
51755
51756
51757     operation.tooltip = function() {
51758         var disable = operation.disabled();
51759         return disable ?
51760             t('operations.delete.' + disable + '.' + multi) :
51761             t('operations.delete.description' + '.' + multi);
51762     };
51763
51764
51765     operation.annotation = function() {
51766         return selectedIDs.length === 1 ?
51767             t('operations.delete.annotation.' + context.geometry(selectedIDs[0])) :
51768             t('operations.delete.annotation.multiple', { n: selectedIDs.length });
51769     };
51770
51771
51772     operation.id = 'delete';
51773     operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
51774     operation.title = t('operations.delete.title');
51775     operation.behavior = behaviorOperation(context).which(operation);
51776
51777     return operation;
51778 }
51779
51780 function operationDisconnect(selectedIDs, context) {
51781     var vertices = lodash.filter(selectedIDs, function(entityId) {
51782         return context.geometry(entityId) === 'vertex';
51783     });
51784
51785     var entityId = vertices[0],
51786         action = actionDisconnect(entityId);
51787
51788     if (selectedIDs.length > 1) {
51789         action.limitWays(lodash.without(selectedIDs, entityId));
51790     }
51791
51792
51793     var operation = function() {
51794         context.perform(action, operation.annotation());
51795     };
51796
51797
51798     operation.available = function() {
51799         return vertices.length === 1;
51800     };
51801
51802
51803     operation.disabled = function() {
51804         var reason;
51805         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
51806             reason = 'connected_to_hidden';
51807         }
51808         return action.disabled(context.graph()) || reason;
51809     };
51810
51811
51812     operation.tooltip = function() {
51813         var disable = operation.disabled();
51814         return disable ?
51815             t('operations.disconnect.' + disable) :
51816             t('operations.disconnect.description');
51817     };
51818
51819
51820     operation.annotation = function() {
51821         return t('operations.disconnect.annotation');
51822     };
51823
51824
51825     operation.id = 'disconnect';
51826     operation.keys = [t('operations.disconnect.key')];
51827     operation.title = t('operations.disconnect.title');
51828     operation.behavior = behaviorOperation(context).which(operation);
51829
51830     return operation;
51831 }
51832
51833 function operationMerge(selectedIDs, context) {
51834
51835     function updatePresetTags(oldGraph, newGraph, ids) {
51836         var id = ids[0],
51837             oldEntity = oldGraph.hasEntity(id),
51838             newEntity = newGraph.hasEntity(id);
51839
51840         if (!oldEntity || !newEntity) return;
51841
51842         var oldPreset = context.presets().match(oldEntity, oldGraph),
51843             newPreset = context.presets().match(newEntity, newGraph);
51844
51845         context.replace(actionChangePreset(id, oldPreset, newPreset));
51846     }
51847
51848
51849     var join = actionJoin(selectedIDs),
51850         merge = actionMerge(selectedIDs),
51851         mergePolygon = actionMergePolygon(selectedIDs);
51852
51853
51854     var operation = function() {
51855         var origGraph = context.graph(),
51856             action;
51857
51858         if (!join.disabled(origGraph)) {
51859             action = join;
51860         } else if (!merge.disabled(origGraph)) {
51861             action = merge;
51862         } else {
51863             action = mergePolygon;
51864         }
51865
51866         context.perform(action, operation.annotation());
51867
51868         var ids = selectedIDs.filter(function(id) {
51869             var entity = context.hasEntity(id);
51870             return entity && entity.type !== 'node';
51871         });
51872
51873         // if we merged tags, rematch preset and update tags if necessary (#3851)
51874         if (action === merge) {
51875             updatePresetTags(origGraph, context.graph(), ids);
51876         }
51877
51878         context.enter(modeSelect(context, ids));
51879     };
51880
51881
51882     operation.available = function() {
51883         return selectedIDs.length >= 2;
51884     };
51885
51886
51887     operation.disabled = function() {
51888         return join.disabled(context.graph()) &&
51889             merge.disabled(context.graph()) &&
51890             mergePolygon.disabled(context.graph());
51891     };
51892
51893
51894     operation.tooltip = function() {
51895         var j = join.disabled(context.graph()),
51896             m = merge.disabled(context.graph()),
51897             p = mergePolygon.disabled(context.graph());
51898
51899         if (j === 'restriction' && m && p) {
51900             return t('operations.merge.restriction',
51901                 { relation: context.presets().item('type/restriction').name() });
51902         }
51903
51904         if (p === 'incomplete_relation' && j && m) {
51905             return t('operations.merge.incomplete_relation');
51906         }
51907
51908         if (j && m && p) {
51909             return t('operations.merge.' + j);
51910         }
51911
51912         return t('operations.merge.description');
51913     };
51914
51915
51916     operation.annotation = function() {
51917         return t('operations.merge.annotation', { n: selectedIDs.length });
51918     };
51919
51920
51921     operation.id = 'merge';
51922     operation.keys = [t('operations.merge.key')];
51923     operation.title = t('operations.merge.title');
51924     operation.behavior = behaviorOperation(context).which(operation);
51925
51926     return operation;
51927 }
51928
51929 function operationMove(selectedIDs, context) {
51930     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
51931         extent = selectedIDs.reduce(function(extent, id) {
51932             return extent.extend(context.entity(id).extent(context.graph()));
51933         }, geoExtent$$1());
51934
51935
51936     var operation = function() {
51937         context.enter(modeMove$$1(context, selectedIDs));
51938     };
51939
51940
51941     operation.available = function() {
51942         return selectedIDs.length > 1 ||
51943             context.entity(selectedIDs[0]).type !== 'node';
51944     };
51945
51946
51947     operation.disabled = function() {
51948         var reason;
51949         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
51950             reason = 'too_large';
51951         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
51952             reason = 'connected_to_hidden';
51953         } else if (lodash.some(selectedIDs, incompleteRelation)) {
51954             reason = 'incomplete_relation';
51955         }
51956         return reason;
51957
51958         function incompleteRelation(id) {
51959             var entity = context.entity(id);
51960             return entity.type === 'relation' && !entity.isComplete(context.graph());
51961         }
51962     };
51963
51964
51965     operation.tooltip = function() {
51966         var disable = operation.disabled();
51967         return disable ?
51968             t('operations.move.' + disable + '.' + multi) :
51969             t('operations.move.description.' + multi);
51970     };
51971
51972
51973     operation.annotation = function() {
51974         return selectedIDs.length === 1 ?
51975             t('operations.move.annotation.' + context.geometry(selectedIDs[0])) :
51976             t('operations.move.annotation.multiple');
51977     };
51978
51979
51980     operation.id = 'move';
51981     operation.keys = [t('operations.move.key')];
51982     operation.title = t('operations.move.title');
51983     operation.behavior = behaviorOperation(context).which(operation);
51984
51985     return operation;
51986 }
51987
51988 function operationOrthogonalize(selectedIDs, context) {
51989     var entityId = selectedIDs[0],
51990         entity = context.entity(entityId),
51991         extent = entity.extent(context.graph()),
51992         geometry = context.geometry(entityId),
51993         action = actionOrthogonalize(entityId, context.projection);
51994
51995
51996     var operation = function() {
51997         context.perform(action, operation.annotation());
51998     };
51999
52000
52001     operation.available = function() {
52002         return selectedIDs.length === 1 &&
52003             entity.type === 'way' &&
52004             entity.isClosed() &&
52005             lodash.uniq(entity.nodes).length > 2;
52006     };
52007
52008
52009     operation.disabled = function() {
52010         var reason;
52011         if (extent.percentContainedIn(context.extent()) < 0.8) {
52012             reason = 'too_large';
52013         } else if (context.hasHiddenConnections(entityId)) {
52014             reason = 'connected_to_hidden';
52015         }
52016         return action.disabled(context.graph()) || reason;
52017     };
52018
52019
52020     operation.tooltip = function() {
52021         var disable = operation.disabled();
52022         return disable ?
52023             t('operations.orthogonalize.' + disable) :
52024             t('operations.orthogonalize.description.' + geometry);
52025     };
52026
52027
52028     operation.annotation = function() {
52029         return t('operations.orthogonalize.annotation.' + geometry);
52030     };
52031
52032
52033     operation.id = 'orthogonalize';
52034     operation.keys = [t('operations.orthogonalize.key')];
52035     operation.title = t('operations.orthogonalize.title');
52036     operation.behavior = behaviorOperation(context).which(operation);
52037
52038     return operation;
52039 }
52040
52041 function operationReflectShort(selectedIDs, context) {
52042     return operationReflect(selectedIDs, context, 'short');
52043 }
52044
52045
52046 function operationReflectLong(selectedIDs, context) {
52047     return operationReflect(selectedIDs, context, 'long');
52048 }
52049
52050
52051 function operationReflect(selectedIDs, context, axis) {
52052     axis = axis || 'long';
52053     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
52054         extent = selectedIDs.reduce(function(extent, id) {
52055             return extent.extend(context.entity(id).extent(context.graph()));
52056         }, geoExtent$$1());
52057
52058
52059     var operation = function() {
52060         var action = actionReflect(selectedIDs, context.projection)
52061             .useLongAxis(Boolean(axis === 'long'));
52062         context.perform(action, operation.annotation());
52063     };
52064
52065
52066     operation.available = function() {
52067         return lodash.some(selectedIDs, hasArea);
52068
52069         function hasArea(id) {
52070             var entity = context.entity(id);
52071             return (entity.type === 'way' && entity.isClosed()) ||
52072                 (entity.type ==='relation' && entity.isMultipolygon());
52073         }
52074     };
52075
52076
52077     operation.disabled = function() {
52078         var reason;
52079         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
52080             reason = 'too_large';
52081         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52082             reason = 'connected_to_hidden';
52083         } else if (lodash.some(selectedIDs, incompleteRelation)) {
52084             reason = 'incomplete_relation';
52085         }
52086         return reason;
52087
52088         function incompleteRelation(id) {
52089             var entity = context.entity(id);
52090             return entity.type === 'relation' && !entity.isComplete(context.graph());
52091         }
52092     };
52093
52094
52095     operation.tooltip = function() {
52096         var disable = operation.disabled();
52097         return disable ?
52098             t('operations.reflect.' + disable + '.' + multi) :
52099             t('operations.reflect.description.' + axis + '.' + multi);
52100     };
52101
52102
52103     operation.annotation = function() {
52104         return t('operations.reflect.annotation.' + axis + '.' + multi);
52105     };
52106
52107
52108     operation.id = 'reflect-' + axis;
52109     operation.keys = [t('operations.reflect.key.' + axis)];
52110     operation.title = t('operations.reflect.title.' + axis);
52111     operation.behavior = behaviorOperation(context).which(operation);
52112
52113     return operation;
52114 }
52115
52116 function operationReverse(selectedIDs, context) {
52117     var entityId = selectedIDs[0];
52118
52119     var operation = function() {
52120         context.perform(actionReverse(entityId), operation.annotation());
52121     };
52122
52123
52124     operation.available = function() {
52125         return selectedIDs.length === 1 && context.geometry(entityId) === 'line';
52126     };
52127
52128
52129     operation.disabled = function() {
52130         return false;
52131     };
52132
52133
52134     operation.tooltip = function() {
52135         return t('operations.reverse.description');
52136     };
52137
52138
52139     operation.annotation = function() {
52140         return t('operations.reverse.annotation');
52141     };
52142
52143
52144     operation.id = 'reverse';
52145     operation.keys = [t('operations.reverse.key')];
52146     operation.title = t('operations.reverse.title');
52147     operation.behavior = behaviorOperation(context).which(operation);
52148
52149     return operation;
52150 }
52151
52152 function operationRotate(selectedIDs, context) {
52153     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
52154         extent = selectedIDs.reduce(function(extent, id) {
52155             return extent.extend(context.entity(id).extent(context.graph()));
52156         }, geoExtent$$1());
52157
52158
52159     var operation = function() {
52160         context.enter(modeRotate$$1(context, selectedIDs));
52161     };
52162
52163
52164     operation.available = function() {
52165         return lodash.some(selectedIDs, hasArea);
52166
52167         function hasArea(id) {
52168             var entity = context.entity(id);
52169             return (entity.type === 'way' && entity.isClosed()) ||
52170                 (entity.type ==='relation' && entity.isMultipolygon());
52171         }
52172     };
52173
52174
52175     operation.disabled = function() {
52176         var reason;
52177         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
52178             reason = 'too_large';
52179         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52180             reason = 'connected_to_hidden';
52181         } else if (lodash.some(selectedIDs, incompleteRelation)) {
52182             reason = 'incomplete_relation';
52183         }
52184         return reason;
52185
52186         function incompleteRelation(id) {
52187             var entity = context.entity(id);
52188             return entity.type === 'relation' && !entity.isComplete(context.graph());
52189         }
52190     };
52191
52192
52193     operation.tooltip = function() {
52194         var disable = operation.disabled();
52195         return disable ?
52196             t('operations.rotate.' + disable + '.' + multi) :
52197             t('operations.rotate.description.' + multi);
52198     };
52199
52200
52201     operation.annotation = function() {
52202         return selectedIDs.length === 1 ?
52203             t('operations.rotate.annotation.' + context.geometry(selectedIDs[0])) :
52204             t('operations.rotate.annotation.multiple');
52205     };
52206
52207
52208     operation.id = 'rotate';
52209     operation.keys = [t('operations.rotate.key')];
52210     operation.title = t('operations.rotate.title');
52211     operation.behavior = behaviorOperation(context).which(operation);
52212
52213     return operation;
52214 }
52215
52216 function operationSplit(selectedIDs, context) {
52217     var vertices = lodash.filter(selectedIDs, function(entityId) {
52218         return context.geometry(entityId) === 'vertex';
52219     });
52220
52221     var entityId = vertices[0],
52222         action = actionSplit(entityId),
52223         ways = [];
52224
52225     if (vertices.length === 1) {
52226         if (selectedIDs.length > 1) {
52227             action.limitWays(lodash.without(selectedIDs, entityId));
52228         }
52229         ways = action.ways(context.graph());
52230     }
52231
52232
52233     var operation = function() {
52234         var difference = context.perform(action, operation.annotation());
52235         context.enter(modeSelect(context, difference.extantIDs()));
52236     };
52237
52238
52239     operation.available = function() {
52240         return vertices.length === 1;
52241     };
52242
52243
52244     operation.disabled = function() {
52245         var reason;
52246         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52247             reason = 'connected_to_hidden';
52248         }
52249         return action.disabled(context.graph()) || reason;
52250     };
52251
52252
52253     operation.tooltip = function() {
52254         var disable = operation.disabled();
52255         if (disable) {
52256             return t('operations.split.' + disable);
52257         }
52258         if (ways.length === 1) {
52259             return t('operations.split.description.' + context.geometry(ways[0].id));
52260         } else {
52261             return t('operations.split.description.multiple');
52262         }
52263     };
52264
52265
52266     operation.annotation = function() {
52267         return ways.length === 1 ?
52268             t('operations.split.annotation.' + context.geometry(ways[0].id)) :
52269             t('operations.split.annotation.multiple', { n: ways.length });
52270     };
52271
52272
52273     operation.id = 'split';
52274     operation.keys = [t('operations.split.key')];
52275     operation.title = t('operations.split.title');
52276     operation.behavior = behaviorOperation(context).which(operation);
52277
52278     return operation;
52279 }
52280
52281 function operationStraighten(selectedIDs, context) {
52282     var entityId = selectedIDs[0],
52283         action = actionStraighten(entityId, context.projection);
52284
52285
52286     function operation() {
52287         context.perform(action, operation.annotation());
52288     }
52289
52290
52291     operation.available = function() {
52292         var entity = context.entity(entityId);
52293         return selectedIDs.length === 1 &&
52294             entity.type === 'way' &&
52295             !entity.isClosed() &&
52296             lodash.uniq(entity.nodes).length > 2;
52297     };
52298
52299
52300     operation.disabled = function() {
52301         var reason;
52302         if (context.hasHiddenConnections(entityId)) {
52303             reason = 'connected_to_hidden';
52304         }
52305         return action.disabled(context.graph()) || reason;
52306     };
52307
52308
52309     operation.tooltip = function() {
52310         var disable = operation.disabled();
52311         return disable ?
52312             t('operations.straighten.' + disable) :
52313             t('operations.straighten.description');
52314     };
52315
52316
52317     operation.annotation = function() {
52318         return t('operations.straighten.annotation');
52319     };
52320
52321
52322     operation.id = 'straighten';
52323     operation.keys = [t('operations.straighten.key')];
52324     operation.title = t('operations.straighten.title');
52325     operation.behavior = behaviorOperation(context).which(operation);
52326
52327     return operation;
52328 }
52329
52330
52331
52332 var Operations = Object.freeze({
52333         operationCircularize: operationCircularize,
52334         operationContinue: operationContinue,
52335         operationDelete: operationDelete,
52336         operationDisconnect: operationDisconnect,
52337         operationMerge: operationMerge,
52338         operationMove: operationMove,
52339         operationOrthogonalize: operationOrthogonalize,
52340         operationReflectShort: operationReflectShort,
52341         operationReflectLong: operationReflectLong,
52342         operationReverse: operationReverse,
52343         operationRotate: operationRotate,
52344         operationSplit: operationSplit,
52345         operationStraighten: operationStraighten
52346 });
52347
52348 function modeMove$$1(context, entityIDs, baseGraph) {
52349     var mode = {
52350         id: 'move',
52351         button: 'browse'
52352     };
52353
52354     var keybinding = d3keybinding('move'),
52355         behaviors = [
52356             behaviorEdit(context),
52357             operationCircularize(entityIDs, context).behavior,
52358             operationDelete(entityIDs, context).behavior,
52359             operationOrthogonalize(entityIDs, context).behavior,
52360             operationReflectLong(entityIDs, context).behavior,
52361             operationReflectShort(entityIDs, context).behavior,
52362             operationRotate(entityIDs, context).behavior
52363         ],
52364         annotation = entityIDs.length === 1 ?
52365             t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
52366             t('operations.move.annotation.multiple'),
52367         prevGraph,
52368         cache,
52369         origin,
52370         nudgeInterval;
52371
52372
52373     function vecSub(a, b) {
52374         return [a[0] - b[0], a[1] - b[1]];
52375     }
52376
52377
52378     function edge(point, size) {
52379         var pad = [80, 20, 50, 20],   // top, right, bottom, left
52380             x = 0,
52381             y = 0;
52382
52383         if (point[0] > size[0] - pad[1])
52384             x = -10;
52385         if (point[0] < pad[3])
52386             x = 10;
52387         if (point[1] > size[1] - pad[2])
52388             y = -10;
52389         if (point[1] < pad[0])
52390             y = 10;
52391
52392         if (x || y) {
52393             return [x, y];
52394         } else {
52395             return null;
52396         }
52397     }
52398
52399
52400     function doMove(nudge) {
52401         nudge = nudge || [0, 0];
52402
52403         var fn;
52404         if (prevGraph !== context.graph()) {
52405             cache = {};
52406             origin = context.map().mouseCoordinates();
52407             fn = context.perform;
52408         } else {
52409             fn = context.overwrite;
52410         }
52411
52412         var currMouse = context.mouse(),
52413             origMouse = context.projection(origin),
52414             delta = vecSub(vecSub(currMouse, origMouse), nudge);
52415
52416         fn(actionMove(entityIDs, delta, context.projection, cache), annotation);
52417         prevGraph = context.graph();
52418     }
52419
52420
52421     function startNudge(nudge) {
52422         if (nudgeInterval) window.clearInterval(nudgeInterval);
52423         nudgeInterval = window.setInterval(function() {
52424             context.pan(nudge);
52425             doMove(nudge);
52426         }, 50);
52427     }
52428
52429
52430     function stopNudge() {
52431         if (nudgeInterval) {
52432             window.clearInterval(nudgeInterval);
52433             nudgeInterval = null;
52434         }
52435     }
52436
52437
52438     function move() {
52439         doMove();
52440         var nudge = edge(context.mouse(), context.map().dimensions());
52441         if (nudge) {
52442             startNudge(nudge);
52443         } else {
52444             stopNudge();
52445         }
52446     }
52447
52448
52449     function finish() {
52450         event.stopPropagation();
52451         context.enter(modeSelect(context, entityIDs));
52452         stopNudge();
52453     }
52454
52455
52456     function cancel() {
52457         if (baseGraph) {
52458             while (context.graph() !== baseGraph) context.pop();
52459             context.enter(modeBrowse(context));
52460         } else {
52461             context.pop();
52462             context.enter(modeSelect(context, entityIDs));
52463         }
52464         stopNudge();
52465     }
52466
52467
52468     function undone() {
52469         context.enter(modeBrowse(context));
52470     }
52471
52472
52473     mode.enter = function() {
52474         origin = context.map().mouseCoordinates();
52475         prevGraph = null;
52476         cache = {};
52477
52478         behaviors.forEach(function(behavior) {
52479             context.install(behavior);
52480         });
52481
52482         context.surface()
52483             .on('mousemove.move', move)
52484             .on('click.move', finish);
52485
52486         context.history()
52487             .on('undone.move', undone);
52488
52489         keybinding
52490             .on('⎋', cancel)
52491             .on('↩', finish);
52492
52493         select(document)
52494             .call(keybinding);
52495     };
52496
52497
52498     mode.exit = function() {
52499         stopNudge();
52500
52501         behaviors.forEach(function(behavior) {
52502             context.uninstall(behavior);
52503         });
52504
52505         context.surface()
52506             .on('mousemove.move', null)
52507             .on('click.move', null);
52508
52509         context.history()
52510             .on('undone.move', null);
52511
52512         keybinding.off();
52513     };
52514
52515
52516     return mode;
52517 }
52518
52519 function modeRotate$$1(context, entityIDs) {
52520     var mode = {
52521         id: 'rotate',
52522         button: 'browse'
52523     };
52524
52525     var keybinding = d3keybinding('rotate'),
52526         behaviors = [
52527             behaviorEdit(context),
52528             operationCircularize(entityIDs, context).behavior,
52529             operationDelete(entityIDs, context).behavior,
52530             operationMove(entityIDs, context).behavior,
52531             operationOrthogonalize(entityIDs, context).behavior,
52532             operationReflectLong(entityIDs, context).behavior,
52533             operationReflectShort(entityIDs, context).behavior
52534         ],
52535         annotation = entityIDs.length === 1 ?
52536             t('operations.rotate.annotation.' + context.geometry(entityIDs[0])) :
52537             t('operations.rotate.annotation.multiple'),
52538         prevGraph,
52539         prevAngle,
52540         prevTransform,
52541         pivot;
52542
52543
52544     function doRotate() {
52545         var fn;
52546         if (context.graph() !== prevGraph) {
52547             fn = context.perform;
52548         } else {
52549             fn = context.replace;
52550         }
52551
52552         // projection changed, recalculate pivot
52553         var projection = context.projection;
52554         var currTransform = projection.transform();
52555         if (!prevTransform ||
52556             currTransform.k !== prevTransform.k ||
52557             currTransform.x !== prevTransform.x ||
52558             currTransform.y !== prevTransform.y) {
52559
52560             var nodes = utilGetAllNodes(entityIDs, context.graph()),
52561                 points = nodes.map(function(n) { return projection(n.loc); });
52562
52563             pivot = d3polygonCentroid(d3polygonHull(points));
52564             prevAngle = undefined;
52565         }
52566
52567
52568         var currMouse = context.mouse(),
52569             currAngle = Math.atan2(currMouse[1] - pivot[1], currMouse[0] - pivot[0]);
52570
52571         if (typeof prevAngle === 'undefined') prevAngle = currAngle;
52572         var delta = currAngle - prevAngle;
52573
52574         fn(actionRotate(entityIDs, pivot, delta, projection), annotation);
52575
52576         prevTransform = currTransform;
52577         prevAngle = currAngle;
52578         prevGraph = context.graph();
52579     }
52580
52581
52582     function finish() {
52583         event.stopPropagation();
52584         context.enter(modeSelect(context, entityIDs));
52585     }
52586
52587
52588     function cancel() {
52589         context.pop();
52590         context.enter(modeSelect(context, entityIDs));
52591     }
52592
52593
52594     function undone() {
52595         context.enter(modeBrowse(context));
52596     }
52597
52598
52599     mode.enter = function() {
52600         behaviors.forEach(function(behavior) {
52601             context.install(behavior);
52602         });
52603
52604         context.surface()
52605             .on('mousemove.rotate', doRotate)
52606             .on('click.rotate', finish);
52607
52608         context.history()
52609             .on('undone.rotate', undone);
52610
52611         keybinding
52612             .on('⎋', cancel)
52613             .on('↩', finish);
52614
52615         select(document)
52616             .call(keybinding);
52617     };
52618
52619
52620     mode.exit = function() {
52621         behaviors.forEach(function(behavior) {
52622             context.uninstall(behavior);
52623         });
52624
52625         context.surface()
52626             .on('mousemove.rotate', null)
52627             .on('click.rotate', null);
52628
52629         context.history()
52630             .on('undone.rotate', null);
52631
52632         keybinding.off();
52633     };
52634
52635
52636     return mode;
52637 }
52638
52639 function modeSave$$1(context) {
52640     var mode = {
52641         id: 'save'
52642     };
52643
52644     var commit = uiCommit(context)
52645             .on('cancel', cancel)
52646             .on('save', save);
52647
52648
52649     function cancel() {
52650         context.enter(modeBrowse(context));
52651     }
52652
52653
52654     function save(changeset, tryAgain) {
52655
52656         var loading = uiLoading(context).message(t('save.uploading')).blocking(true),
52657             history = context.history(),
52658             origChanges = history.changes(actionDiscardTags(history.difference())),
52659             localGraph = context.graph(),
52660             remoteGraph = coreGraph$$1(history.base(), true),
52661             modified = lodash.filter(history.difference().summary(), {changeType: 'modified'}),
52662             toCheck = lodash.map(lodash.map(modified, 'entity'), 'id'),
52663             toLoad = withChildNodes(toCheck, localGraph),
52664             conflicts = [],
52665             errors = [];
52666
52667         if (!tryAgain) {
52668             history.perform(actionNoop());  // checkpoint
52669         }
52670
52671         context.container().call(loading);
52672
52673         if (toCheck.length) {
52674             context.connection().loadMultiple(toLoad, loaded);
52675         } else {
52676             upload();
52677         }
52678
52679
52680         function withChildNodes(ids, graph) {
52681             return lodash.uniq(lodash.reduce(ids, function(result, id) {
52682                 var entity = graph.entity(id);
52683                 if (entity.type === 'way') {
52684                     try {
52685                         var cn = graph.childNodes(entity);
52686                         result.push.apply(result, lodash.map(lodash.filter(cn, 'version'), 'id'));
52687                     } catch (err) {
52688                         /* eslint-disable no-console */
52689                         if (typeof console !== 'undefined') console.error(err);
52690                         /* eslint-enable no-console */
52691                     }
52692                 }
52693                 return result;
52694             }, lodash.clone(ids)));
52695         }
52696
52697
52698         // Reload modified entities into an alternate graph and check for conflicts..
52699         function loaded(err, result) {
52700             if (errors.length) return;
52701
52702             if (err) {
52703                 errors.push({
52704                     msg: err.responseText,
52705                     details: [ t('save.status_code', { code: err.status }) ]
52706                 });
52707                 showErrors();
52708
52709             } else {
52710                 var loadMore = [];
52711                 lodash.each(result.data, function(entity) {
52712                     remoteGraph.replace(entity);
52713                     toLoad = lodash.without(toLoad, entity.id);
52714
52715                     // Because loadMultiple doesn't download /full like loadEntity,
52716                     // need to also load children that aren't already being checked..
52717                     if (!entity.visible) return;
52718                     if (entity.type === 'way') {
52719                         loadMore.push.apply(loadMore,
52720                             lodash.difference(entity.nodes, toCheck, toLoad, loadMore));
52721                     } else if (entity.type === 'relation' && entity.isMultipolygon()) {
52722                         loadMore.push.apply(loadMore,
52723                             lodash.difference(lodash.map(entity.members, 'id'), toCheck, toLoad, loadMore));
52724                     }
52725                 });
52726
52727                 if (loadMore.length) {
52728                     toLoad.push.apply(toLoad, loadMore);
52729                     context.connection().loadMultiple(loadMore, loaded);
52730                 }
52731
52732                 if (!toLoad.length) {
52733                     checkConflicts();
52734                 }
52735             }
52736         }
52737
52738
52739         function checkConflicts() {
52740             function choice(id, text$$1, action) {
52741                 return { id: id, text: text$$1, action: function() { history.replace(action); } };
52742             }
52743             function formatUser(d) {
52744                 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
52745             }
52746             function entityName(entity) {
52747                 return utilDisplayName(entity) || (utilDisplayType(entity.id) + ' ' + entity.id);
52748             }
52749
52750             function compareVersions(local$$1, remote) {
52751                 if (local$$1.version !== remote.version) return false;
52752
52753                 if (local$$1.type === 'way') {
52754                     var children = lodash.union(local$$1.nodes, remote.nodes);
52755
52756                     for (var i = 0; i < children.length; i++) {
52757                         var a = localGraph.hasEntity(children[i]),
52758                             b = remoteGraph.hasEntity(children[i]);
52759
52760                         if (a && b && a.version !== b.version) return false;
52761                     }
52762                 }
52763
52764                 return true;
52765             }
52766
52767             lodash.each(toCheck, function(id) {
52768                 var local$$1 = localGraph.entity(id),
52769                     remote = remoteGraph.entity(id);
52770
52771                 if (compareVersions(local$$1, remote)) return;
52772
52773                 var action = actionMergeRemoteChanges,
52774                     merge$$1 = action(id, localGraph, remoteGraph, formatUser);
52775
52776                 history.replace(merge$$1);
52777
52778                 var mergeConflicts = merge$$1.conflicts();
52779                 if (!mergeConflicts.length) return;  // merged safely
52780
52781                 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
52782                     forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
52783                     keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
52784                     keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
52785
52786                 conflicts.push({
52787                     id: id,
52788                     name: entityName(local$$1),
52789                     details: mergeConflicts,
52790                     chosen: 1,
52791                     choices: [
52792                         choice(id, keepMine, forceLocal),
52793                         choice(id, keepTheirs, forceRemote)
52794                     ]
52795                 });
52796             });
52797
52798             upload();
52799         }
52800
52801
52802         function upload() {
52803             if (conflicts.length) {
52804                 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
52805                 showConflicts();
52806             } else if (errors.length) {
52807                 showErrors();
52808             } else {
52809                 var changes = history.changes(actionDiscardTags(history.difference()));
52810                 if (changes.modified.length || changes.created.length || changes.deleted.length) {
52811                     context.connection().putChangeset(changeset, changes, uploadCallback);
52812                 } else {        // changes were insignificant or reverted by user
52813                     select('.inspector-wrap *').remove();
52814                     loading.close();
52815                     context.flush();
52816                     cancel();
52817                 }
52818             }
52819         }
52820
52821
52822         function uploadCallback(err, changeset) {
52823             if (err) {
52824                 errors.push({
52825                     msg: err.responseText,
52826                     details: [ t('save.status_code', { code: err.status }) ]
52827                 });
52828                 showErrors();
52829             } else {
52830                 history.clearSaved();
52831                 success(changeset);
52832                 // Add delay to allow for postgres replication #1646 #2678
52833                 window.setTimeout(function() {
52834                     select('.inspector-wrap *').remove();
52835                     loading.close();
52836                     context.flush();
52837                 }, 2500);
52838             }
52839         }
52840
52841
52842         function showConflicts() {
52843             var selection$$1 = context.container()
52844                 .select('#sidebar')
52845                 .append('div')
52846                 .attr('class','sidebar-component');
52847
52848             loading.close();
52849
52850             selection$$1.call(uiConflicts(context)
52851                 .list(conflicts)
52852                 .on('download', function() {
52853                     var data = JXON.stringify(changeset.update({ id: 'CHANGEME' }).osmChangeJXON(origChanges)),
52854                         win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
52855                     win.focus();
52856                 })
52857                 .on('cancel', function() {
52858                     history.pop();
52859                     selection$$1.remove();
52860                 })
52861                 .on('save', function() {
52862                     for (var i = 0; i < conflicts.length; i++) {
52863                         if (conflicts[i].chosen === 1) {  // user chose "keep theirs"
52864                             var entity = context.hasEntity(conflicts[i].id);
52865                             if (entity && entity.type === 'way') {
52866                                 var children = lodash.uniq(entity.nodes);
52867                                 for (var j = 0; j < children.length; j++) {
52868                                     history.replace(actionRevert(children[j]));
52869                                 }
52870                             }
52871                             history.replace(actionRevert(conflicts[i].id));
52872                         }
52873                     }
52874
52875                     selection$$1.remove();
52876                     save(changeset, true);
52877                 })
52878             );
52879         }
52880
52881
52882         function showErrors() {
52883             var selection$$1 = uiConfirm(context.container());
52884
52885             history.pop();
52886             loading.close();
52887
52888             selection$$1
52889                 .select('.modal-section.header')
52890                 .append('h3')
52891                 .text(t('save.error'));
52892
52893             addErrors(selection$$1, errors);
52894             selection$$1.okButton();
52895         }
52896
52897
52898         function addErrors(selection$$1, data) {
52899             var message = selection$$1
52900                 .select('.modal-section.message-text');
52901
52902             var items = message
52903                 .selectAll('.error-container')
52904                 .data(data);
52905
52906             var enter = items.enter()
52907                 .append('div')
52908                 .attr('class', 'error-container');
52909
52910             enter
52911                 .append('a')
52912                 .attr('class', 'error-description')
52913                 .attr('href', '#')
52914                 .classed('hide-toggle', true)
52915                 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
52916                 .on('click', function() {
52917                     var error = select(this),
52918                         detail = select(this.nextElementSibling),
52919                         exp = error.classed('expanded');
52920
52921                     detail.style('display', exp ? 'none' : 'block');
52922                     error.classed('expanded', !exp);
52923
52924                     event.preventDefault();
52925                 });
52926
52927             var details = enter
52928                 .append('div')
52929                 .attr('class', 'error-detail-container')
52930                 .style('display', 'none');
52931
52932             details
52933                 .append('ul')
52934                 .attr('class', 'error-detail-list')
52935                 .selectAll('li')
52936                 .data(function(d) { return d.details || []; })
52937                 .enter()
52938                 .append('li')
52939                 .attr('class', 'error-detail-item')
52940                 .text(function(d) { return d; });
52941
52942             items.exit()
52943                 .remove();
52944         }
52945
52946     }
52947
52948
52949     function success(changeset) {
52950         commit.reset();
52951         context.enter(modeBrowse(context)
52952             .sidebar(uiSuccess(context)
52953                 .changeset(changeset)
52954                 .on('cancel', function() {
52955                     context.ui().sidebar.hide();
52956                 })
52957             )
52958         );
52959     }
52960
52961
52962     mode.enter = function() {
52963         function done() {
52964             context.ui().sidebar.show(commit);
52965         }
52966
52967         context.container().selectAll('#content')
52968             .attr('class', 'inactive');
52969
52970         if (context.connection().authenticated()) {
52971             done();
52972         } else {
52973             context.connection().authenticate(function(err) {
52974                 if (err) {
52975                     cancel();
52976                 } else {
52977                     done();
52978                 }
52979             });
52980         }
52981     };
52982
52983
52984     mode.exit = function() {
52985         context.container().selectAll('#content')
52986             .attr('class', 'active');
52987
52988         context.ui().sidebar.hide();
52989     };
52990
52991     return mode;
52992 }
52993
52994 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
52995 // For example, ⌘Z -> Ctrl+Z
52996 function uiCmd(code) {
52997     var detected = utilDetect();
52998
52999     if (detected.os === 'mac') {
53000         return code;
53001     }
53002
53003     if (detected.os === 'win') {
53004         if (code === '⌘⇧Z') return 'Ctrl+Y';
53005     }
53006
53007     var result = '',
53008         replacements = {
53009             '⌘': 'Ctrl',
53010             '⇧': 'Shift',
53011             '⌥': 'Alt',
53012             '⌫': 'Backspace',
53013             '⌦': 'Delete'
53014         };
53015
53016     for (var i = 0; i < code.length; i++) {
53017         if (code[i] in replacements) {
53018             result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
53019         } else {
53020             result += code[i];
53021         }
53022     }
53023
53024     return result;
53025 }
53026
53027 // deprecation warning - Radial Menu to be removed in iD v3
53028 var relatedParent;
53029
53030
53031 function modeSelect(context, selectedIDs) {
53032     var mode = {
53033         id: 'select',
53034         button: 'browse'
53035     };
53036
53037     var keybinding = d3keybinding('select'),
53038         timeout$$1 = null,
53039         behaviors = [
53040             behaviorCopy(context),
53041             behaviorPaste(context),
53042             behaviorBreathe(context),
53043             behaviorHover(context),
53044             behaviorSelect(context),
53045             behaviorLasso(context),
53046             modeDragNode$$1(context).selectedIDs(selectedIDs).behavior
53047         ],
53048         inspector,
53049         editMenu,
53050         newFeature = false,
53051         suppressMenu = true,
53052         follow = false;
53053
53054
53055     var wrap = context.container()
53056         .select('.inspector-wrap');
53057
53058
53059     function singular() {
53060         if (selectedIDs.length === 1) {
53061             return context.hasEntity(selectedIDs[0]);
53062         }
53063     }
53064
53065
53066     function checkSelectedIDs() {
53067         var ids = [];
53068         if (Array.isArray(selectedIDs)) {
53069             ids = selectedIDs.filter(function(id) {
53070                 return context.hasEntity(id);
53071             });
53072         }
53073
53074         if (ids.length) {
53075             selectedIDs = ids;
53076         } else {
53077             context.enter(modeBrowse(context));
53078         }
53079         return !!ids.length;
53080     }
53081
53082
53083     // find the common parent ways for nextVertex, previousVertex
53084     function commonParents() {
53085         var graph = context.graph(),
53086             commonParents = [];
53087
53088         for (var i = 0; i < selectedIDs.length; i++) {
53089             var entity = context.hasEntity(selectedIDs[i]);
53090             if (!entity || entity.geometry(graph) !== 'vertex') {
53091                 return [];  // selection includes some not vertexes
53092             }
53093
53094             var currParents = lodash.map(graph.parentWays(entity), 'id');
53095             if (!commonParents.length) {
53096                 commonParents = currParents;
53097                 continue;
53098             }
53099
53100             commonParents = lodash.intersection(commonParents, currParents);
53101             if (!commonParents.length) {
53102                 return [];
53103             }
53104         }
53105
53106         return commonParents;
53107     }
53108
53109
53110     function singularParent() {
53111         var parents = commonParents();
53112         if (!parents || parents.length === 0) {
53113             relatedParent = null;
53114             return null;
53115         }
53116
53117         // relatedParent is used when we visit a vertex with multiple
53118         // parents, and we want to remember which parent line we started on.
53119
53120         if (parents.length === 1) {
53121             relatedParent = parents[0];  // remember this parent for later
53122             return relatedParent;
53123         }
53124
53125         if (parents.indexOf(relatedParent) !== -1) {
53126             return relatedParent;   // prefer the previously seen parent
53127         }
53128
53129         return parents[0];
53130     }
53131
53132
53133     function closeMenu() {
53134         if (editMenu) {
53135             context.surface().call(editMenu.close);
53136         }
53137     }
53138
53139
53140     function positionMenu() {
53141         if (!editMenu) { return; }
53142
53143         var entity = singular();
53144         if (entity && context.geometry(entity.id) === 'relation') {
53145             suppressMenu = true;
53146         } else {
53147             var point = context.mouse(),
53148                 viewport = geoExtent$$1(context.projection.clipExtent()).polygon();
53149
53150             if (point && geoPointInPolygon(point, viewport)) {
53151                 editMenu.center(point);
53152             } else {
53153                 suppressMenu = true;
53154             }
53155         }
53156     }
53157
53158
53159     function showMenu() {
53160         closeMenu();
53161         if (editMenu) {
53162             context.surface().call(editMenu);
53163         }
53164     }
53165
53166
53167     function toggleMenu() {
53168         // deprecation warning - Radial Menu to be removed in iD v3
53169         if (select('.edit-menu, .radial-menu').empty()) {
53170             positionMenu();
53171             showMenu();
53172         } else {
53173             closeMenu();
53174         }
53175     }
53176
53177
53178     mode.selectedIDs = function() {
53179         return selectedIDs;
53180     };
53181
53182
53183     mode.reselect = function() {
53184         if (!checkSelectedIDs()) return;
53185
53186         var surfaceNode = context.surface().node();
53187         if (surfaceNode.focus) {   // FF doesn't support it
53188             surfaceNode.focus();
53189         }
53190
53191         positionMenu();
53192         if (!suppressMenu) {
53193             showMenu();
53194         }
53195     };
53196
53197
53198     mode.newFeature = function(_) {
53199         if (!arguments.length) return newFeature;
53200         newFeature = _;
53201         return mode;
53202     };
53203
53204
53205     mode.suppressMenu = function(_) {
53206         if (!arguments.length) return suppressMenu;
53207         suppressMenu = _;
53208         return mode;
53209     };
53210
53211
53212     mode.follow = function(_) {
53213         if (!arguments.length) return follow;
53214         follow = _;
53215         return mode;
53216     };
53217
53218
53219     mode.enter = function() {
53220
53221         function update() {
53222             closeMenu();
53223             checkSelectedIDs();
53224         }
53225
53226
53227         function dblclick() {
53228             var target = select(event.target),
53229                 datum = target.datum();
53230
53231             if (datum instanceof osmWay && !target.classed('fill')) {
53232                 var choice = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection),
53233                     prev = datum.nodes[choice.index - 1],
53234                     next = datum.nodes[choice.index];
53235
53236                 context.perform(
53237                     actionAddMidpoint({loc: choice.loc, edge: [prev, next]}, osmNode()),
53238                     t('operations.add.annotation.vertex')
53239                 );
53240
53241                 event.preventDefault();
53242                 event.stopPropagation();
53243
53244             } else if (datum.type === 'midpoint') {
53245                 context.perform(
53246                     actionAddMidpoint({loc: datum.loc, edge: datum.edge}, osmNode()),
53247                     t('operations.add.annotation.vertex'));
53248
53249                 event.preventDefault();
53250                 event.stopPropagation();
53251             }
53252         }
53253
53254
53255         function selectElements(drawn) {
53256             if (!checkSelectedIDs()) return;
53257
53258             var surface = context.surface(),
53259                 entity = singular();
53260
53261             if (entity && context.geometry(entity.id) === 'relation') {
53262                 suppressMenu = true;
53263                 return;
53264             }
53265
53266             surface.selectAll('.related')
53267                 .classed('related', false);
53268
53269             singularParent();
53270             if (relatedParent) {
53271                 surface.selectAll(utilEntitySelector([relatedParent]))
53272                     .classed('related', true);
53273             }
53274
53275             var selection$$1 = context.surface()
53276                 .selectAll(utilEntityOrMemberSelector(selectedIDs, context.graph()));
53277
53278             if (selection$$1.empty()) {
53279                 // Return to browse mode if selected DOM elements have
53280                 // disappeared because the user moved them out of view..
53281                 var source = event && event.type === 'zoom' && event.sourceEvent;
53282                 if (drawn && source && (source.type === 'mousemove' || source.type === 'touchmove')) {
53283                     context.enter(modeBrowse(context));
53284                 }
53285             } else {
53286                 selection$$1
53287                     .classed('selected', true);
53288             }
53289         }
53290
53291
53292         function esc() {
53293             context.enter(modeBrowse(context));
53294         }
53295
53296
53297         function firstVertex() {
53298             event.preventDefault();
53299             var parent = singularParent();
53300             if (parent) {
53301                 var way = context.entity(parent);
53302                 context.enter(
53303                     modeSelect(context, [way.first()]).follow(true)
53304                 );
53305             }
53306         }
53307
53308
53309         function lastVertex() {
53310             event.preventDefault();
53311             var parent = singularParent();
53312             if (parent) {
53313                 var way = context.entity(parent);
53314                 context.enter(
53315                     modeSelect(context, [way.last()]).follow(true)
53316                 );
53317             }
53318         }
53319
53320
53321         function previousVertex() {
53322             event.preventDefault();
53323             var parent = singularParent();
53324             if (!parent) return;
53325
53326             var way = context.entity(parent),
53327                 length = way.nodes.length,
53328                 curr = way.nodes.indexOf(selectedIDs[0]),
53329                 index = -1;
53330
53331             if (curr > 0) {
53332                 index = curr - 1;
53333             } else if (way.isClosed()) {
53334                 index = length - 2;
53335             }
53336
53337             if (index !== -1) {
53338                 context.enter(
53339                     modeSelect(context, [way.nodes[index]]).follow(true)
53340                 );
53341             }
53342         }
53343
53344
53345         function nextVertex() {
53346             event.preventDefault();
53347             var parent = singularParent();
53348             if (!parent) return;
53349
53350             var way = context.entity(parent),
53351                 length = way.nodes.length,
53352                 curr = way.nodes.indexOf(selectedIDs[0]),
53353                 index = -1;
53354
53355             if (curr < length - 1) {
53356                 index = curr + 1;
53357             } else if (way.isClosed()) {
53358                 index = 0;
53359             }
53360
53361             if (index !== -1) {
53362                 context.enter(
53363                     modeSelect(context, [way.nodes[index]]).follow(true)
53364                 );
53365             }
53366         }
53367
53368
53369         function nextParent() {
53370             event.preventDefault();
53371             var parents = lodash.uniq(commonParents());
53372             if (!parents || parents.length < 2) return;
53373
53374             var index = parents.indexOf(relatedParent);
53375             if (index < 0 || index > parents.length - 2) {
53376                 relatedParent = parents[0];
53377             } else {
53378                 relatedParent = parents[index + 1];
53379             }
53380
53381             var surface = context.surface();
53382             surface.selectAll('.related')
53383                 .classed('related', false);
53384
53385             if (relatedParent) {
53386                 surface.selectAll(utilEntitySelector([relatedParent]))
53387                     .classed('related', true);
53388             }
53389         }
53390
53391
53392         if (!checkSelectedIDs()) return;
53393
53394         var operations = lodash.without(values(Operations), operationDelete)
53395                 .map(function(o) { return o(selectedIDs, context); })
53396                 .filter(function(o) { return o.available(); });
53397
53398         // deprecation warning - Radial Menu to be removed in iD v3
53399         var isRadialMenu = context.storage('edit-menu-style') === 'radial';
53400         if (isRadialMenu) {
53401             operations = operations.slice(0,7);
53402             operations.unshift(operationDelete(selectedIDs, context));
53403         } else {
53404             operations.push(operationDelete(selectedIDs, context));
53405         }
53406
53407         operations.forEach(function(operation) {
53408             if (operation.behavior) {
53409                 behaviors.push(operation.behavior);
53410             }
53411         });
53412
53413         behaviors.forEach(function(behavior) {
53414             context.install(behavior);
53415         });
53416
53417         keybinding
53418             .on(['[','pgup'], previousVertex)
53419             .on([']', 'pgdown'], nextVertex)
53420             .on([uiCmd('⌘['), 'home'], firstVertex)
53421             .on([uiCmd('⌘]'), 'end'], lastVertex)
53422             .on(['\\', 'pause'], nextParent)
53423             .on('⎋', esc, true)
53424             .on('space', toggleMenu);
53425
53426         select(document)
53427             .call(keybinding);
53428
53429
53430         // deprecation warning - Radial Menu to be removed in iD v3
53431         editMenu = isRadialMenu
53432             ? uiRadialMenu(context, operations)
53433             : uiEditMenu(context, operations);
53434
53435         context.ui().sidebar
53436             .select(singular() ? singular().id : null, newFeature);
53437
53438         context.history()
53439             .on('undone.select', update)
53440             .on('redone.select', update);
53441
53442         context.map()
53443             .on('move.select', closeMenu)
53444             .on('drawn.select', selectElements);
53445
53446         context.surface()
53447             .on('dblclick.select', dblclick);
53448
53449
53450         selectElements();
53451
53452         if (selectedIDs.length > 1) {
53453             var entities = uiSelectionList(context, selectedIDs);
53454             context.ui().sidebar.show(entities);
53455         }
53456
53457         if (follow) {
53458             var extent$$1 = geoExtent$$1(),
53459                 graph = context.graph();
53460             selectedIDs.forEach(function(id) {
53461                 var entity = context.entity(id);
53462                 extent$$1._extend(entity.extent(graph));
53463             });
53464
53465             var loc = extent$$1.center();
53466             context.map().centerEase(loc);
53467         } else if (singular() && singular().type === 'way') {
53468             context.map().pan([0,0]);  // full redraw, to adjust z-sorting #2914
53469         }
53470
53471         timeout$$1 = window.setTimeout(function() {
53472             positionMenu();
53473             if (!suppressMenu) {
53474                 showMenu();
53475             }
53476         }, 270);  /* after any centerEase completes */
53477
53478     };
53479
53480
53481     mode.exit = function() {
53482         if (timeout$$1) window.clearTimeout(timeout$$1);
53483
53484         if (inspector) wrap.call(inspector.close);
53485
53486         behaviors.forEach(function(behavior) {
53487             context.uninstall(behavior);
53488         });
53489
53490         keybinding.off();
53491         closeMenu();
53492         editMenu = undefined;
53493
53494         context.history()
53495             .on('undone.select', null)
53496             .on('redone.select', null);
53497
53498         var surface = context.surface();
53499
53500         surface
53501             .on('dblclick.select', null);
53502
53503         surface
53504             .selectAll('.selected')
53505             .classed('selected', false);
53506
53507         surface
53508             .selectAll('.related')
53509             .classed('related', false);
53510
53511         context.map().on('drawn.select', null);
53512         context.ui().sidebar.hide();
53513     };
53514
53515
53516     return mode;
53517 }
53518
53519 function uiAccount(context) {
53520     var connection = context.connection();
53521
53522
53523     function update(selection$$1) {
53524         if (!connection.authenticated()) {
53525             selection$$1.selectAll('#userLink, #logoutLink')
53526                 .classed('hide', true);
53527             return;
53528         }
53529
53530         connection.userDetails(function(err, details) {
53531             var userLink = selection$$1.select('#userLink'),
53532                 logoutLink = selection$$1.select('#logoutLink');
53533
53534             userLink.html('');
53535             logoutLink.html('');
53536
53537             if (err) return;
53538
53539             selection$$1.selectAll('#userLink, #logoutLink')
53540                 .classed('hide', false);
53541
53542             // Link
53543             userLink.append('a')
53544                 .attr('href', connection.userURL(details.display_name))
53545                 .attr('target', '_blank');
53546
53547             // Add thumbnail or dont
53548             if (details.image_url) {
53549                 userLink.append('img')
53550                     .attr('class', 'icon pre-text user-icon')
53551                     .attr('src', details.image_url);
53552             } else {
53553                 userLink
53554                     .call(svgIcon('#icon-avatar', 'pre-text light'));
53555             }
53556
53557             // Add user name
53558             userLink.append('span')
53559                 .attr('class', 'label')
53560                 .text(details.display_name);
53561
53562             logoutLink.append('a')
53563                 .attr('class', 'logout')
53564                 .attr('href', '#')
53565                 .text(t('logout'))
53566                 .on('click.logout', function() {
53567                     event.preventDefault();
53568                     connection.logout();
53569                 });
53570         });
53571     }
53572
53573
53574     return function(selection$$1) {
53575         selection$$1.append('li')
53576             .attr('id', 'logoutLink')
53577             .classed('hide', true);
53578
53579         selection$$1.append('li')
53580             .attr('id', 'userLink')
53581             .classed('hide', true);
53582
53583         connection
53584             .on('change.account', function() { update(selection$$1); });
53585
53586         update(selection$$1);
53587     };
53588 }
53589
53590 function uiAttribution(context) {
53591     var selection$$1;
53592
53593
53594     function attribution(data, klass) {
53595         var div = selection$$1.selectAll('.' + klass)
53596             .data([0]);
53597
53598         div = div.enter()
53599             .append('div')
53600             .attr('class', klass)
53601             .merge(div);
53602
53603
53604         var background = div.selectAll('.attribution')
53605             .data(data, function(d) { return d.name(); });
53606
53607         background.exit()
53608             .remove();
53609
53610         background = background.enter()
53611             .append('span')
53612             .attr('class', 'attribution')
53613             .each(function(d) {
53614                 if (d.terms_html) {
53615                     select(this)
53616                         .html(d.terms_html);
53617                     return;
53618                 }
53619
53620                 var source = d.terms_text || d.id || d.name();
53621
53622                 if (d.logo) {
53623                     source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
53624                 }
53625
53626                 if (d.terms_url) {
53627                     select(this)
53628                         .append('a')
53629                         .attr('href', d.terms_url)
53630                         .attr('target', '_blank')
53631                         .html(source);
53632                 } else {
53633                     select(this)
53634                         .text(source);
53635                 }
53636             })
53637             .merge(background);
53638
53639
53640         var copyright = background.selectAll('.copyright-notice')
53641             .data(function(d) {
53642                 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
53643                 return notice ? [notice] : [];
53644             });
53645
53646         copyright.exit()
53647             .remove();
53648
53649         copyright = copyright.enter()
53650             .append('span')
53651             .attr('class', 'copyright-notice')
53652             .merge(copyright);
53653
53654         copyright
53655             .text(String);
53656     }
53657
53658
53659     function update() {
53660         attribution([context.background().baseLayerSource()], 'base-layer-attribution');
53661         attribution(context.background().overlayLayerSources().filter(function (s) {
53662             return s.validZoom(context.map().zoom());
53663         }), 'overlay-layer-attribution');
53664     }
53665
53666
53667     return function(select$$1) {
53668         selection$$1 = select$$1;
53669
53670         context.background()
53671             .on('change.attribution', update);
53672
53673         context.map()
53674             .on('move.attribution', lodash.throttle(update, 400, {leading: false}));
53675
53676         update();
53677     };
53678 }
53679
53680 function rendererBackgroundSource(data) {
53681     var source = lodash.clone(data),
53682         offset = [0, 0],
53683         name = source.name,
53684         best = !!source.best;
53685
53686     source.scaleExtent = data.scaleExtent || [0, 20];
53687     source.overzoom = data.overzoom !== false;
53688
53689
53690     source.offset = function(_) {
53691         if (!arguments.length) return offset;
53692         offset = _;
53693         return source;
53694     };
53695
53696
53697     source.nudge = function(_, zoomlevel) {
53698         offset[0] += _[0] / Math.pow(2, zoomlevel);
53699         offset[1] += _[1] / Math.pow(2, zoomlevel);
53700         return source;
53701     };
53702
53703
53704     source.name = function() {
53705         return name;
53706     };
53707
53708
53709     source.best = function() {
53710         return best;
53711     };
53712
53713
53714     source.area = function() {
53715         if (!data.polygon) return Number.MAX_VALUE;  // worldwide
53716         var area$$1 = area({ type: 'MultiPolygon', coordinates: [ data.polygon ] });
53717         return isNaN(area$$1) ? 0 : area$$1;
53718     };
53719
53720
53721     source.imageryUsed = function() {
53722         return name || source.id;
53723     };
53724
53725
53726     source.url = function(coord) {
53727         return data.template
53728             .replace('{x}', coord[0])
53729             .replace('{y}', coord[1])
53730             // TMS-flipped y coordinate
53731             .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
53732             .replace(/\{z(oom)?\}/, coord[2])
53733             .replace(/\{switch:([^}]+)\}/, function(s, r) {
53734                 var subdomains = r.split(',');
53735                 return subdomains[(coord[0] + coord[1]) % subdomains.length];
53736             })
53737             .replace('{u}', function() {
53738                 var u = '';
53739                 for (var zoom$$1 = coord[2]; zoom$$1 > 0; zoom$$1--) {
53740                     var b = 0;
53741                     var mask = 1 << (zoom$$1 - 1);
53742                     if ((coord[0] & mask) !== 0) b++;
53743                     if ((coord[1] & mask) !== 0) b += 2;
53744                     u += b.toString();
53745                 }
53746                 return u;
53747             });
53748     };
53749
53750
53751     source.intersects = function(extent$$1) {
53752         extent$$1 = extent$$1.polygon();
53753         return !data.polygon || data.polygon.some(function(polygon) {
53754             return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
53755         });
53756     };
53757
53758
53759     source.validZoom = function(z) {
53760         return source.scaleExtent[0] <= z &&
53761             (source.overzoom || source.scaleExtent[1] > z);
53762     };
53763
53764
53765     source.isLocatorOverlay = function() {
53766         return source.id === 'mapbox_locator_overlay';
53767     };
53768
53769
53770     source.copyrightNotices = function() {};
53771
53772
53773     return source;
53774 }
53775
53776
53777 rendererBackgroundSource.Bing = function(data, dispatch$$1) {
53778     // http://msdn.microsoft.com/en-us/library/ff701716.aspx
53779     // http://msdn.microsoft.com/en-us/library/ff701701.aspx
53780
53781     data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
53782
53783     var bing = rendererBackgroundSource(data),
53784         key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
53785         url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
53786             key + '&jsonp={callback}',
53787         providers = [];
53788
53789     jsonpRequest(url, function(json$$1) {
53790         providers = json$$1.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
53791             return {
53792                 attribution: provider.attribution,
53793                 areas: provider.coverageAreas.map(function(area$$1) {
53794                     return {
53795                         zoom: [area$$1.zoomMin, area$$1.zoomMax],
53796                         extent: geoExtent$$1([area$$1.bbox[1], area$$1.bbox[0]], [area$$1.bbox[3], area$$1.bbox[2]])
53797                     };
53798                 })
53799             };
53800         });
53801         dispatch$$1.call('change');
53802     });
53803
53804     bing.copyrightNotices = function(zoom$$1, extent$$1) {
53805         zoom$$1 = Math.min(zoom$$1, 21);
53806         return providers.filter(function(provider) {
53807             return lodash.some(provider.areas, function(area$$1) {
53808                 return extent$$1.intersects(area$$1.extent) &&
53809                     area$$1.zoom[0] <= zoom$$1 &&
53810                     area$$1.zoom[1] >= zoom$$1;
53811             });
53812         }).map(function(provider) {
53813             return provider.attribution;
53814         }).join(', ');
53815     };
53816
53817     bing.logo = 'bing_maps.png';
53818     bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
53819
53820     return bing;
53821 };
53822
53823
53824 rendererBackgroundSource.None = function() {
53825     var source = rendererBackgroundSource({ id: 'none', template: '' });
53826
53827     source.name = function() {
53828         return t('background.none');
53829     };
53830
53831     source.imageryUsed = function() {
53832         return 'None';
53833     };
53834
53835     source.area = function() {
53836         return -1;  // sources in background pane are sorted by area
53837     };
53838
53839     return source;
53840 };
53841
53842
53843 rendererBackgroundSource.Custom = function(template) {
53844     var source = rendererBackgroundSource({ id: 'custom', template: template });
53845
53846     source.name = function() {
53847         return t('background.custom');
53848     };
53849
53850     source.imageryUsed = function() {
53851         return 'Custom (' + template + ')';
53852     };
53853
53854     source.area = function() {
53855         return -2;  // sources in background pane are sorted by area
53856     };
53857
53858     return source;
53859 };
53860
53861 function rendererTileLayer(context) {
53862     var tileSize = 256,
53863         tile = d3geoTile(),
53864         projection,
53865         cache = {},
53866         tileOrigin,
53867         z,
53868         transformProp = utilPrefixCSSProperty('Transform'),
53869         source = rendererBackgroundSource.None();
53870
53871
53872     // blacklist overlay tiles around Null Island..
53873     function nearNullIsland(x, y, z) {
53874         if (z >= 7) {
53875             var center = Math.pow(2, z - 1),
53876                 width = Math.pow(2, z - 6),
53877                 min$$1 = center - (width / 2),
53878                 max$$1 = center + (width / 2) - 1;
53879             return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
53880         }
53881         return false;
53882     }
53883
53884
53885     function tileSizeAtZoom(d, z) {
53886         var epsilon = 0.002;
53887         return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
53888     }
53889
53890
53891     function atZoom(t, distance) {
53892         var power = Math.pow(2, distance);
53893         return [
53894             Math.floor(t[0] * power),
53895             Math.floor(t[1] * power),
53896             t[2] + distance];
53897     }
53898
53899
53900     function lookUp(d) {
53901         for (var up = -1; up > -d[2]; up--) {
53902             var tile = atZoom(d, up);
53903             if (cache[source.url(tile)] !== false) {
53904                 return tile;
53905             }
53906         }
53907     }
53908
53909
53910     function uniqueBy(a, n) {
53911         var o = [], seen = {};
53912         for (var i = 0; i < a.length; i++) {
53913             if (seen[a[i][n]] === undefined) {
53914                 o.push(a[i]);
53915                 seen[a[i][n]] = true;
53916             }
53917         }
53918         return o;
53919     }
53920
53921
53922     function addSource(d) {
53923         d.push(source.url(d));
53924         return d;
53925     }
53926
53927
53928     // Update tiles based on current state of `projection`.
53929     function background(selection$$1) {
53930         tile.scale(projection.scale() * 2 * Math.PI)
53931             .translate(projection.translate());
53932
53933         tileOrigin = [
53934             projection.scale() * Math.PI - projection.translate()[0],
53935             projection.scale() * Math.PI - projection.translate()[1]];
53936
53937         z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
53938
53939         render(selection$$1);
53940     }
53941
53942
53943     // Derive the tiles onscreen, remove those offscreen and position them.
53944     // Important that this part not depend on `projection` because it's
53945     // rentered when tiles load/error (see #644).
53946     function render(selection$$1) {
53947         var requests = [];
53948         var showDebug = context.getDebug('tile') && !source.overlay;
53949
53950         if (source.validZoom(z)) {
53951             tile().forEach(function(d) {
53952                 addSource(d);
53953                 if (d[3] === '') return;
53954                 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
53955                 requests.push(d);
53956                 if (cache[d[3]] === false && lookUp(d)) {
53957                     requests.push(addSource(lookUp(d)));
53958                 }
53959             });
53960
53961             requests = uniqueBy(requests, 3).filter(function(r) {
53962                 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
53963                     return false;
53964                 }
53965                 // don't re-request tiles which have failed in the past
53966                 return cache[r[3]] !== false;
53967             });
53968         }
53969
53970         var pixelOffset = [
53971             source.offset()[0] * Math.pow(2, z),
53972             source.offset()[1] * Math.pow(2, z)
53973         ];
53974
53975         function load(d) {
53976             cache[d[3]] = true;
53977             select(this)
53978                 .on('error', null)
53979                 .on('load', null)
53980                 .classed('tile-loaded', true);
53981             render(selection$$1);
53982         }
53983
53984         function error(d) {
53985             cache[d[3]] = false;
53986             select(this)
53987                 .on('error', null)
53988                 .on('load', null)
53989                 .remove();
53990             render(selection$$1);
53991         }
53992
53993         function imageTransform(d) {
53994             var _ts = tileSize * Math.pow(2, z - d[2]);
53995             var scale = tileSizeAtZoom(d, z);
53996             return 'translate(' +
53997                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
53998                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
53999                 'scale(' + scale + ',' + scale + ')';
54000         }
54001
54002         function debugTransform(d) {
54003             var _ts = tileSize * Math.pow(2, z - d[2]);
54004             var scale = tileSizeAtZoom(d, z);
54005             return 'translate(' +
54006                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + scale * (tileSize / 4)) + 'px,' +
54007                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + scale * (tileSize / 2)) + 'px)';
54008         }
54009
54010
54011         var image = selection$$1.selectAll('img')
54012             .data(requests, function(d) { return d[3]; });
54013
54014         image.exit()
54015             .style(transformProp, imageTransform)
54016             .classed('tile-removing', true)
54017             .each(function() {
54018                 var tile = select(this);
54019                 window.setTimeout(function() {
54020                     if (tile.classed('tile-removing')) {
54021                         tile.remove();
54022                     }
54023                 }, 300);
54024             });
54025
54026         image.enter()
54027           .append('img')
54028             .attr('class', 'tile')
54029             .attr('src', function(d) { return d[3]; })
54030             .on('error', error)
54031             .on('load', load)
54032           .merge(image)
54033             .style(transformProp, imageTransform)
54034             .classed('tile-debug', showDebug)
54035             .classed('tile-removing', false);
54036
54037
54038         var debug = selection$$1.selectAll('.tile-label-debug')
54039             .data(showDebug ? requests : [], function(d) { return d[3]; });
54040
54041         debug.exit()
54042             .remove();
54043
54044         debug.enter()
54045           .append('div')
54046             .attr('class', 'tile-label-debug')
54047           .merge(debug)
54048             .text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; })
54049             .style(transformProp, debugTransform);
54050     }
54051
54052
54053     background.projection = function(_) {
54054         if (!arguments.length) return projection;
54055         projection = _;
54056         return background;
54057     };
54058
54059
54060     background.dimensions = function(_) {
54061         if (!arguments.length) return tile.size();
54062         tile.size(_);
54063         return background;
54064     };
54065
54066
54067     background.source = function(_) {
54068         if (!arguments.length) return source;
54069         source = _;
54070         cache = {};
54071         tile.scaleExtent(source.scaleExtent);
54072         return background;
54073     };
54074
54075
54076     return background;
54077 }
54078
54079 function rendererBackground(context) {
54080     var dispatch$$1 = dispatch('change'),
54081         baseLayer = rendererTileLayer(context).projection(context.projection),
54082         overlayLayers = [],
54083         backgroundSources;
54084
54085
54086     function findSource(id) {
54087         return lodash.find(backgroundSources, function(d) {
54088             return d.id && d.id === id;
54089         });
54090     }
54091
54092
54093     function background(selection$$1) {
54094         var base = selection$$1.selectAll('.layer-background')
54095             .data([0]);
54096
54097         base.enter()
54098             .insert('div', '.layer-data')
54099             .attr('class', 'layer layer-background')
54100             .merge(base)
54101             .call(baseLayer);
54102
54103         var overlays = selection$$1.selectAll('.layer-overlay')
54104             .data(overlayLayers, function(d) { return d.source().name(); });
54105
54106         overlays.exit()
54107             .remove();
54108
54109         overlays.enter()
54110             .insert('div', '.layer-data')
54111             .attr('class', 'layer layer-overlay')
54112             .merge(overlays)
54113             .each(function(layer) { select(this).call(layer); });
54114     }
54115
54116
54117     background.updateImagery = function() {
54118         if (context.inIntro()) return;
54119
54120         var b = background.baseLayerSource(),
54121             o = overlayLayers
54122                 .filter(function (d) { return !d.source().isLocatorOverlay(); })
54123                 .map(function (d) { return d.source().id; })
54124                 .join(','),
54125             meters = geoOffsetToMeters(b.offset()),
54126             epsilon = 0.01,
54127             x = +meters[0].toFixed(2),
54128             y = +meters[1].toFixed(2),
54129             q = utilStringQs(window.location.hash.substring(1));
54130
54131         var id = b.id;
54132         if (id === 'custom') {
54133             id = 'custom:' + b.template;
54134         }
54135
54136         if (id) {
54137             q.background = id;
54138         } else {
54139             delete q.background;
54140         }
54141
54142         if (o) {
54143             q.overlays = o;
54144         } else {
54145             delete q.overlays;
54146         }
54147
54148         if (Math.abs(x) > epsilon || Math.abs(y) > epsilon) {
54149             q.offset = x + ',' + y;
54150         } else {
54151             delete q.offset;
54152         }
54153
54154         window.location.replace('#' + utilQsString(q, true));
54155
54156         var imageryUsed = [b.imageryUsed()];
54157
54158         overlayLayers
54159             .filter(function (d) { return !d.source().isLocatorOverlay(); })
54160             .forEach(function (d) { imageryUsed.push(d.source().imageryUsed()); });
54161
54162         var gpx = context.layers().layer('gpx');
54163         if (gpx && gpx.enabled() && gpx.hasGpx()) {
54164             imageryUsed.push('Local GPX');
54165         }
54166
54167         var mapillary_images = context.layers().layer('mapillary-images');
54168         if (mapillary_images && mapillary_images.enabled()) {
54169             imageryUsed.push('Mapillary Images');
54170         }
54171
54172         var mapillary_signs = context.layers().layer('mapillary-signs');
54173         if (mapillary_signs && mapillary_signs.enabled()) {
54174             imageryUsed.push('Mapillary Signs');
54175         }
54176
54177         context.history().imageryUsed(imageryUsed);
54178     };
54179
54180
54181     background.sources = function(extent$$1) {
54182         return backgroundSources.filter(function(source) {
54183             return source.intersects(extent$$1);
54184         });
54185     };
54186
54187
54188     background.dimensions = function(_) {
54189         if (!_) return;
54190         baseLayer.dimensions(_);
54191
54192         overlayLayers.forEach(function(layer) {
54193             layer.dimensions(_);
54194         });
54195     };
54196
54197
54198     background.baseLayerSource = function(d) {
54199         if (!arguments.length) return baseLayer.source();
54200
54201         // test source against OSM imagery blacklists..
54202         var blacklists = context.connection().imageryBlacklists();
54203
54204         var fail = false,
54205             tested = 0,
54206             regex, i;
54207
54208         for (i = 0; i < blacklists.length; i++) {
54209             try {
54210                 regex = new RegExp(blacklists[i]);
54211                 fail = regex.test(d.template);
54212                 tested++;
54213                 if (fail) break;
54214             } catch (e) {
54215                 /* noop */
54216             }
54217         }
54218
54219         // ensure at least one test was run.
54220         if (!tested) {
54221             regex = new RegExp('.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*');
54222             fail = regex.test(d.template);
54223         }
54224
54225         baseLayer.source(!fail ? d : rendererBackgroundSource.None());
54226         dispatch$$1.call('change');
54227         background.updateImagery();
54228         return background;
54229     };
54230
54231
54232     background.bing = function() {
54233         background.baseLayerSource(findSource('Bing'));
54234     };
54235
54236
54237     background.showsLayer = function(d) {
54238         return d.id === baseLayer.source().id ||
54239             overlayLayers.some(function(layer) { return d.id === layer.source().id; });
54240     };
54241
54242
54243     background.overlayLayerSources = function() {
54244         return overlayLayers.map(function (l) { return l.source(); });
54245     };
54246
54247
54248     background.toggleOverlayLayer = function(d) {
54249         var layer;
54250
54251         for (var i = 0; i < overlayLayers.length; i++) {
54252             layer = overlayLayers[i];
54253             if (layer.source() === d) {
54254                 overlayLayers.splice(i, 1);
54255                 dispatch$$1.call('change');
54256                 background.updateImagery();
54257                 return;
54258             }
54259         }
54260
54261         layer = rendererTileLayer(context)
54262             .source(d)
54263             .projection(context.projection)
54264             .dimensions(baseLayer.dimensions());
54265
54266         overlayLayers.push(layer);
54267         dispatch$$1.call('change');
54268         background.updateImagery();
54269     };
54270
54271
54272     background.nudge = function(d, zoom$$1) {
54273         baseLayer.source().nudge(d, zoom$$1);
54274         dispatch$$1.call('change');
54275         background.updateImagery();
54276         return background;
54277     };
54278
54279
54280     background.offset = function(d) {
54281         if (!arguments.length) return baseLayer.source().offset();
54282         baseLayer.source().offset(d);
54283         dispatch$$1.call('change');
54284         background.updateImagery();
54285         return background;
54286     };
54287
54288
54289     background.init = function() {
54290         function parseMap(qmap) {
54291             if (!qmap) return false;
54292             var args = qmap.split('/').map(Number);
54293             if (args.length < 3 || args.some(isNaN)) return false;
54294             return geoExtent$$1([args[2], args[1]]);
54295         }
54296
54297         var dataImagery = data.imagery || [],
54298             q = utilStringQs(window.location.hash.substring(1)),
54299             chosen = q.background || q.layer,
54300             extent$$1 = parseMap(q.map),
54301             best;
54302
54303         backgroundSources = dataImagery.map(function(source) {
54304             if (source.type === 'bing') {
54305                 return rendererBackgroundSource.Bing(source, dispatch$$1);
54306             } else {
54307                 return rendererBackgroundSource(source);
54308             }
54309         });
54310
54311         backgroundSources.unshift(rendererBackgroundSource.None());
54312
54313         if (!chosen && extent$$1) {
54314             best = lodash.find(this.sources(extent$$1), function(s) { return s.best(); });
54315         }
54316
54317         if (chosen && chosen.indexOf('custom:') === 0) {
54318             background.baseLayerSource(rendererBackgroundSource.Custom(chosen.replace(/^custom:/, '')));
54319         } else {
54320             background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
54321         }
54322
54323         var locator = lodash.find(backgroundSources, function(d) {
54324             return d.overlay && d.default;
54325         });
54326
54327         if (locator) {
54328             background.toggleOverlayLayer(locator);
54329         }
54330
54331         var overlays = (q.overlays || '').split(',');
54332         overlays.forEach(function(overlay) {
54333             overlay = findSource(overlay);
54334             if (overlay) {
54335                 background.toggleOverlayLayer(overlay);
54336             }
54337         });
54338
54339         if (q.gpx) {
54340             var gpx = context.layers().layer('gpx');
54341             if (gpx) {
54342                 gpx.url(q.gpx);
54343             }
54344         }
54345
54346         if (q.offset) {
54347             var offset = q.offset.replace(/;/g, ',').split(',').map(function(n) {
54348                 return !isNaN(n) && n;
54349             });
54350
54351             if (offset.length === 2) {
54352                 background.offset(geoMetersToOffset(offset));
54353             }
54354         }
54355     };
54356
54357
54358     return utilRebind(background, dispatch$$1, 'on');
54359 }
54360
54361 function rendererFeatures(context) {
54362     var traffic_roads = {
54363         'motorway': true,
54364         'motorway_link': true,
54365         'trunk': true,
54366         'trunk_link': true,
54367         'primary': true,
54368         'primary_link': true,
54369         'secondary': true,
54370         'secondary_link': true,
54371         'tertiary': true,
54372         'tertiary_link': true,
54373         'residential': true,
54374         'unclassified': true,
54375         'living_street': true
54376     };
54377
54378     var service_roads = {
54379         'service': true,
54380         'road': true,
54381         'track': true
54382     };
54383
54384     var paths = {
54385         'path': true,
54386         'footway': true,
54387         'cycleway': true,
54388         'bridleway': true,
54389         'steps': true,
54390         'pedestrian': true,
54391         'corridor': true
54392     };
54393
54394     var past_futures = {
54395         'proposed': true,
54396         'construction': true,
54397         'abandoned': true,
54398         'dismantled': true,
54399         'disused': true,
54400         'razed': true,
54401         'demolished': true,
54402         'obliterated': true
54403     };
54404
54405     var dispatch$$1 = dispatch('change', 'redraw'),
54406         _cullFactor = 1,
54407         _cache = {},
54408         _features = {},
54409         _stats = {},
54410         _keys = [],
54411         _hidden = [];
54412
54413
54414     function update() {
54415         _hidden = features.hidden();
54416         dispatch$$1.call('change');
54417         dispatch$$1.call('redraw');
54418     }
54419
54420
54421     function defineFeature(k, filter, max$$1) {
54422         _keys.push(k);
54423         _features[k] = {
54424             filter: filter,
54425             enabled: true,   // whether the user wants it enabled..
54426             count: 0,
54427             currentMax: (max$$1 || Infinity),
54428             defaultMax: (max$$1 || Infinity),
54429             enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
54430             disable: function() { this.enabled = false; this.currentMax = 0; },
54431             hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
54432             autoHidden: function() { return this.hidden() && this.currentMax > 0; }
54433         };
54434     }
54435
54436
54437     defineFeature('points', function isPoint(entity, resolver, geometry) {
54438         return geometry === 'point';
54439     }, 200);
54440
54441     defineFeature('traffic_roads', function isTrafficRoad(entity) {
54442         return traffic_roads[entity.tags.highway];
54443     });
54444
54445     defineFeature('service_roads', function isServiceRoad(entity) {
54446         return service_roads[entity.tags.highway];
54447     });
54448
54449     defineFeature('paths', function isPath(entity) {
54450         return paths[entity.tags.highway];
54451     });
54452
54453     defineFeature('buildings', function isBuilding(entity) {
54454         return (
54455             !!entity.tags['building:part'] ||
54456             (!!entity.tags.building && entity.tags.building !== 'no') ||
54457             entity.tags.amenity === 'shelter' ||
54458             entity.tags.parking === 'multi-storey' ||
54459             entity.tags.parking === 'sheds' ||
54460             entity.tags.parking === 'carports' ||
54461             entity.tags.parking === 'garage_boxes'
54462         );
54463     }, 250);
54464
54465     defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
54466         return geometry === 'area' &&
54467             !_features.buildings.filter(entity) &&
54468             !_features.water.filter(entity);
54469     });
54470
54471     defineFeature('boundaries', function isBoundary(entity) {
54472         return !!entity.tags.boundary;
54473     });
54474
54475     defineFeature('water', function isWater(entity) {
54476         return (
54477             !!entity.tags.waterway ||
54478             entity.tags.natural === 'water' ||
54479             entity.tags.natural === 'coastline' ||
54480             entity.tags.natural === 'bay' ||
54481             entity.tags.landuse === 'pond' ||
54482             entity.tags.landuse === 'basin' ||
54483             entity.tags.landuse === 'reservoir' ||
54484             entity.tags.landuse === 'salt_pond'
54485         );
54486     });
54487
54488     defineFeature('rail', function isRail(entity) {
54489         return (
54490             !!entity.tags.railway ||
54491             entity.tags.landuse === 'railway'
54492         ) && !(
54493             traffic_roads[entity.tags.highway] ||
54494             service_roads[entity.tags.highway] ||
54495             paths[entity.tags.highway]
54496         );
54497     });
54498
54499     defineFeature('power', function isPower(entity) {
54500         return !!entity.tags.power;
54501     });
54502
54503     // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
54504     defineFeature('past_future', function isPastFuture(entity) {
54505         if (
54506             traffic_roads[entity.tags.highway] ||
54507             service_roads[entity.tags.highway] ||
54508             paths[entity.tags.highway]
54509         ) { return false; }
54510
54511         var strings = Object.keys(entity.tags);
54512
54513         for (var i = 0; i < strings.length; i++) {
54514             var s = strings[i];
54515             if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
54516         }
54517         return false;
54518     });
54519
54520     // Lines or areas that don't match another feature filter.
54521     // IMPORTANT: The 'others' feature must be the last one defined,
54522     //   so that code in getMatches can skip this test if `hasMatch = true`
54523     defineFeature('others', function isOther(entity, resolver, geometry) {
54524         return (geometry === 'line' || geometry === 'area');
54525     });
54526
54527
54528     function features() {}
54529
54530
54531     features.features = function() {
54532         return _features;
54533     };
54534
54535
54536     features.keys = function() {
54537         return _keys;
54538     };
54539
54540
54541     features.enabled = function(k) {
54542         if (!arguments.length) {
54543             return _keys.filter(function(k) { return _features[k].enabled; });
54544         }
54545         return _features[k] && _features[k].enabled;
54546     };
54547
54548
54549     features.disabled = function(k) {
54550         if (!arguments.length) {
54551             return _keys.filter(function(k) { return !_features[k].enabled; });
54552         }
54553         return _features[k] && !_features[k].enabled;
54554     };
54555
54556
54557     features.hidden = function(k) {
54558         if (!arguments.length) {
54559             return _keys.filter(function(k) { return _features[k].hidden(); });
54560         }
54561         return _features[k] && _features[k].hidden();
54562     };
54563
54564
54565     features.autoHidden = function(k) {
54566         if (!arguments.length) {
54567             return _keys.filter(function(k) { return _features[k].autoHidden(); });
54568         }
54569         return _features[k] && _features[k].autoHidden();
54570     };
54571
54572
54573     features.enable = function(k) {
54574         if (_features[k] && !_features[k].enabled) {
54575             _features[k].enable();
54576             update();
54577         }
54578     };
54579
54580
54581     features.disable = function(k) {
54582         if (_features[k] && _features[k].enabled) {
54583             _features[k].disable();
54584             update();
54585         }
54586     };
54587
54588
54589     features.toggle = function(k) {
54590         if (_features[k]) {
54591             (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
54592             update();
54593         }
54594     };
54595
54596
54597     features.resetStats = function() {
54598         for (var i = 0; i < _keys.length; i++) {
54599             _features[_keys[i]].count = 0;
54600         }
54601         dispatch$$1.call('change');
54602     };
54603
54604
54605     features.gatherStats = function(d, resolver, dimensions) {
54606         var needsRedraw = false,
54607             type = lodash.groupBy(d, function(ent) { return ent.type; }),
54608             entities = [].concat(type.relation || [], type.way || [], type.node || []),
54609             currHidden, geometry, matches, i, j;
54610
54611         for (i = 0; i < _keys.length; i++) {
54612             _features[_keys[i]].count = 0;
54613         }
54614
54615         // adjust the threshold for point/building culling based on viewport size..
54616         // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
54617         _cullFactor = dimensions[0] * dimensions[1] / 1000000;
54618
54619         for (i = 0; i < entities.length; i++) {
54620             geometry = entities[i].geometry(resolver);
54621             if (!(geometry === 'vertex' || geometry === 'relation')) {
54622                 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
54623                 for (j = 0; j < matches.length; j++) {
54624                     _features[matches[j]].count++;
54625                 }
54626             }
54627         }
54628
54629         currHidden = features.hidden();
54630         if (currHidden !== _hidden) {
54631             _hidden = currHidden;
54632             needsRedraw = true;
54633             dispatch$$1.call('change');
54634         }
54635
54636         return needsRedraw;
54637     };
54638
54639
54640     features.stats = function() {
54641         for (var i = 0; i < _keys.length; i++) {
54642             _stats[_keys[i]] = _features[_keys[i]].count;
54643         }
54644
54645         return _stats;
54646     };
54647
54648
54649     features.clear = function(d) {
54650         for (var i = 0; i < d.length; i++) {
54651             features.clearEntity(d[i]);
54652         }
54653     };
54654
54655
54656     features.clearEntity = function(entity) {
54657         delete _cache[osmEntity$$1.key(entity)];
54658     };
54659
54660
54661     features.reset = function() {
54662         _cache = {};
54663     };
54664
54665
54666     features.getMatches = function(entity, resolver, geometry) {
54667         if (geometry === 'vertex' || geometry === 'relation') return {};
54668
54669         var ent = osmEntity$$1.key(entity);
54670         if (!_cache[ent]) {
54671             _cache[ent] = {};
54672         }
54673
54674         if (!_cache[ent].matches) {
54675             var matches = {},
54676                 hasMatch = false;
54677
54678             for (var i = 0; i < _keys.length; i++) {
54679                 if (_keys[i] === 'others') {
54680                     if (hasMatch) continue;
54681
54682                     // Multipolygon members:
54683                     // If an entity...
54684                     //   1. is a way that hasn't matched other 'interesting' feature rules,
54685                     //   2. and it belongs to a single parent multipolygon relation
54686                     // ...then match whatever feature rules the parent multipolygon has matched.
54687                     // see #2548, #2887
54688                     //
54689                     // IMPORTANT:
54690                     // For this to work, getMatches must be called on relations before ways.
54691                     //
54692                     if (entity.type === 'way') {
54693                         var parents = features.getParents(entity, resolver, geometry);
54694                         if (parents.length === 1 && parents[0].isMultipolygon()) {
54695                             var pkey = osmEntity$$1.key(parents[0]);
54696                             if (_cache[pkey] && _cache[pkey].matches) {
54697                                 matches = lodash.clone(_cache[pkey].matches);
54698                                 continue;
54699                             }
54700                         }
54701                     }
54702                 }
54703
54704                 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
54705                     matches[_keys[i]] = hasMatch = true;
54706                 }
54707             }
54708             _cache[ent].matches = matches;
54709         }
54710
54711         return _cache[ent].matches;
54712     };
54713
54714
54715     features.getParents = function(entity, resolver, geometry) {
54716         if (geometry === 'point') return [];
54717
54718         var ent = osmEntity$$1.key(entity);
54719         if (!_cache[ent]) {
54720             _cache[ent] = {};
54721         }
54722
54723         if (!_cache[ent].parents) {
54724             var parents = [];
54725             if (geometry === 'vertex') {
54726                 parents = resolver.parentWays(entity);
54727             } else {   // 'line', 'area', 'relation'
54728                 parents = resolver.parentRelations(entity);
54729             }
54730             _cache[ent].parents = parents;
54731         }
54732         return _cache[ent].parents;
54733     };
54734
54735
54736     features.isHiddenFeature = function(entity, resolver, geometry) {
54737         if (!_hidden.length) return false;
54738         if (!entity.version) return false;
54739
54740         var matches = features.getMatches(entity, resolver, geometry);
54741
54742         for (var i = 0; i < _hidden.length; i++) {
54743             if (matches[_hidden[i]]) return true;
54744         }
54745         return false;
54746     };
54747
54748
54749     features.isHiddenChild = function(entity, resolver, geometry) {
54750         if (!_hidden.length) return false;
54751         if (!entity.version || geometry === 'point') return false;
54752
54753         var parents = features.getParents(entity, resolver, geometry);
54754         if (!parents.length) return false;
54755
54756         for (var i = 0; i < parents.length; i++) {
54757             if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
54758                 return false;
54759             }
54760         }
54761         return true;
54762     };
54763
54764
54765     features.hasHiddenConnections = function(entity, resolver) {
54766         if (!_hidden.length) return false;
54767         var childNodes, connections;
54768
54769         if (entity.type === 'midpoint') {
54770             childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
54771             connections = [];
54772         } else {
54773             childNodes = entity.nodes ? resolver.childNodes(entity) : [];
54774             connections = features.getParents(entity, resolver, entity.geometry(resolver));
54775         }
54776
54777         // gather ways connected to child nodes..
54778         connections = lodash.reduce(childNodes, function(result, e) {
54779             return resolver.isShared(e) ? lodash.union(result, resolver.parentWays(e)) : result;
54780         }, connections);
54781
54782         return connections.length ? lodash.some(connections, function(e) {
54783             return features.isHidden(e, resolver, e.geometry(resolver));
54784         }) : false;
54785     };
54786
54787
54788     features.isHidden = function(entity, resolver, geometry) {
54789         if (!_hidden.length) return false;
54790         if (!entity.version) return false;
54791
54792         var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
54793         return fn(entity, resolver, geometry);
54794     };
54795
54796
54797     features.filter = function(d, resolver) {
54798         if (!_hidden.length) return d;
54799
54800         var result = [];
54801         for (var i = 0; i < d.length; i++) {
54802             var entity = d[i];
54803             if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
54804                 result.push(entity);
54805             }
54806         }
54807         return result;
54808     };
54809
54810
54811     return utilRebind(features, dispatch$$1, 'on');
54812 }
54813
54814 function utilBindOnce(target, type, listener, capture) {
54815     var typeOnce = type + '.once';
54816     function one() {
54817         target.on(typeOnce, null);
54818         listener.apply(this, arguments);
54819     }
54820     target.on(typeOnce, one, capture);
54821     return this;
54822 }
54823
54824 function rendererMap(context) {
54825
54826     var dimensions = [1, 1],
54827         dispatch$$1 = dispatch('move', 'drawn'),
54828         projection = context.projection,
54829         curtainProjection = context.curtainProjection,
54830         dblclickEnabled = true,
54831         redrawEnabled = true,
54832         transformStart = projection.transform(),
54833         transformLast,
54834         transformed = false,
54835         minzoom = 0,
54836         drawLayers = svgLayers(projection, context),
54837         drawPoints = svgPoints$$1(projection, context),
54838         drawVertices = svgVertices$$1(projection, context),
54839         drawLines = svgLines$$1(projection, context),
54840         drawAreas = svgAreas$$1(projection, context),
54841         drawMidpoints = svgMidpoints$$1(projection, context),
54842         drawLabels = svgLabels(projection, context),
54843         supersurface = select(null),
54844         wrapper = select(null),
54845         surface = select(null),
54846         mouse$$1,
54847         mousemove;
54848
54849     var zoom$$1 = zoom()
54850             .scaleExtent([ztok(2), ztok(24)])
54851             .interpolate(interpolateValue)
54852             .filter(zoomEventFilter)
54853             .on('zoom', zoomPan);
54854
54855     var _selection = select(null);
54856
54857
54858     function map$$1(selection$$1) {
54859
54860         _selection = selection$$1;
54861
54862         context
54863             .on('change.map', immediateRedraw);
54864
54865         context.connection()
54866             .on('change.map', immediateRedraw);
54867
54868         context.history()
54869             .on('change.map', immediateRedraw)
54870             .on('undone.map redone.map', function(stack$$1) {
54871                 var mode = context.mode().id;
54872                 if (mode !== 'browse' && mode !== 'select') return;
54873
54874                 var followSelected = false;
54875                 if (Array.isArray(stack$$1.selectedIDs)) {
54876                     followSelected = (stack$$1.selectedIDs.length === 1 && stack$$1.selectedIDs[0][0] === 'n');
54877                     context.enter(
54878                         modeSelect(context, stack$$1.selectedIDs).follow(followSelected)
54879                     );
54880                 }
54881                 if (!followSelected && stack$$1.transform) {
54882                     map$$1.transformEase(stack$$1.transform);
54883                 }
54884             });
54885
54886         context.background()
54887             .on('change.map', immediateRedraw);
54888
54889         context.features()
54890             .on('redraw.map', immediateRedraw);
54891
54892         drawLayers
54893             .on('change.map', function() {
54894                 context.background().updateImagery();
54895                 immediateRedraw();
54896             });
54897
54898         selection$$1
54899             .on('dblclick.map', dblClick)
54900             .call(zoom$$1)
54901             .call(zoom$$1.transform, projection.transform());
54902
54903         supersurface = selection$$1.append('div')
54904             .attr('id', 'supersurface')
54905             .call(utilSetTransform, 0, 0);
54906
54907         // Need a wrapper div because Opera can't cope with an absolutely positioned
54908         // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
54909         wrapper = supersurface
54910             .append('div')
54911             .attr('class', 'layer layer-data');
54912
54913         map$$1.surface = surface = wrapper
54914             .call(drawLayers)
54915             .selectAll('.surface')
54916             .attr('id', 'surface');
54917
54918         surface
54919             .call(drawLabels.observe)
54920             .on('mousedown.zoom', function() {
54921                 if (event.button === 2) {
54922                     event.stopPropagation();
54923                 }
54924             }, true)
54925             .on('mouseup.zoom', function() {
54926                 if (resetTransform()) immediateRedraw();
54927             })
54928             .on('mousemove.map', function() {
54929                 mousemove = event;
54930             })
54931             .on('mouseover.vertices', function() {
54932                 if (map$$1.editable() && !transformed) {
54933                     var hover = event.target.__data__;
54934                     surface.selectAll('.data-layer-osm')
54935                         .call(drawVertices.drawHover, context.graph(), hover, map$$1.extent(), map$$1.zoom());
54936                     dispatch$$1.call('drawn', this, {full: false});
54937                 }
54938             })
54939             .on('mouseout.vertices', function() {
54940                 if (map$$1.editable() && !transformed) {
54941                     var hover = event.relatedTarget && event.relatedTarget.__data__;
54942                     surface.selectAll('.data-layer-osm')
54943                         .call(drawVertices.drawHover, context.graph(), hover, map$$1.extent(), map$$1.zoom());
54944                     dispatch$$1.call('drawn', this, {full: false});
54945                 }
54946             });
54947
54948         supersurface
54949             .call(context.background());
54950
54951         context.on('enter.map', function() {
54952             if (map$$1.editable() && !transformed) {
54953                 var all = context.intersects(map$$1.extent()),
54954                     filter = utilFunctor(true),
54955                     graph = context.graph();
54956
54957                 all = context.features().filter(all, graph);
54958                 surface.selectAll('.data-layer-osm')
54959                     .call(drawVertices, graph, all, filter, map$$1.extent(), map$$1.zoom())
54960                     .call(drawMidpoints, graph, all, filter, map$$1.trimmedExtent());
54961                 dispatch$$1.call('drawn', this, {full: false});
54962             }
54963         });
54964
54965         map$$1.dimensions(utilGetDimensions(selection$$1));
54966     }
54967
54968
54969     function zoomEventFilter() {
54970         // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
54971         // Intercept `mousedown` and check if there is an orphaned zoom gesture.
54972         // This can happen if a previous `mousedown` occurred without a `mouseup`.
54973         // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
54974         // so that d3-zoom won't stop propagation of new `mousedown` events.
54975         if (event.type === 'mousedown') {
54976             var hasOrphan = false;
54977             var listeners = window.__on;
54978             for (var i = 0; i < listeners.length; i++) {
54979                 var listener = listeners[i];
54980                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
54981                     hasOrphan = true;
54982                     break;
54983                 }
54984             }
54985             if (hasOrphan) {
54986                 var event$$1 = window.CustomEvent;
54987                 if (event$$1) {
54988                     event$$1 = new event$$1('mouseup');
54989                 } else {
54990                     event$$1 = window.document.createEvent('Event');
54991                     event$$1.initEvent('mouseup', false, false);
54992                 }
54993                 // Event needs to be dispatched with an event.view property.
54994                 event$$1.view = window;
54995                 window.dispatchEvent(event$$1);
54996             }
54997         }
54998
54999         return event.button !== 2;   // ignore right clicks
55000     }
55001
55002
55003     function ztok(z) {
55004         return 256 * Math.pow(2, z);
55005     }
55006
55007     function ktoz(k) {
55008         return Math.max(Math.log(k) / Math.LN2 - 8, 0);
55009     }
55010
55011     function pxCenter() {
55012         return [dimensions[0] / 2, dimensions[1] / 2];
55013     }
55014
55015
55016     function drawVector(difference, extent$$1) {
55017         var graph = context.graph(),
55018             features = context.features(),
55019             all = context.intersects(map$$1.extent()),
55020             data, filter;
55021
55022         if (difference) {
55023             var complete = difference.complete(map$$1.extent());
55024             data = lodash.compact(lodash.values(complete));
55025             filter = function(d) { return d.id in complete; };
55026             features.clear(data);
55027
55028         } else {
55029             // force a full redraw if gatherStats detects that a feature
55030             // should be auto-hidden (e.g. points or buildings)..
55031             if (features.gatherStats(all, graph, dimensions)) {
55032                 extent$$1 = undefined;
55033             }
55034
55035             if (extent$$1) {
55036                 data = context.intersects(map$$1.extent().intersection(extent$$1));
55037                 var set$$1 = set$2(lodash.map(data, 'id'));
55038                 filter = function(d) { return set$$1.has(d.id); };
55039
55040             } else {
55041                 data = all;
55042                 filter = utilFunctor(true);
55043             }
55044         }
55045
55046         data = features.filter(data, graph);
55047
55048         surface.selectAll('.data-layer-osm')
55049             .call(drawVertices, graph, data, filter, map$$1.extent(), map$$1.zoom())
55050             .call(drawLines, graph, data, filter)
55051             .call(drawAreas, graph, data, filter)
55052             .call(drawMidpoints, graph, data, filter, map$$1.trimmedExtent())
55053             .call(drawLabels, graph, data, filter, dimensions, !difference && !extent$$1)
55054             .call(drawPoints, graph, data, filter);
55055
55056         dispatch$$1.call('drawn', this, {full: true});
55057     }
55058
55059
55060     function editOff() {
55061         context.features().resetStats();
55062         surface.selectAll('.layer-osm *').remove();
55063         dispatch$$1.call('drawn', this, {full: true});
55064     }
55065
55066
55067     function dblClick() {
55068         if (!dblclickEnabled) {
55069             event.preventDefault();
55070             event.stopImmediatePropagation();
55071         }
55072     }
55073
55074
55075     function zoomPan(manualEvent) {
55076         var event$$1 = (manualEvent || event),
55077             source = event$$1.sourceEvent,
55078             eventTransform = event$$1.transform;
55079
55080         if (transformStart.x === eventTransform.x &&
55081             transformStart.y === eventTransform.y &&
55082             transformStart.k === eventTransform.k) {
55083             return;  // no change
55084         }
55085
55086         // Normalize mousewheel - #3029
55087         // If wheel delta is provided in LINE units, recalculate it in PIXEL units
55088         // We are essentially redoing the calculations that occur here:
55089         //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
55090         // See this for more info:
55091         //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
55092         if (source && source.type === 'wheel' && source.deltaMode === 1 /* LINE */) {
55093             // pick sensible scroll amount if user scrolling fast or slow..
55094             var lines = Math.abs(source.deltaY),
55095                 scroll = lines > 2 ? 40 : lines * 10;
55096
55097             var t0 = transformed ? transformLast : transformStart,
55098                 p0 = mouse$$1(source),
55099                 p1 = t0.invert(p0),
55100                 k2 = t0.k * Math.pow(2, -source.deltaY * scroll / 500),
55101                 x2 = p0[0] - p1[0] * k2,
55102                 y2 = p0[1] - p1[1] * k2;
55103
55104             eventTransform = identity$8.translate(x2,y2).scale(k2);
55105             _selection.node().__zoom = eventTransform;
55106         }
55107
55108         if (ktoz(eventTransform.k * 2 * Math.PI) < minzoom) {
55109             surface.interrupt();
55110             uiFlash().text(t('cannot_zoom'));
55111             setZoom(context.minEditableZoom(), true);
55112             queueRedraw();
55113             dispatch$$1.call('move', this, map$$1);
55114             return;
55115         }
55116
55117         projection.transform(eventTransform);
55118
55119         var scale = eventTransform.k / transformStart.k,
55120             tX = (eventTransform.x / scale - transformStart.x) * scale,
55121             tY = (eventTransform.y / scale - transformStart.y) * scale;
55122
55123         if (context.inIntro()) {
55124             curtainProjection.transform({
55125                 x: eventTransform.x - tX,
55126                 y: eventTransform.y - tY,
55127                 k: eventTransform.k
55128             });
55129         }
55130
55131         transformed = true;
55132         transformLast = eventTransform;
55133         utilSetTransform(supersurface, tX, tY, scale);
55134         queueRedraw();
55135
55136         dispatch$$1.call('move', this, map$$1);
55137     }
55138
55139
55140     function resetTransform() {
55141         if (!transformed) return false;
55142
55143         // deprecation warning - Radial Menu to be removed in iD v3
55144         surface.selectAll('.edit-menu, .radial-menu').interrupt().remove();
55145         utilSetTransform(supersurface, 0, 0);
55146         transformed = false;
55147         if (context.inIntro()) {
55148             curtainProjection.transform(projection.transform());
55149         }
55150         return true;
55151     }
55152
55153
55154     function redraw(difference, extent$$1) {
55155         if (surface.empty() || !redrawEnabled) return;
55156
55157         // If we are in the middle of a zoom/pan, we can't do differenced redraws.
55158         // It would result in artifacts where differenced entities are redrawn with
55159         // one transform and unchanged entities with another.
55160         if (resetTransform()) {
55161             difference = extent$$1 = undefined;
55162         }
55163
55164         var z = String(~~map$$1.zoom());
55165         if (surface.attr('data-zoom') !== z) {
55166             surface.attr('data-zoom', z)
55167                 .classed('low-zoom', z <= 16);
55168         }
55169
55170         if (!difference) {
55171             supersurface.call(context.background());
55172         }
55173
55174         wrapper
55175             .call(drawLayers);
55176
55177         // OSM
55178         if (map$$1.editable()) {
55179             context.loadTiles(projection, dimensions);
55180             drawVector(difference, extent$$1);
55181         } else {
55182             editOff();
55183         }
55184
55185         transformStart = projection.transform();
55186
55187         return map$$1;
55188     }
55189
55190
55191     var queueRedraw = lodash.throttle(redraw, 750);
55192
55193
55194     var immediateRedraw = function(difference, extent$$1) {
55195         if (!difference && !extent$$1) queueRedraw.cancel();
55196         redraw(difference, extent$$1);
55197     };
55198
55199
55200     function pointLocation(p) {
55201         var translate = projection.translate(),
55202             scale = projection.scale() * 2 * Math.PI;
55203         return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
55204     }
55205
55206
55207     function locationPoint(l) {
55208         var translate = projection.translate(),
55209             scale = projection.scale() * 2 * Math.PI;
55210         return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
55211     }
55212
55213
55214     map$$1.mouse = function() {
55215         var event$$1 = mousemove || event;
55216         if (event$$1) {
55217             var s;
55218             while ((s = event$$1.sourceEvent)) { event$$1 = s; }
55219             return mouse$$1(event$$1);
55220         }
55221         return null;
55222     };
55223
55224
55225     map$$1.mouseCoordinates = function() {
55226         return projection.invert(map$$1.mouse());
55227     };
55228
55229
55230     map$$1.dblclickEnable = function(_) {
55231         if (!arguments.length) return dblclickEnabled;
55232         dblclickEnabled = _;
55233         return map$$1;
55234     };
55235
55236
55237     map$$1.redrawEnable = function(_) {
55238         if (!arguments.length) return redrawEnabled;
55239         redrawEnabled = _;
55240         return map$$1;
55241     };
55242
55243
55244     function setTransform(t2, duration, force) {
55245         var t$$1 = projection.transform();
55246         if (!force && t2.k === t$$1.k && t2.x === t$$1.x && t2.y === t$$1.y) {
55247             return false;
55248         }
55249
55250         if (duration) {
55251             _selection
55252                 .transition()
55253                 .duration(duration)
55254                 .on('start', function() { map$$1.startEase(); })
55255                 .call(zoom$$1.transform, identity$8.translate(t2.x, t2.y).scale(t2.k));
55256         } else {
55257             projection.transform(t2);
55258             transformStart = t2;
55259             _selection.call(zoom$$1.transform, transformStart);
55260         }
55261     }
55262
55263
55264     function setZoom(z2, force, duration) {
55265         if (z2 === map$$1.zoom() && !force) {
55266             return false;
55267         }
55268
55269         var k = projection.scale(),
55270             k2 = Math.max(ztok(2), Math.min(ztok(24), ztok(z2))) / (2 * Math.PI),
55271             center = pxCenter(),
55272             l = pointLocation(center);
55273
55274         projection.scale(k2);
55275
55276         var t$$1 = projection.translate();
55277         l = locationPoint(l);
55278
55279         t$$1[0] += center[0] - l[0];
55280         t$$1[1] += center[1] - l[1];
55281
55282         if (duration) {
55283             projection.scale(k);  // reset scale
55284             _selection
55285                 .transition()
55286                 .duration(duration)
55287                 .on('start', function() { map$$1.startEase(); })
55288                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k2));
55289         } else {
55290             projection.translate(t$$1);
55291             transformStart = projection.transform();
55292             _selection.call(zoom$$1.transform, transformStart);
55293         }
55294
55295         return true;
55296     }
55297
55298
55299     function setCenter(loc2, duration) {
55300         var c = map$$1.center();
55301         if (loc2[0] === c[0] && loc2[1] === c[1]) {
55302             return false;
55303         }
55304
55305         var t$$1 = projection.translate(),
55306             k = projection.scale(),
55307             pxC = pxCenter(),
55308             ll = projection(loc2);
55309
55310         t$$1[0] = t$$1[0] - ll[0] + pxC[0];
55311         t$$1[1] = t$$1[1] - ll[1] + pxC[1];
55312
55313         if (duration) {
55314             _selection
55315                 .transition()
55316                 .duration(duration)
55317                 .on('start', function() { map$$1.startEase(); })
55318                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
55319         } else {
55320             projection.translate(t$$1);
55321             transformStart = projection.transform();
55322             _selection.call(zoom$$1.transform, transformStart);
55323         }
55324
55325         return true;
55326     }
55327
55328
55329     map$$1.pan = function(delta, duration) {
55330         var t$$1 = projection.translate(),
55331             k = projection.scale();
55332
55333         t$$1[0] += delta[0];
55334         t$$1[1] += delta[1];
55335
55336         if (duration) {
55337             _selection
55338                 .transition()
55339                 .duration(duration)
55340                 .on('start', function() { map$$1.startEase(); })
55341                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
55342         } else {
55343             projection.translate(t$$1);
55344             transformStart = projection.transform();
55345             _selection.call(zoom$$1.transform, transformStart);
55346             dispatch$$1.call('move', this, map$$1);
55347             immediateRedraw();
55348         }
55349
55350         return map$$1;
55351     };
55352
55353
55354     map$$1.dimensions = function(_) {
55355         if (!arguments.length) return dimensions;
55356         var center = map$$1.center();
55357         dimensions = _;
55358         drawLayers.dimensions(dimensions);
55359         context.background().dimensions(dimensions);
55360         projection.clipExtent([[0, 0], dimensions]);
55361         mouse$$1 = utilFastMouse(supersurface.node());
55362         setCenter(center);
55363
55364         queueRedraw();
55365         return map$$1;
55366     };
55367
55368
55369     function zoomIn(delta) {
55370         setZoom(~~map$$1.zoom() + delta, true, 250);
55371     }
55372
55373     function zoomOut(delta) {
55374         setZoom(~~map$$1.zoom() - delta, true, 250);
55375     }
55376
55377     map$$1.zoomIn = function() { zoomIn(1); };
55378     map$$1.zoomInFurther = function() { zoomIn(4); };
55379
55380     map$$1.zoomOut = function() { zoomOut(1); };
55381     map$$1.zoomOutFurther = function() { zoomOut(4); };
55382
55383
55384     map$$1.center = function(loc2) {
55385         if (!arguments.length) {
55386             return projection.invert(pxCenter());
55387         }
55388
55389         if (setCenter(loc2)) {
55390             dispatch$$1.call('move', this, map$$1);
55391         }
55392
55393         queueRedraw();
55394         return map$$1;
55395     };
55396
55397
55398     map$$1.zoom = function(z2) {
55399         if (!arguments.length) {
55400             return Math.max(ktoz(projection.scale() * 2 * Math.PI), 0);
55401         }
55402
55403         if (z2 < minzoom) {
55404             surface.interrupt();
55405             uiFlash().text(t('cannot_zoom'));
55406             z2 = context.minEditableZoom();
55407         }
55408
55409         if (setZoom(z2)) {
55410             dispatch$$1.call('move', this, map$$1);
55411         }
55412
55413         queueRedraw();
55414         return map$$1;
55415     };
55416
55417
55418     map$$1.zoomTo = function(entity, zoomLimits) {
55419         var extent$$1 = entity.extent(context.graph());
55420         if (!isFinite(extent$$1.area())) return;
55421
55422         var z2 = map$$1.trimmedExtentZoom(extent$$1);
55423         zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
55424         map$$1.centerZoom(extent$$1.center(), Math.min(Math.max(z2, zoomLimits[0]), zoomLimits[1]));
55425     };
55426
55427
55428     map$$1.centerZoom = function(loc2, z2) {
55429         var centered = setCenter(loc2),
55430             zoomed   = setZoom(z2);
55431
55432         if (centered || zoomed) {
55433             dispatch$$1.call('move', this, map$$1);
55434         }
55435
55436         queueRedraw();
55437         return map$$1;
55438     };
55439
55440
55441     map$$1.centerEase = function(loc2, duration) {
55442         duration = duration || 250;
55443         setCenter(loc2, duration);
55444         return map$$1;
55445     };
55446
55447
55448     map$$1.zoomEase = function(z2, duration) {
55449         duration = duration || 250;
55450         setZoom(z2, false, duration);
55451         return map$$1;
55452     };
55453
55454
55455     map$$1.transformEase = function(t2, duration) {
55456         duration = duration || 250;
55457         setTransform(t2, duration, false);
55458         return map$$1;
55459     };
55460
55461
55462     map$$1.startEase = function() {
55463         utilBindOnce(surface, 'mousedown.ease', function() {
55464             map$$1.cancelEase();
55465         });
55466         return map$$1;
55467     };
55468
55469
55470     map$$1.cancelEase = function() {
55471         _selection.interrupt();
55472         return map$$1;
55473     };
55474
55475
55476     map$$1.extent = function(_) {
55477         if (!arguments.length) {
55478             return new geoExtent$$1(projection.invert([0, dimensions[1]]),
55479                                  projection.invert([dimensions[0], 0]));
55480         } else {
55481             var extent$$1 = geoExtent$$1(_);
55482             map$$1.centerZoom(extent$$1.center(), map$$1.extentZoom(extent$$1));
55483         }
55484     };
55485
55486
55487     map$$1.trimmedExtent = function(_) {
55488         if (!arguments.length) {
55489             var headerY = 60, footerY = 30, pad = 10;
55490             return new geoExtent$$1(projection.invert([pad, dimensions[1] - footerY - pad]),
55491                                  projection.invert([dimensions[0] - pad, headerY + pad]));
55492         } else {
55493             var extent$$1 = geoExtent$$1(_);
55494             map$$1.centerZoom(extent$$1.center(), map$$1.trimmedExtentZoom(extent$$1));
55495         }
55496     };
55497
55498
55499     function calcZoom(extent$$1, dim) {
55500         var tl = projection([extent$$1[0][0], extent$$1[1][1]]),
55501             br = projection([extent$$1[1][0], extent$$1[0][1]]);
55502
55503         // Calculate maximum zoom that fits extent
55504         var hFactor = (br[0] - tl[0]) / dim[0],
55505             vFactor = (br[1] - tl[1]) / dim[1],
55506             hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
55507             vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
55508             newZoom = map$$1.zoom() - Math.max(hZoomDiff, vZoomDiff);
55509
55510         return newZoom;
55511     }
55512
55513
55514     map$$1.extentZoom = function(_) {
55515         return calcZoom(geoExtent$$1(_), dimensions);
55516     };
55517
55518
55519     map$$1.trimmedExtentZoom = function(_) {
55520         var trimY = 120, trimX = 40,
55521             trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
55522         return calcZoom(geoExtent$$1(_), trimmed);
55523     };
55524
55525
55526     map$$1.editable = function() {
55527         return map$$1.zoom() >= context.minEditableZoom();
55528     };
55529
55530
55531     map$$1.minzoom = function(_) {
55532         if (!arguments.length) return minzoom;
55533         minzoom = _;
55534         return map$$1;
55535     };
55536
55537
55538     map$$1.layers = drawLayers;
55539
55540
55541     return utilRebind(map$$1, dispatch$$1, 'on');
55542 }
55543
55544 var TAU = 2 * Math.PI;
55545 function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
55546 function ktoz(k) { return Math.log(k * TAU) / Math.LN2 - 8; }
55547 function vecSub(a, b) { return [ a[0] - b[0], a[1] - b[1] ]; }
55548 function vecScale(a, b) { return [ a[0] * b, a[1] * b ]; }
55549
55550
55551 function uiMapInMap(context) {
55552     var key = '/';
55553
55554
55555     function map_in_map(selection$$1) {
55556         var backgroundLayer = rendererTileLayer(context),
55557             overlayLayers = {},
55558             projection = geoRawMercator(),
55559             gpxLayer = svgGpx(projection, context).showLabels(false),
55560             debugLayer = svgDebug(projection, context),
55561             zoom$$1 = zoom()
55562                 .scaleExtent([ztok(0.5), ztok(24)])
55563                 .on('start', zoomStarted)
55564                 .on('zoom', zoomed)
55565                 .on('end', zoomEnded),
55566             isTransformed = false,
55567             isHidden = true,
55568             skipEvents = false,
55569             gesture = null,
55570             zDiff = 6,    // by default, minimap renders at (main zoom - 6)
55571             wrap = select(null),
55572             tiles = select(null),
55573             viewport = select(null),
55574             tStart,  // transform at start of gesture
55575             tCurr,   // transform at most recent event
55576             timeoutId;
55577
55578
55579         function zoomStarted() {
55580             if (skipEvents) return;
55581             tStart = tCurr = projection.transform();
55582             gesture = null;
55583         }
55584
55585
55586         function zoomed() {
55587             if (skipEvents) return;
55588
55589             var x = event.transform.x,
55590                 y = event.transform.y,
55591                 k = event.transform.k,
55592                 isZooming = (k !== tStart.k),
55593                 isPanning = (x !== tStart.x || y !== tStart.y);
55594
55595             if (!isZooming && !isPanning) {
55596                 return;  // no change
55597             }
55598
55599             // lock in either zooming or panning, don't allow both in minimap.
55600             if (!gesture) {
55601                 gesture = isZooming ? 'zoom' : 'pan';
55602             }
55603
55604             var tMini = projection.transform(),
55605                 tX, tY, scale;
55606
55607             if (gesture === 'zoom') {
55608                 var dMini = utilGetDimensions(wrap),
55609                     cMini = vecScale(dMini, 0.5);
55610                 scale = k / tMini.k;
55611                 tX = (cMini[0] / scale - cMini[0]) * scale;
55612                 tY = (cMini[1] / scale - cMini[1]) * scale;
55613             } else {
55614                 k = tMini.k;
55615                 scale = 1;
55616                 tX = x - tMini.x;
55617                 tY = y - tMini.y;
55618             }
55619
55620             utilSetTransform(tiles, tX, tY, scale);
55621             utilSetTransform(viewport, 0, 0, scale);
55622             isTransformed = true;
55623             tCurr = identity$8.translate(x, y).scale(k);
55624
55625             var zMain = ktoz(context.projection.scale()),
55626                 zMini = ktoz(k);
55627
55628             zDiff = zMain - zMini;
55629
55630             queueRedraw();
55631         }
55632
55633
55634         function zoomEnded() {
55635             if (skipEvents) return;
55636             if (gesture !== 'pan') return;
55637
55638             updateProjection();
55639             gesture = null;
55640             var dMini = utilGetDimensions(wrap),
55641                 cMini = vecScale(dMini, 0.5);
55642             context.map().center(projection.invert(cMini));   // recenter main map..
55643         }
55644
55645
55646         function updateProjection() {
55647             var loc = context.map().center(),
55648                 dMini = utilGetDimensions(wrap),
55649                 cMini = vecScale(dMini, 0.5),
55650                 tMain = context.projection.transform(),
55651                 zMain = ktoz(tMain.k),
55652                 zMini = Math.max(zMain - zDiff, 0.5),
55653                 kMini = ztok(zMini);
55654
55655             projection
55656                 .translate([tMain.x, tMain.y])
55657                 .scale(kMini);
55658
55659             var point = projection(loc),
55660                 mouse$$1 = (gesture === 'pan') ? vecSub([tCurr.x, tCurr.y], [tStart.x, tStart.y]) : [0, 0],
55661                 xMini = cMini[0] - point[0] + tMain.x + mouse$$1[0],
55662                 yMini = cMini[1] - point[1] + tMain.y + mouse$$1[1];
55663
55664             projection
55665                 .translate([xMini, yMini])
55666                 .clipExtent([[0, 0], dMini]);
55667
55668             tCurr = projection.transform();
55669
55670             if (isTransformed) {
55671                 utilSetTransform(tiles, 0, 0);
55672                 utilSetTransform(viewport, 0, 0);
55673                 isTransformed = false;
55674             }
55675
55676             zoom$$1
55677                 .scaleExtent([ztok(0.5), ztok(zMain - 3)]);
55678
55679             skipEvents = true;
55680             wrap.call(zoom$$1.transform, tCurr);
55681             skipEvents = false;
55682         }
55683
55684
55685         function redraw() {
55686             clearTimeout(timeoutId);
55687             if (isHidden) return;
55688
55689             updateProjection();
55690
55691             var dMini = utilGetDimensions(wrap),
55692                 zMini = ktoz(projection.scale());
55693
55694             // setup tile container
55695             tiles = wrap
55696                 .selectAll('.map-in-map-tiles')
55697                 .data([0]);
55698
55699             tiles = tiles.enter()
55700                 .append('div')
55701                 .attr('class', 'map-in-map-tiles')
55702                 .merge(tiles);
55703
55704             // redraw background
55705             backgroundLayer
55706                 .source(context.background().baseLayerSource())
55707                 .projection(projection)
55708                 .dimensions(dMini);
55709
55710             var background = tiles
55711                 .selectAll('.map-in-map-background')
55712                 .data([0]);
55713
55714             background.enter()
55715                 .append('div')
55716                 .attr('class', 'map-in-map-background')
55717                 .merge(background)
55718                 .call(backgroundLayer);
55719
55720
55721             // redraw overlay
55722             var overlaySources = context.background().overlayLayerSources();
55723             var activeOverlayLayers = [];
55724             for (var i = 0; i < overlaySources.length; i++) {
55725                 if (overlaySources[i].validZoom(zMini)) {
55726                     if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
55727                     activeOverlayLayers.push(overlayLayers[i]
55728                         .source(overlaySources[i])
55729                         .projection(projection)
55730                         .dimensions(dMini));
55731                 }
55732             }
55733
55734             var overlay = tiles
55735                 .selectAll('.map-in-map-overlay')
55736                 .data([0]);
55737
55738             overlay = overlay.enter()
55739                 .append('div')
55740                 .attr('class', 'map-in-map-overlay')
55741                 .merge(overlay);
55742
55743
55744             var overlays = overlay
55745                 .selectAll('div')
55746                 .data(activeOverlayLayers, function(d) { return d.source().name(); });
55747
55748             overlays.exit()
55749                 .remove();
55750
55751             overlays = overlays.enter()
55752                 .append('div')
55753                 .merge(overlays)
55754                 .each(function(layer) { select(this).call(layer); });
55755
55756
55757             var dataLayers = tiles
55758                 .selectAll('.map-in-map-data')
55759                 .data([0]);
55760
55761             dataLayers.exit()
55762                 .remove();
55763
55764             dataLayers = dataLayers.enter()
55765                 .append('svg')
55766                 .attr('class', 'map-in-map-data')
55767                 .merge(dataLayers)
55768                 .call(gpxLayer)
55769                 .call(debugLayer);
55770
55771
55772             // redraw viewport bounding box
55773             if (gesture !== 'pan') {
55774                 var getPath = index$4(projection),
55775                     bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
55776
55777                 viewport = wrap.selectAll('.map-in-map-viewport')
55778                     .data([0]);
55779
55780                 viewport = viewport.enter()
55781                     .append('svg')
55782                     .attr('class', 'map-in-map-viewport')
55783                     .merge(viewport);
55784
55785
55786                 var path$$1 = viewport.selectAll('.map-in-map-bbox')
55787                     .data([bbox]);
55788
55789                 path$$1.enter()
55790                     .append('path')
55791                     .attr('class', 'map-in-map-bbox')
55792                     .merge(path$$1)
55793                     .attr('d', getPath)
55794                     .classed('thick', function(d) { return getPath.area(d) < 30; });
55795             }
55796         }
55797
55798
55799         function queueRedraw() {
55800             clearTimeout(timeoutId);
55801             timeoutId = setTimeout(function() { redraw(); }, 750);
55802         }
55803
55804
55805         function toggle() {
55806             if (event) event.preventDefault();
55807
55808             isHidden = !isHidden;
55809
55810             var label = select('.minimap-toggle');
55811             label.classed('active', !isHidden)
55812                 .select('input').property('checked', !isHidden);
55813
55814             if (isHidden) {
55815                 wrap
55816                     .style('display', 'block')
55817                     .style('opacity', '1')
55818                     .transition()
55819                     .duration(200)
55820                     .style('opacity', '0')
55821                     .on('end', function() {
55822                         selection$$1.selectAll('.map-in-map')
55823                             .style('display', 'none');
55824                     });
55825             } else {
55826                 wrap
55827                     .style('display', 'block')
55828                     .style('opacity', '0')
55829                     .transition()
55830                     .duration(200)
55831                     .style('opacity', '1')
55832                     .on('end', function() {
55833                         redraw();
55834                     });
55835             }
55836         }
55837
55838
55839         uiMapInMap.toggle = toggle;
55840
55841         wrap = selection$$1.selectAll('.map-in-map')
55842             .data([0]);
55843
55844         wrap = wrap.enter()
55845             .append('div')
55846             .attr('class', 'map-in-map')
55847             .style('display', (isHidden ? 'none' : 'block'))
55848             .call(zoom$$1)
55849             .on('dblclick.zoom', null)
55850             .merge(wrap);
55851
55852         context.map()
55853             .on('drawn.map-in-map', function(drawn) {
55854                 if (drawn.full === true) {
55855                     redraw();
55856                 }
55857             });
55858
55859         redraw();
55860
55861         var keybinding = d3keybinding('map-in-map')
55862             .on(key, toggle);
55863
55864         select(document)
55865             .call(keybinding);
55866     }
55867
55868     return map_in_map;
55869 }
55870
55871 function uiTooltipHtml(text, key, heading) {
55872     var s = '';
55873
55874     if (heading) {
55875         s += '<div class="tooltip-heading"><span>' + heading + '</span></div>';
55876     }
55877     if (text) {
55878         s += '<div class="tooltip-text"><span>' + text + '</span></div>';
55879     }
55880     if (key) {
55881         s += '<div class="keyhint-wrap"><span>' + t('tooltip_keyhint') + '</span>' +
55882             '<span class="keyhint">' + key + '</span></div>';
55883     }
55884
55885     return s;
55886 }
55887
55888 function uiBackground(context) {
55889     var key = 'B',
55890         detected = utilDetect(),
55891         opacities = [1, 0.75, 0.5, 0.25],
55892         directions = [
55893             ['right', [0.5, 0]],
55894             ['top', [0, -0.5]],
55895             ['left', [-0.5, 0]],
55896             ['bottom', [0, 0.5]]],
55897         opacityDefault = (context.storage('background-opacity') !== null) ?
55898             (+context.storage('background-opacity')) : 1.0,
55899         customTemplate = context.storage('background-custom-template') || '',
55900         previous;
55901
55902     // Can be 0 from <1.3.0 use or due to issue #1923.
55903     if (opacityDefault === 0) opacityDefault = 1.0;
55904
55905
55906     function background(selection$$1) {
55907
55908         function sortSources(a, b) {
55909             return a.best() && !b.best() ? -1
55910                 : b.best() && !a.best() ? 1
55911                 : descending(a.area(), b.area()) || ascending(a.name(), b.name()) || 0;
55912         }
55913
55914
55915         function setOpacity(d) {
55916             var bg = context.container().selectAll('.layer-background')
55917                 .transition()
55918                 .style('opacity', d)
55919                 .attr('data-opacity', d);
55920
55921             if (!detected.opera) {
55922                 utilSetTransform(bg, 0, 0);
55923             }
55924
55925             opacityList.selectAll('li')
55926                 .classed('active', function(_) { return _ === d; });
55927
55928             context.storage('background-opacity', d);
55929         }
55930
55931
55932         function setTooltips(selection$$1) {
55933             selection$$1.each(function(d, i, nodes) {
55934                 var item = select(this).select('label'),
55935                     span = item.select('span'),
55936                     placement = (i < nodes.length / 2) ? 'bottom' : 'top',
55937                     isOverflowing = (span.property('clientWidth') !== span.property('scrollWidth'));
55938
55939                 if (d === previous) {
55940                     item.call(tooltip()
55941                         .placement(placement)
55942                         .html(true)
55943                         .title(function() {
55944                             var tip = '<div>' + t('background.switch') + '</div>';
55945                             return uiTooltipHtml(tip, uiCmd('⌘B'));
55946                         })
55947                     );
55948                 } else if (d.description || isOverflowing) {
55949                     item.call(tooltip()
55950                         .placement(placement)
55951                         .title(d.description || d.name())
55952                     );
55953                 } else {
55954                     item.call(tooltip().destroy);
55955                 }
55956             });
55957         }
55958
55959
55960         function selectLayer() {
55961             function active$$1(d) {
55962                 return context.background().showsLayer(d);
55963             }
55964
55965             content.selectAll('.layer, .custom_layer')
55966                 .classed('active', active$$1)
55967                 .classed('switch', function(d) { return d === previous; })
55968                 .call(setTooltips)
55969                 .selectAll('input')
55970                 .property('checked', active$$1);
55971         }
55972
55973
55974         function clickSetSource(d) {
55975             event.preventDefault();
55976             previous = context.background().baseLayerSource();
55977             context.background().baseLayerSource(d);
55978             selectLayer();
55979             document.activeElement.blur();
55980         }
55981
55982
55983         function editCustom() {
55984             event.preventDefault();
55985             var template = window.prompt(t('background.custom_prompt'), customTemplate);
55986             if (template) {
55987                 setCustom(template);
55988             } else {
55989                 selectLayer();
55990             }
55991         }
55992
55993
55994         function setCustom(template) {
55995             context.storage('background-custom-template', template);
55996             var d = rendererBackgroundSource.Custom(template);
55997             content.selectAll('.custom_layer').datum(d);
55998             clickSetSource(d);
55999         }
56000
56001
56002         function clickSetOverlay(d) {
56003             event.preventDefault();
56004             context.background().toggleOverlayLayer(d);
56005             selectLayer();
56006             document.activeElement.blur();
56007         }
56008
56009
56010         function drawList(layerList, type, change, filter) {
56011             var sources = context.background()
56012                 .sources(context.map().extent())
56013                 .filter(filter);
56014
56015             var layerLinks = layerList.selectAll('li.layer')
56016                 .data(sources, function(d) { return d.name(); });
56017
56018             layerLinks.exit()
56019                 .remove();
56020
56021             var enter = layerLinks.enter()
56022                 .insert('li', '.custom_layer')
56023                 .attr('class', 'layer')
56024                 .classed('best', function(d) { return d.best(); });
56025
56026             enter.filter(function(d) { return d.best(); })
56027                 .append('div')
56028                 .attr('class', 'best')
56029                 .call(tooltip()
56030                     .title(t('background.best_imagery'))
56031                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
56032                 .append('span')
56033                 .html('&#9733;');
56034
56035             var label = enter
56036                 .append('label');
56037
56038             label
56039                 .append('input')
56040                 .attr('type', type)
56041                 .attr('name', 'layers')
56042                 .on('change', change);
56043
56044             label
56045                 .append('span')
56046                 .text(function(d) { return d.name(); });
56047
56048
56049             layerList.selectAll('li.layer')
56050                 .sort(sortSources)
56051                 .style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
56052         }
56053
56054
56055         function update() {
56056             backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
56057             overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
56058
56059             selectLayer();
56060
56061             var source = context.background().baseLayerSource();
56062             if (source.id === 'custom') {
56063                 customTemplate = source.template;
56064             }
56065
56066             updateOffsetVal();
56067         }
56068
56069
56070         function updateOffsetVal() {
56071             var meters = geoOffsetToMeters(context.background().offset()),
56072                 x = +meters[0].toFixed(2),
56073                 y = +meters[1].toFixed(2);
56074
56075             selectAll('.nudge-inner-rect')
56076                 .select('input')
56077                 .classed('error', false)
56078                 .property('value', x + ', ' + y);
56079
56080             selectAll('.nudge-reset')
56081                 .classed('disabled', function() {
56082                     return (x === 0 && y === 0);
56083                 });
56084         }
56085
56086
56087         function resetOffset() {
56088             if (event.button !== 0) return;
56089             context.background().offset([0, 0]);
56090             updateOffsetVal();
56091         }
56092
56093
56094         function nudge(d) {
56095             context.background().nudge(d, context.map().zoom());
56096             updateOffsetVal();
56097         }
56098
56099
56100         function buttonOffset(d) {
56101             if (event.button !== 0) return;
56102             var timeout$$1 = window.setTimeout(function() {
56103                     interval$$1 = window.setInterval(nudge.bind(null, d), 100);
56104                 }, 500),
56105                 interval$$1;
56106
56107             function doneNudge() {
56108                 window.clearTimeout(timeout$$1);
56109                 window.clearInterval(interval$$1);
56110                 select(window)
56111                     .on('mouseup.buttonoffset', null, true)
56112                     .on('mousedown.buttonoffset', null, true);
56113             }
56114
56115             select(window)
56116                 .on('mouseup.buttonoffset', doneNudge, true)
56117                 .on('mousedown.buttonoffset', doneNudge, true);
56118
56119             nudge(d);
56120         }
56121
56122
56123         function inputOffset() {
56124             if (event.button !== 0) return;
56125             var input = select(this);
56126             var d = input.node().value;
56127
56128             if (d === '') return resetOffset();
56129
56130             d = d.replace(/;/g, ',').split(',').map(function(n) {
56131                 // if n is NaN, it will always get mapped to false.
56132                 return !isNaN(n) && n;
56133             });
56134
56135             if (d.length !== 2 || !d[0] || !d[1]) {
56136                 input.classed('error', true);
56137                 return;
56138             }
56139
56140             context.background().offset(geoMetersToOffset(d));
56141             updateOffsetVal();
56142         }
56143
56144
56145         function dragOffset() {
56146             if (event.button !== 0) return;
56147             var origin = [event.clientX, event.clientY];
56148
56149             context.container()
56150                 .append('div')
56151                 .attr('class', 'nudge-surface');
56152
56153             select(window)
56154                 .on('mousemove.offset', function() {
56155                     var latest = [event.clientX, event.clientY];
56156                     var d = [
56157                         -(origin[0] - latest[0]) / 4,
56158                         -(origin[1] - latest[1]) / 4
56159                     ];
56160
56161                     origin = latest;
56162                     nudge(d);
56163                 })
56164                 .on('mouseup.offset', function() {
56165                     if (event.button !== 0) return;
56166                     selectAll('.nudge-surface')
56167                         .remove();
56168
56169                     select(window)
56170                         .on('mousemove.offset', null)
56171                         .on('mouseup.offset', null);
56172                 });
56173
56174             event.preventDefault();
56175         }
56176
56177
56178         function hide() {
56179             setVisible(false);
56180         }
56181
56182
56183         function toggle() {
56184             if (event) event.preventDefault();
56185             tooltipBehavior.hide(button);
56186             setVisible(!button.classed('active'));
56187         }
56188
56189
56190         function quickSwitch() {
56191             if (previous) {
56192                 clickSetSource(previous);
56193             }
56194         }
56195
56196
56197         function setVisible(show) {
56198             if (show !== shown) {
56199                 button.classed('active', show);
56200                 shown = show;
56201
56202                 if (show) {
56203                     selection$$1
56204                         .on('mousedown.background-inside', function() {
56205                             event.stopPropagation();
56206                         });
56207
56208                     content
56209                         .style('display', 'block')
56210                         .style('right', '-300px')
56211                         .transition()
56212                         .duration(200)
56213                         .style('right', '0px');
56214
56215                     content.selectAll('.layer, .custom_layer')
56216                         .call(setTooltips);
56217
56218                 } else {
56219                     content
56220                         .style('display', 'block')
56221                         .style('right', '0px')
56222                         .transition()
56223                         .duration(200)
56224                         .style('right', '-300px')
56225                         .on('end', function() {
56226                             select(this).style('display', 'none');
56227                         });
56228
56229                     selection$$1
56230                         .on('mousedown.background-inside', null);
56231                 }
56232             }
56233         }
56234
56235
56236         var content = selection$$1
56237                 .append('div')
56238                 .attr('class', 'fillL map-overlay col3 content hide'),
56239             tooltipBehavior = tooltip()
56240                 .placement((textDirection === 'rtl') ? 'right' : 'left')
56241                 .html(true)
56242                 .title(uiTooltipHtml(t('background.description'), key)),
56243             button = selection$$1
56244                 .append('button')
56245                 .attr('tabindex', -1)
56246                 .on('click', toggle)
56247                 .call(svgIcon('#icon-layers', 'light'))
56248                 .call(tooltipBehavior),
56249             shown = false;
56250
56251
56252         /* opacity switcher */
56253
56254         var opawrap = content
56255                 .append('div')
56256                 .attr('class', 'opacity-options-wrapper');
56257
56258         opawrap
56259             .append('h4')
56260             .text(t('background.title'));
56261
56262         var opacityList = opawrap
56263             .append('ul')
56264             .attr('class', 'opacity-options');
56265
56266         opacityList.selectAll('div.opacity')
56267             .data(opacities)
56268             .enter()
56269             .append('li')
56270             .attr('data-original-title', function(d) {
56271                 return t('background.percent_brightness', { opacity: (d * 100) });
56272             })
56273             .on('click.set-opacity', setOpacity)
56274             .html('<div class="select-box"></div>')
56275             .call(tooltip()
56276                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
56277             .append('div')
56278             .attr('class', 'opacity')
56279             .style('opacity', function(d) { return 1.25 - d; });
56280
56281
56282         /* background switcher */
56283
56284         var backgroundList = content
56285             .append('ul')
56286             .attr('class', 'layer-list')
56287             .attr('dir', 'auto');
56288
56289         var custom = backgroundList
56290             .append('li')
56291             .attr('class', 'custom_layer')
56292             .datum(rendererBackgroundSource.Custom());
56293
56294         custom
56295             .append('button')
56296             .attr('class', 'layer-browse')
56297             .call(tooltip()
56298                 .title(t('background.custom_button'))
56299                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
56300             .on('click', editCustom)
56301             .call(svgIcon('#icon-search'));
56302
56303         var label = custom
56304             .append('label');
56305
56306         label
56307             .append('input')
56308             .attr('type', 'radio')
56309             .attr('name', 'layers')
56310             .on('change', function () {
56311                 if (customTemplate) {
56312                     setCustom(customTemplate);
56313                 } else {
56314                     editCustom();
56315                 }
56316             });
56317
56318         label
56319             .append('span')
56320             .text(t('background.custom'));
56321
56322         content
56323             .append('div')
56324             .attr('class', 'imagery-faq')
56325             .append('a')
56326             .attr('target', '_blank')
56327             .attr('tabindex', -1)
56328             .call(svgIcon('#icon-out-link', 'inline'))
56329             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
56330             .append('span')
56331             .text(t('background.imagery_source_faq'));
56332
56333         var overlayList = content
56334             .append('ul')
56335             .attr('class', 'layer-list');
56336
56337         var controls = content
56338             .append('div')
56339             .attr('class', 'controls-list');
56340
56341
56342         /* minimap toggle */
56343
56344         var minimapLabel = controls
56345             .append('label')
56346             .call(tooltip()
56347                 .html(true)
56348                 .title(uiTooltipHtml(t('background.minimap.tooltip'), '/'))
56349                 .placement('top')
56350             );
56351
56352         minimapLabel
56353             .classed('minimap-toggle', true)
56354             .append('input')
56355             .attr('type', 'checkbox')
56356             .on('change', function() {
56357                 uiMapInMap.toggle();
56358                 event.preventDefault();
56359             });
56360
56361         minimapLabel
56362             .append('span')
56363             .text(t('background.minimap.description'));
56364
56365
56366         /* imagery offset controls */
56367
56368         var adjustments = content
56369             .append('div')
56370             .attr('class', 'adjustments');
56371
56372         adjustments
56373             .append('a')
56374             .text(t('background.fix_misalignment'))
56375             .attr('href', '#')
56376             .classed('hide-toggle', true)
56377             .classed('expanded', false)
56378             .on('click', function() {
56379                 if (event.button !== 0) return;
56380                 var exp = select(this).classed('expanded');
56381                 nudgeContainer.style('display', exp ? 'none' : 'block');
56382                 select(this).classed('expanded', !exp);
56383                 event.preventDefault();
56384             });
56385
56386         var nudgeContainer = adjustments
56387             .append('div')
56388             .attr('class', 'nudge-container cf')
56389             .style('display', 'none');
56390
56391         nudgeContainer
56392             .append('div')
56393             .attr('class', 'nudge-instructions')
56394             .text(t('background.offset'));
56395
56396         var nudgeRect = nudgeContainer
56397             .append('div')
56398             .attr('class', 'nudge-outer-rect')
56399             .on('mousedown', dragOffset);
56400
56401         nudgeRect
56402             .append('div')
56403             .attr('class', 'nudge-inner-rect')
56404             .append('input')
56405             .on('change', inputOffset)
56406             .on('mousedown', function() {
56407                 if (event.button !== 0) return;
56408                 event.stopPropagation();
56409             });
56410
56411         nudgeContainer
56412             .append('div')
56413             .selectAll('button')
56414             .data(directions).enter()
56415             .append('button')
56416             .attr('class', function(d) { return d[0] + ' nudge'; })
56417             .on('mousedown', function(d) {
56418                 if (event.button !== 0) return;
56419                 buttonOffset(d[1]);
56420             });
56421
56422         nudgeContainer
56423             .append('button')
56424             .attr('title', t('background.reset'))
56425             .attr('class', 'nudge-reset disabled')
56426             .on('click', resetOffset)
56427             .call(
56428                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
56429             );
56430
56431         context.map()
56432             .on('move.background-update', lodash.debounce(update, 1000));
56433
56434         context.background()
56435             .on('change.background-update', update);
56436
56437
56438         update();
56439         setOpacity(opacityDefault);
56440
56441         var keybinding = d3keybinding('background')
56442             .on(key, toggle)
56443             .on(uiCmd('⌘B'), quickSwitch)
56444             .on('F', hide)
56445             .on('H', hide);
56446
56447         select(document)
56448             .call(keybinding);
56449
56450         context.surface().on('mousedown.background-outside', hide);
56451         context.container().on('mousedown.background-outside', hide);
56452     }
56453
56454     return background;
56455 }
56456
56457 function uiContributors(context) {
56458     var debouncedUpdate = lodash.debounce(function() { update(); }, 1000),
56459         limit = 4,
56460         hidden = false,
56461         wrap = select(null);
56462
56463
56464     function update() {
56465         var users = {},
56466             entities = context.intersects(context.map().extent());
56467
56468         entities.forEach(function(entity) {
56469             if (entity && entity.user) users[entity.user] = true;
56470         });
56471
56472         var u = Object.keys(users),
56473             subset = u.slice(0, u.length > limit ? limit - 1 : limit);
56474
56475         wrap.html('')
56476             .call(svgIcon('#icon-nearby', 'pre-text light'));
56477
56478         var userList = select(document.createElement('span'));
56479
56480         userList.selectAll()
56481             .data(subset)
56482             .enter()
56483             .append('a')
56484             .attr('class', 'user-link')
56485             .attr('href', function(d) { return context.connection().userURL(d); })
56486             .attr('target', '_blank')
56487             .attr('tabindex', -1)
56488             .text(String);
56489
56490         if (u.length > limit) {
56491             var count = select(document.createElement('span'));
56492
56493             count.append('a')
56494                 .attr('target', '_blank')
56495                 .attr('tabindex', -1)
56496                 .attr('href', function() {
56497                     return context.connection().changesetsURL(context.map().center(), context.map().zoom());
56498                 })
56499                 .text(u.length - limit + 1);
56500
56501             wrap.append('span')
56502                 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
56503
56504         } else {
56505             wrap.append('span')
56506                 .html(t('contributors.list', { users: userList.html() }));
56507         }
56508
56509         if (!u.length) {
56510             hidden = true;
56511             wrap
56512                 .transition()
56513                 .style('opacity', 0);
56514
56515         } else if (hidden) {
56516             wrap
56517                 .transition()
56518                 .style('opacity', 1);
56519         }
56520     }
56521
56522
56523     return function(selection$$1) {
56524         wrap = selection$$1;
56525         update();
56526
56527         context.connection().on('loaded.contributors', debouncedUpdate);
56528         context.map().on('move.contributors', debouncedUpdate);
56529     };
56530 }
56531
56532 function uiFeatureInfo(context) {
56533     function update(selection$$1) {
56534         var features = context.features(),
56535             stats = features.stats(),
56536             count = 0,
56537             hiddenList = lodash.compact(lodash.map(features.hidden(), function(k) {
56538                 if (stats[k]) {
56539                     count += stats[k];
56540                     return String(stats[k]) + ' ' + t('feature.' + k + '.description');
56541                 }
56542             }));
56543
56544         selection$$1.html('');
56545
56546         if (hiddenList.length) {
56547             var tooltipBehavior = tooltip()
56548                     .placement('top')
56549                     .html(true)
56550                     .title(function() {
56551                         return uiTooltipHtml(hiddenList.join('<br/>'));
56552                     });
56553
56554             var warning = selection$$1.append('a')
56555                 .attr('href', '#')
56556                 .attr('tabindex', -1)
56557                 .html(t('feature_info.hidden_warning', { count: count }))
56558                 .call(tooltipBehavior)
56559                 .on('click', function() {
56560                     tooltipBehavior.hide(warning);
56561                     // open map data panel?
56562                     event.preventDefault();
56563                 });
56564         }
56565
56566         selection$$1
56567             .classed('hide', !hiddenList.length);
56568     }
56569
56570
56571     return function(selection$$1) {
56572         update(selection$$1);
56573
56574         context.features().on('change.feature_info', function() {
56575             update(selection$$1);
56576         });
56577     };
56578 }
56579
56580 function uiFullScreen(context) {
56581     var element = context.container().node(),
56582         keybinding = d3keybinding('full-screen');
56583         // button;
56584
56585
56586     function getFullScreenFn() {
56587         if (element.requestFullscreen) {
56588             return element.requestFullscreen;
56589         } else if (element.msRequestFullscreen) {
56590             return element.msRequestFullscreen;
56591         } else if (element.mozRequestFullScreen) {
56592             return element.mozRequestFullScreen;
56593         } else if (element.webkitRequestFullscreen) {
56594             return element.webkitRequestFullscreen;
56595         }
56596     }
56597
56598
56599     function getExitFullScreenFn() {
56600         if (document.exitFullscreen) {
56601             return document.exitFullscreen;
56602         } else if (document.msExitFullscreen) {
56603             return document.msExitFullscreen;
56604         } else if (document.mozCancelFullScreen) {
56605             return document.mozCancelFullScreen;
56606         } else if (document.webkitExitFullscreen) {
56607             return document.webkitExitFullscreen;
56608         }
56609     }
56610
56611
56612     function isFullScreen() {
56613         return document.fullscreenElement ||
56614             document.mozFullScreenElement ||
56615             document.webkitFullscreenElement ||
56616             document.msFullscreenElement;
56617     }
56618
56619
56620     function isSupported() {
56621         return !!getFullScreenFn();
56622     }
56623
56624
56625     function fullScreen() {
56626         event.preventDefault();
56627         if (!isFullScreen()) {
56628             // button.classed('active', true);
56629             getFullScreenFn().apply(element);
56630         } else {
56631             // button.classed('active', false);
56632             getExitFullScreenFn().apply(document);
56633         }
56634     }
56635
56636
56637     return function() { // selection) {
56638         if (!isSupported())
56639             return;
56640
56641         // button = selection.append('button')
56642         //     .attr('title', t('full_screen'))
56643         //     .attr('tabindex', -1)
56644         //     .on('click', fullScreen)
56645         //     .call(tooltip);
56646
56647         // button.append('span')
56648         //     .attr('class', 'icon full-screen');
56649
56650         keybinding
56651             .on('f11', fullScreen)
56652             .on(uiCmd('⌘⇧F'), fullScreen);
56653
56654         select(document)
56655             .call(keybinding);
56656     };
56657 }
56658
56659 function uiModal(selection$$1, blocking) {
56660     var keybinding = d3keybinding('modal');
56661     var previous = selection$$1.select('div.modal');
56662     var animate = previous.empty();
56663
56664     previous.transition()
56665         .duration(200)
56666         .style('opacity', 0)
56667         .remove();
56668
56669     var shaded = selection$$1
56670         .append('div')
56671         .attr('class', 'shaded')
56672         .style('opacity', 0);
56673
56674     shaded.close = function() {
56675         shaded
56676             .transition()
56677             .duration(200)
56678             .style('opacity',0)
56679             .remove();
56680
56681         modal
56682             .transition()
56683             .duration(200)
56684             .style('top','0px');
56685
56686         keybinding.off();
56687     };
56688
56689
56690     var modal = shaded
56691         .append('div')
56692         .attr('class', 'modal fillL col6');
56693
56694     if (!blocking) {
56695         shaded.on('click.remove-modal', function() {
56696             if (event.target === this) {
56697                 shaded.close();
56698             }
56699         });
56700
56701         modal.append('button')
56702             .attr('class', 'close')
56703             .on('click', shaded.close)
56704             .call(svgIcon('#icon-close'));
56705
56706         keybinding
56707             .on('⌫', shaded.close)
56708             .on('⎋', shaded.close);
56709
56710         select(document)
56711             .call(keybinding);
56712     }
56713
56714     modal
56715         .append('div')
56716         .attr('class', 'content');
56717
56718     if (animate) {
56719         shaded.transition().style('opacity', 1);
56720     } else {
56721         shaded.style('opacity', 1);
56722     }
56723
56724
56725     return shaded;
56726 }
56727
56728 function uiLoading(context) {
56729     var message = '',
56730         blocking = false,
56731         modalSelection;
56732
56733
56734     var loading = function(selection) {
56735         modalSelection = uiModal(selection, blocking);
56736
56737         var loadertext = modalSelection.select('.content')
56738             .classed('loading-modal', true)
56739             .append('div')
56740             .attr('class', 'modal-section fillL');
56741
56742         loadertext
56743             .append('img')
56744             .attr('class', 'loader')
56745             .attr('src', context.imagePath('loader-white.gif'));
56746
56747         loadertext
56748             .append('h3')
56749             .text(message);
56750
56751         modalSelection.select('button.close')
56752             .attr('class', 'hide');
56753
56754         return loading;
56755     };
56756
56757
56758     loading.message = function(_) {
56759         if (!arguments.length) return message;
56760         message = _;
56761         return loading;
56762     };
56763
56764
56765     loading.blocking = function(_) {
56766         if (!arguments.length) return blocking;
56767         blocking = _;
56768         return loading;
56769     };
56770
56771
56772     loading.close = function() {
56773         modalSelection.remove();
56774     };
56775
56776
56777     return loading;
56778 }
56779
56780 function uiGeolocate(context) {
56781     var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
56782         locating = uiLoading(context).message(t('geolocate.locating')).blocking(true),
56783         timeoutId;
56784
56785
56786     function click() {
56787         if (context.inIntro()) return;
56788         context.enter(modeBrowse(context));
56789         context.container().call(locating);
56790         navigator.geolocation.getCurrentPosition(success, error, geoOptions);
56791
56792         // This timeout ensures that we still call finish() even if
56793         // the user declines to share their location in Firefox
56794         timeoutId = setTimeout(finish, 10000 /* 10sec */ );
56795     }
56796
56797
56798     function success(position) {
56799         var map = context.map(),
56800             extent = geoExtent$$1([position.coords.longitude, position.coords.latitude])
56801                 .padByMeters(position.coords.accuracy);
56802
56803         map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
56804         finish();
56805     }
56806
56807
56808     function error() {
56809         finish();
56810     }
56811
56812
56813     function finish() {
56814         locating.close();  // unblock ui
56815         if (timeoutId) { clearTimeout(timeoutId); }
56816         timeoutId = undefined;
56817     }
56818
56819
56820     return function(selection) {
56821         if (!navigator.geolocation) return;
56822
56823         selection
56824             .append('button')
56825             .attr('tabindex', -1)
56826             .attr('title', t('geolocate.title'))
56827             .on('click', click)
56828             .call(svgIcon('#icon-geolocate', 'light'))
56829             .call(tooltip()
56830                 .placement((textDirection === 'rtl') ? 'right' : 'left'));
56831     };
56832 }
56833
56834 var marked = createCommonjsModule(function (module, exports) {
56835 /**
56836  * marked - a markdown parser
56837  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
56838  * https://github.com/chjj/marked
56839  */
56840
56841 (function() {
56842
56843 /**
56844  * Block-Level Grammar
56845  */
56846
56847 var block = {
56848   newline: /^\n+/,
56849   code: /^( {4}[^\n]+\n*)+/,
56850   fences: noop,
56851   hr: /^( *[-*_]){3,} *(?:\n+|$)/,
56852   heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
56853   nptable: noop,
56854   lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
56855   blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
56856   list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
56857   html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
56858   def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
56859   table: noop,
56860   paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
56861   text: /^[^\n]+/
56862 };
56863
56864 block.bullet = /(?:[*+-]|\d+\.)/;
56865 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
56866 block.item = replace(block.item, 'gm')
56867   (/bull/g, block.bullet)
56868   ();
56869
56870 block.list = replace(block.list)
56871   (/bull/g, block.bullet)
56872   ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
56873   ('def', '\\n+(?=' + block.def.source + ')')
56874   ();
56875
56876 block.blockquote = replace(block.blockquote)
56877   ('def', block.def)
56878   ();
56879
56880 block._tag = '(?!(?:'
56881   + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
56882   + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
56883   + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
56884
56885 block.html = replace(block.html)
56886   ('comment', /<!--[\s\S]*?-->/)
56887   ('closed', /<(tag)[\s\S]+?<\/\1>/)
56888   ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
56889   (/tag/g, block._tag)
56890   ();
56891
56892 block.paragraph = replace(block.paragraph)
56893   ('hr', block.hr)
56894   ('heading', block.heading)
56895   ('lheading', block.lheading)
56896   ('blockquote', block.blockquote)
56897   ('tag', '<' + block._tag)
56898   ('def', block.def)
56899   ();
56900
56901 /**
56902  * Normal Block Grammar
56903  */
56904
56905 block.normal = merge({}, block);
56906
56907 /**
56908  * GFM Block Grammar
56909  */
56910
56911 block.gfm = merge({}, block.normal, {
56912   fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
56913   paragraph: /^/,
56914   heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
56915 });
56916
56917 block.gfm.paragraph = replace(block.paragraph)
56918   ('(?!', '(?!'
56919     + block.gfm.fences.source.replace('\\1', '\\2') + '|'
56920     + block.list.source.replace('\\1', '\\3') + '|')
56921   ();
56922
56923 /**
56924  * GFM + Tables Block Grammar
56925  */
56926
56927 block.tables = merge({}, block.gfm, {
56928   nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
56929   table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
56930 });
56931
56932 /**
56933  * Block Lexer
56934  */
56935
56936 function Lexer(options) {
56937   this.tokens = [];
56938   this.tokens.links = {};
56939   this.options = options || marked.defaults;
56940   this.rules = block.normal;
56941
56942   if (this.options.gfm) {
56943     if (this.options.tables) {
56944       this.rules = block.tables;
56945     } else {
56946       this.rules = block.gfm;
56947     }
56948   }
56949 }
56950
56951 /**
56952  * Expose Block Rules
56953  */
56954
56955 Lexer.rules = block;
56956
56957 /**
56958  * Static Lex Method
56959  */
56960
56961 Lexer.lex = function(src, options) {
56962   var lexer = new Lexer(options);
56963   return lexer.lex(src);
56964 };
56965
56966 /**
56967  * Preprocessing
56968  */
56969
56970 Lexer.prototype.lex = function(src) {
56971   src = src
56972     .replace(/\r\n|\r/g, '\n')
56973     .replace(/\t/g, '    ')
56974     .replace(/\u00a0/g, ' ')
56975     .replace(/\u2424/g, '\n');
56976
56977   return this.token(src, true);
56978 };
56979
56980 /**
56981  * Lexing
56982  */
56983
56984 Lexer.prototype.token = function(src, top, bq) {
56985   var src = src.replace(/^ +$/gm, '')
56986     , next
56987     , loose
56988     , cap
56989     , bull
56990     , b
56991     , item
56992     , space
56993     , i
56994     , l;
56995
56996   while (src) {
56997     // newline
56998     if (cap = this.rules.newline.exec(src)) {
56999       src = src.substring(cap[0].length);
57000       if (cap[0].length > 1) {
57001         this.tokens.push({
57002           type: 'space'
57003         });
57004       }
57005     }
57006
57007     // code
57008     if (cap = this.rules.code.exec(src)) {
57009       src = src.substring(cap[0].length);
57010       cap = cap[0].replace(/^ {4}/gm, '');
57011       this.tokens.push({
57012         type: 'code',
57013         text: !this.options.pedantic
57014           ? cap.replace(/\n+$/, '')
57015           : cap
57016       });
57017       continue;
57018     }
57019
57020     // fences (gfm)
57021     if (cap = this.rules.fences.exec(src)) {
57022       src = src.substring(cap[0].length);
57023       this.tokens.push({
57024         type: 'code',
57025         lang: cap[2],
57026         text: cap[3] || ''
57027       });
57028       continue;
57029     }
57030
57031     // heading
57032     if (cap = this.rules.heading.exec(src)) {
57033       src = src.substring(cap[0].length);
57034       this.tokens.push({
57035         type: 'heading',
57036         depth: cap[1].length,
57037         text: cap[2]
57038       });
57039       continue;
57040     }
57041
57042     // table no leading pipe (gfm)
57043     if (top && (cap = this.rules.nptable.exec(src))) {
57044       src = src.substring(cap[0].length);
57045
57046       item = {
57047         type: 'table',
57048         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
57049         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
57050         cells: cap[3].replace(/\n$/, '').split('\n')
57051       };
57052
57053       for (i = 0; i < item.align.length; i++) {
57054         if (/^ *-+: *$/.test(item.align[i])) {
57055           item.align[i] = 'right';
57056         } else if (/^ *:-+: *$/.test(item.align[i])) {
57057           item.align[i] = 'center';
57058         } else if (/^ *:-+ *$/.test(item.align[i])) {
57059           item.align[i] = 'left';
57060         } else {
57061           item.align[i] = null;
57062         }
57063       }
57064
57065       for (i = 0; i < item.cells.length; i++) {
57066         item.cells[i] = item.cells[i].split(/ *\| */);
57067       }
57068
57069       this.tokens.push(item);
57070
57071       continue;
57072     }
57073
57074     // lheading
57075     if (cap = this.rules.lheading.exec(src)) {
57076       src = src.substring(cap[0].length);
57077       this.tokens.push({
57078         type: 'heading',
57079         depth: cap[2] === '=' ? 1 : 2,
57080         text: cap[1]
57081       });
57082       continue;
57083     }
57084
57085     // hr
57086     if (cap = this.rules.hr.exec(src)) {
57087       src = src.substring(cap[0].length);
57088       this.tokens.push({
57089         type: 'hr'
57090       });
57091       continue;
57092     }
57093
57094     // blockquote
57095     if (cap = this.rules.blockquote.exec(src)) {
57096       src = src.substring(cap[0].length);
57097
57098       this.tokens.push({
57099         type: 'blockquote_start'
57100       });
57101
57102       cap = cap[0].replace(/^ *> ?/gm, '');
57103
57104       // Pass `top` to keep the current
57105       // "toplevel" state. This is exactly
57106       // how markdown.pl works.
57107       this.token(cap, top, true);
57108
57109       this.tokens.push({
57110         type: 'blockquote_end'
57111       });
57112
57113       continue;
57114     }
57115
57116     // list
57117     if (cap = this.rules.list.exec(src)) {
57118       src = src.substring(cap[0].length);
57119       bull = cap[2];
57120
57121       this.tokens.push({
57122         type: 'list_start',
57123         ordered: bull.length > 1
57124       });
57125
57126       // Get each top-level item.
57127       cap = cap[0].match(this.rules.item);
57128
57129       next = false;
57130       l = cap.length;
57131       i = 0;
57132
57133       for (; i < l; i++) {
57134         item = cap[i];
57135
57136         // Remove the list item's bullet
57137         // so it is seen as the next token.
57138         space = item.length;
57139         item = item.replace(/^ *([*+-]|\d+\.) +/, '');
57140
57141         // Outdent whatever the
57142         // list item contains. Hacky.
57143         if (~item.indexOf('\n ')) {
57144           space -= item.length;
57145           item = !this.options.pedantic
57146             ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
57147             : item.replace(/^ {1,4}/gm, '');
57148         }
57149
57150         // Determine whether the next list item belongs here.
57151         // Backpedal if it does not belong in this list.
57152         if (this.options.smartLists && i !== l - 1) {
57153           b = block.bullet.exec(cap[i + 1])[0];
57154           if (bull !== b && !(bull.length > 1 && b.length > 1)) {
57155             src = cap.slice(i + 1).join('\n') + src;
57156             i = l - 1;
57157           }
57158         }
57159
57160         // Determine whether item is loose or not.
57161         // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
57162         // for discount behavior.
57163         loose = next || /\n\n(?!\s*$)/.test(item);
57164         if (i !== l - 1) {
57165           next = item.charAt(item.length - 1) === '\n';
57166           if (!loose) loose = next;
57167         }
57168
57169         this.tokens.push({
57170           type: loose
57171             ? 'loose_item_start'
57172             : 'list_item_start'
57173         });
57174
57175         // Recurse.
57176         this.token(item, false, bq);
57177
57178         this.tokens.push({
57179           type: 'list_item_end'
57180         });
57181       }
57182
57183       this.tokens.push({
57184         type: 'list_end'
57185       });
57186
57187       continue;
57188     }
57189
57190     // html
57191     if (cap = this.rules.html.exec(src)) {
57192       src = src.substring(cap[0].length);
57193       this.tokens.push({
57194         type: this.options.sanitize
57195           ? 'paragraph'
57196           : 'html',
57197         pre: !this.options.sanitizer
57198           && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
57199         text: cap[0]
57200       });
57201       continue;
57202     }
57203
57204     // def
57205     if ((!bq && top) && (cap = this.rules.def.exec(src))) {
57206       src = src.substring(cap[0].length);
57207       this.tokens.links[cap[1].toLowerCase()] = {
57208         href: cap[2],
57209         title: cap[3]
57210       };
57211       continue;
57212     }
57213
57214     // table (gfm)
57215     if (top && (cap = this.rules.table.exec(src))) {
57216       src = src.substring(cap[0].length);
57217
57218       item = {
57219         type: 'table',
57220         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
57221         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
57222         cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
57223       };
57224
57225       for (i = 0; i < item.align.length; i++) {
57226         if (/^ *-+: *$/.test(item.align[i])) {
57227           item.align[i] = 'right';
57228         } else if (/^ *:-+: *$/.test(item.align[i])) {
57229           item.align[i] = 'center';
57230         } else if (/^ *:-+ *$/.test(item.align[i])) {
57231           item.align[i] = 'left';
57232         } else {
57233           item.align[i] = null;
57234         }
57235       }
57236
57237       for (i = 0; i < item.cells.length; i++) {
57238         item.cells[i] = item.cells[i]
57239           .replace(/^ *\| *| *\| *$/g, '')
57240           .split(/ *\| */);
57241       }
57242
57243       this.tokens.push(item);
57244
57245       continue;
57246     }
57247
57248     // top-level paragraph
57249     if (top && (cap = this.rules.paragraph.exec(src))) {
57250       src = src.substring(cap[0].length);
57251       this.tokens.push({
57252         type: 'paragraph',
57253         text: cap[1].charAt(cap[1].length - 1) === '\n'
57254           ? cap[1].slice(0, -1)
57255           : cap[1]
57256       });
57257       continue;
57258     }
57259
57260     // text
57261     if (cap = this.rules.text.exec(src)) {
57262       // Top-level should never reach here.
57263       src = src.substring(cap[0].length);
57264       this.tokens.push({
57265         type: 'text',
57266         text: cap[0]
57267       });
57268       continue;
57269     }
57270
57271     if (src) {
57272       throw new
57273         Error('Infinite loop on byte: ' + src.charCodeAt(0));
57274     }
57275   }
57276
57277   return this.tokens;
57278 };
57279
57280 /**
57281  * Inline-Level Grammar
57282  */
57283
57284 var inline = {
57285   escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
57286   autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
57287   url: noop,
57288   tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
57289   link: /^!?\[(inside)\]\(href\)/,
57290   reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
57291   nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
57292   strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
57293   em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
57294   code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
57295   br: /^ {2,}\n(?!\s*$)/,
57296   del: noop,
57297   text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
57298 };
57299
57300 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
57301 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
57302
57303 inline.link = replace(inline.link)
57304   ('inside', inline._inside)
57305   ('href', inline._href)
57306   ();
57307
57308 inline.reflink = replace(inline.reflink)
57309   ('inside', inline._inside)
57310   ();
57311
57312 /**
57313  * Normal Inline Grammar
57314  */
57315
57316 inline.normal = merge({}, inline);
57317
57318 /**
57319  * Pedantic Inline Grammar
57320  */
57321
57322 inline.pedantic = merge({}, inline.normal, {
57323   strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
57324   em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
57325 });
57326
57327 /**
57328  * GFM Inline Grammar
57329  */
57330
57331 inline.gfm = merge({}, inline.normal, {
57332   escape: replace(inline.escape)('])', '~|])')(),
57333   url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
57334   del: /^~~(?=\S)([\s\S]*?\S)~~/,
57335   text: replace(inline.text)
57336     (']|', '~]|')
57337     ('|', '|https?://|')
57338     ()
57339 });
57340
57341 /**
57342  * GFM + Line Breaks Inline Grammar
57343  */
57344
57345 inline.breaks = merge({}, inline.gfm, {
57346   br: replace(inline.br)('{2,}', '*')(),
57347   text: replace(inline.gfm.text)('{2,}', '*')()
57348 });
57349
57350 /**
57351  * Inline Lexer & Compiler
57352  */
57353
57354 function InlineLexer(links, options) {
57355   this.options = options || marked.defaults;
57356   this.links = links;
57357   this.rules = inline.normal;
57358   this.renderer = this.options.renderer || new Renderer;
57359   this.renderer.options = this.options;
57360
57361   if (!this.links) {
57362     throw new
57363       Error('Tokens array requires a `links` property.');
57364   }
57365
57366   if (this.options.gfm) {
57367     if (this.options.breaks) {
57368       this.rules = inline.breaks;
57369     } else {
57370       this.rules = inline.gfm;
57371     }
57372   } else if (this.options.pedantic) {
57373     this.rules = inline.pedantic;
57374   }
57375 }
57376
57377 /**
57378  * Expose Inline Rules
57379  */
57380
57381 InlineLexer.rules = inline;
57382
57383 /**
57384  * Static Lexing/Compiling Method
57385  */
57386
57387 InlineLexer.output = function(src, links, options) {
57388   var inline = new InlineLexer(links, options);
57389   return inline.output(src);
57390 };
57391
57392 /**
57393  * Lexing/Compiling
57394  */
57395
57396 InlineLexer.prototype.output = function(src) {
57397   var out = ''
57398     , link
57399     , text
57400     , href
57401     , cap;
57402
57403   while (src) {
57404     // escape
57405     if (cap = this.rules.escape.exec(src)) {
57406       src = src.substring(cap[0].length);
57407       out += cap[1];
57408       continue;
57409     }
57410
57411     // autolink
57412     if (cap = this.rules.autolink.exec(src)) {
57413       src = src.substring(cap[0].length);
57414       if (cap[2] === '@') {
57415         text = cap[1].charAt(6) === ':'
57416           ? this.mangle(cap[1].substring(7))
57417           : this.mangle(cap[1]);
57418         href = this.mangle('mailto:') + text;
57419       } else {
57420         text = escape(cap[1]);
57421         href = text;
57422       }
57423       out += this.renderer.link(href, null, text);
57424       continue;
57425     }
57426
57427     // url (gfm)
57428     if (!this.inLink && (cap = this.rules.url.exec(src))) {
57429       src = src.substring(cap[0].length);
57430       text = escape(cap[1]);
57431       href = text;
57432       out += this.renderer.link(href, null, text);
57433       continue;
57434     }
57435
57436     // tag
57437     if (cap = this.rules.tag.exec(src)) {
57438       if (!this.inLink && /^<a /i.test(cap[0])) {
57439         this.inLink = true;
57440       } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
57441         this.inLink = false;
57442       }
57443       src = src.substring(cap[0].length);
57444       out += this.options.sanitize
57445         ? this.options.sanitizer
57446           ? this.options.sanitizer(cap[0])
57447           : escape(cap[0])
57448         : cap[0];
57449       continue;
57450     }
57451
57452     // link
57453     if (cap = this.rules.link.exec(src)) {
57454       src = src.substring(cap[0].length);
57455       this.inLink = true;
57456       out += this.outputLink(cap, {
57457         href: cap[2],
57458         title: cap[3]
57459       });
57460       this.inLink = false;
57461       continue;
57462     }
57463
57464     // reflink, nolink
57465     if ((cap = this.rules.reflink.exec(src))
57466         || (cap = this.rules.nolink.exec(src))) {
57467       src = src.substring(cap[0].length);
57468       link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
57469       link = this.links[link.toLowerCase()];
57470       if (!link || !link.href) {
57471         out += cap[0].charAt(0);
57472         src = cap[0].substring(1) + src;
57473         continue;
57474       }
57475       this.inLink = true;
57476       out += this.outputLink(cap, link);
57477       this.inLink = false;
57478       continue;
57479     }
57480
57481     // strong
57482     if (cap = this.rules.strong.exec(src)) {
57483       src = src.substring(cap[0].length);
57484       out += this.renderer.strong(this.output(cap[2] || cap[1]));
57485       continue;
57486     }
57487
57488     // em
57489     if (cap = this.rules.em.exec(src)) {
57490       src = src.substring(cap[0].length);
57491       out += this.renderer.em(this.output(cap[2] || cap[1]));
57492       continue;
57493     }
57494
57495     // code
57496     if (cap = this.rules.code.exec(src)) {
57497       src = src.substring(cap[0].length);
57498       out += this.renderer.codespan(escape(cap[2], true));
57499       continue;
57500     }
57501
57502     // br
57503     if (cap = this.rules.br.exec(src)) {
57504       src = src.substring(cap[0].length);
57505       out += this.renderer.br();
57506       continue;
57507     }
57508
57509     // del (gfm)
57510     if (cap = this.rules.del.exec(src)) {
57511       src = src.substring(cap[0].length);
57512       out += this.renderer.del(this.output(cap[1]));
57513       continue;
57514     }
57515
57516     // text
57517     if (cap = this.rules.text.exec(src)) {
57518       src = src.substring(cap[0].length);
57519       out += this.renderer.text(escape(this.smartypants(cap[0])));
57520       continue;
57521     }
57522
57523     if (src) {
57524       throw new
57525         Error('Infinite loop on byte: ' + src.charCodeAt(0));
57526     }
57527   }
57528
57529   return out;
57530 };
57531
57532 /**
57533  * Compile Link
57534  */
57535
57536 InlineLexer.prototype.outputLink = function(cap, link) {
57537   var href = escape(link.href)
57538     , title = link.title ? escape(link.title) : null;
57539
57540   return cap[0].charAt(0) !== '!'
57541     ? this.renderer.link(href, title, this.output(cap[1]))
57542     : this.renderer.image(href, title, escape(cap[1]));
57543 };
57544
57545 /**
57546  * Smartypants Transformations
57547  */
57548
57549 InlineLexer.prototype.smartypants = function(text) {
57550   if (!this.options.smartypants) return text;
57551   return text
57552     // em-dashes
57553     .replace(/---/g, '\u2014')
57554     // en-dashes
57555     .replace(/--/g, '\u2013')
57556     // opening singles
57557     .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
57558     // closing singles & apostrophes
57559     .replace(/'/g, '\u2019')
57560     // opening doubles
57561     .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
57562     // closing doubles
57563     .replace(/"/g, '\u201d')
57564     // ellipses
57565     .replace(/\.{3}/g, '\u2026');
57566 };
57567
57568 /**
57569  * Mangle Links
57570  */
57571
57572 InlineLexer.prototype.mangle = function(text) {
57573   if (!this.options.mangle) return text;
57574   var out = ''
57575     , l = text.length
57576     , i = 0
57577     , ch;
57578
57579   for (; i < l; i++) {
57580     ch = text.charCodeAt(i);
57581     if (Math.random() > 0.5) {
57582       ch = 'x' + ch.toString(16);
57583     }
57584     out += '&#' + ch + ';';
57585   }
57586
57587   return out;
57588 };
57589
57590 /**
57591  * Renderer
57592  */
57593
57594 function Renderer(options) {
57595   this.options = options || {};
57596 }
57597
57598 Renderer.prototype.code = function(code, lang, escaped) {
57599   if (this.options.highlight) {
57600     var out = this.options.highlight(code, lang);
57601     if (out != null && out !== code) {
57602       escaped = true;
57603       code = out;
57604     }
57605   }
57606
57607   if (!lang) {
57608     return '<pre><code>'
57609       + (escaped ? code : escape(code, true))
57610       + '\n</code></pre>';
57611   }
57612
57613   return '<pre><code class="'
57614     + this.options.langPrefix
57615     + escape(lang, true)
57616     + '">'
57617     + (escaped ? code : escape(code, true))
57618     + '\n</code></pre>\n';
57619 };
57620
57621 Renderer.prototype.blockquote = function(quote) {
57622   return '<blockquote>\n' + quote + '</blockquote>\n';
57623 };
57624
57625 Renderer.prototype.html = function(html) {
57626   return html;
57627 };
57628
57629 Renderer.prototype.heading = function(text, level, raw) {
57630   return '<h'
57631     + level
57632     + ' id="'
57633     + this.options.headerPrefix
57634     + raw.toLowerCase().replace(/[^\w]+/g, '-')
57635     + '">'
57636     + text
57637     + '</h'
57638     + level
57639     + '>\n';
57640 };
57641
57642 Renderer.prototype.hr = function() {
57643   return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
57644 };
57645
57646 Renderer.prototype.list = function(body, ordered) {
57647   var type = ordered ? 'ol' : 'ul';
57648   return '<' + type + '>\n' + body + '</' + type + '>\n';
57649 };
57650
57651 Renderer.prototype.listitem = function(text) {
57652   return '<li>' + text + '</li>\n';
57653 };
57654
57655 Renderer.prototype.paragraph = function(text) {
57656   return '<p>' + text + '</p>\n';
57657 };
57658
57659 Renderer.prototype.table = function(header, body) {
57660   return '<table>\n'
57661     + '<thead>\n'
57662     + header
57663     + '</thead>\n'
57664     + '<tbody>\n'
57665     + body
57666     + '</tbody>\n'
57667     + '</table>\n';
57668 };
57669
57670 Renderer.prototype.tablerow = function(content) {
57671   return '<tr>\n' + content + '</tr>\n';
57672 };
57673
57674 Renderer.prototype.tablecell = function(content, flags) {
57675   var type = flags.header ? 'th' : 'td';
57676   var tag = flags.align
57677     ? '<' + type + ' style="text-align:' + flags.align + '">'
57678     : '<' + type + '>';
57679   return tag + content + '</' + type + '>\n';
57680 };
57681
57682 // span level renderer
57683 Renderer.prototype.strong = function(text) {
57684   return '<strong>' + text + '</strong>';
57685 };
57686
57687 Renderer.prototype.em = function(text) {
57688   return '<em>' + text + '</em>';
57689 };
57690
57691 Renderer.prototype.codespan = function(text) {
57692   return '<code>' + text + '</code>';
57693 };
57694
57695 Renderer.prototype.br = function() {
57696   return this.options.xhtml ? '<br/>' : '<br>';
57697 };
57698
57699 Renderer.prototype.del = function(text) {
57700   return '<del>' + text + '</del>';
57701 };
57702
57703 Renderer.prototype.link = function(href, title, text) {
57704   if (this.options.sanitize) {
57705     try {
57706       var prot = decodeURIComponent(unescape(href))
57707         .replace(/[^\w:]/g, '')
57708         .toLowerCase();
57709     } catch (e) {
57710       return '';
57711     }
57712     if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
57713       return '';
57714     }
57715   }
57716   var out = '<a href="' + href + '"';
57717   if (title) {
57718     out += ' title="' + title + '"';
57719   }
57720   out += '>' + text + '</a>';
57721   return out;
57722 };
57723
57724 Renderer.prototype.image = function(href, title, text) {
57725   var out = '<img src="' + href + '" alt="' + text + '"';
57726   if (title) {
57727     out += ' title="' + title + '"';
57728   }
57729   out += this.options.xhtml ? '/>' : '>';
57730   return out;
57731 };
57732
57733 Renderer.prototype.text = function(text) {
57734   return text;
57735 };
57736
57737 /**
57738  * Parsing & Compiling
57739  */
57740
57741 function Parser(options) {
57742   this.tokens = [];
57743   this.token = null;
57744   this.options = options || marked.defaults;
57745   this.options.renderer = this.options.renderer || new Renderer;
57746   this.renderer = this.options.renderer;
57747   this.renderer.options = this.options;
57748 }
57749
57750 /**
57751  * Static Parse Method
57752  */
57753
57754 Parser.parse = function(src, options, renderer) {
57755   var parser = new Parser(options, renderer);
57756   return parser.parse(src);
57757 };
57758
57759 /**
57760  * Parse Loop
57761  */
57762
57763 Parser.prototype.parse = function(src) {
57764   this.inline = new InlineLexer(src.links, this.options, this.renderer);
57765   this.tokens = src.reverse();
57766
57767   var out = '';
57768   while (this.next()) {
57769     out += this.tok();
57770   }
57771
57772   return out;
57773 };
57774
57775 /**
57776  * Next Token
57777  */
57778
57779 Parser.prototype.next = function() {
57780   return this.token = this.tokens.pop();
57781 };
57782
57783 /**
57784  * Preview Next Token
57785  */
57786
57787 Parser.prototype.peek = function() {
57788   return this.tokens[this.tokens.length - 1] || 0;
57789 };
57790
57791 /**
57792  * Parse Text Tokens
57793  */
57794
57795 Parser.prototype.parseText = function() {
57796   var body = this.token.text;
57797
57798   while (this.peek().type === 'text') {
57799     body += '\n' + this.next().text;
57800   }
57801
57802   return this.inline.output(body);
57803 };
57804
57805 /**
57806  * Parse Current Token
57807  */
57808
57809 Parser.prototype.tok = function() {
57810   switch (this.token.type) {
57811     case 'space': {
57812       return '';
57813     }
57814     case 'hr': {
57815       return this.renderer.hr();
57816     }
57817     case 'heading': {
57818       return this.renderer.heading(
57819         this.inline.output(this.token.text),
57820         this.token.depth,
57821         this.token.text);
57822     }
57823     case 'code': {
57824       return this.renderer.code(this.token.text,
57825         this.token.lang,
57826         this.token.escaped);
57827     }
57828     case 'table': {
57829       var header = ''
57830         , body = ''
57831         , i
57832         , row
57833         , cell
57834         , flags
57835         , j;
57836
57837       // header
57838       cell = '';
57839       for (i = 0; i < this.token.header.length; i++) {
57840         flags = { header: true, align: this.token.align[i] };
57841         cell += this.renderer.tablecell(
57842           this.inline.output(this.token.header[i]),
57843           { header: true, align: this.token.align[i] }
57844         );
57845       }
57846       header += this.renderer.tablerow(cell);
57847
57848       for (i = 0; i < this.token.cells.length; i++) {
57849         row = this.token.cells[i];
57850
57851         cell = '';
57852         for (j = 0; j < row.length; j++) {
57853           cell += this.renderer.tablecell(
57854             this.inline.output(row[j]),
57855             { header: false, align: this.token.align[j] }
57856           );
57857         }
57858
57859         body += this.renderer.tablerow(cell);
57860       }
57861       return this.renderer.table(header, body);
57862     }
57863     case 'blockquote_start': {
57864       var body = '';
57865
57866       while (this.next().type !== 'blockquote_end') {
57867         body += this.tok();
57868       }
57869
57870       return this.renderer.blockquote(body);
57871     }
57872     case 'list_start': {
57873       var body = ''
57874         , ordered = this.token.ordered;
57875
57876       while (this.next().type !== 'list_end') {
57877         body += this.tok();
57878       }
57879
57880       return this.renderer.list(body, ordered);
57881     }
57882     case 'list_item_start': {
57883       var body = '';
57884
57885       while (this.next().type !== 'list_item_end') {
57886         body += this.token.type === 'text'
57887           ? this.parseText()
57888           : this.tok();
57889       }
57890
57891       return this.renderer.listitem(body);
57892     }
57893     case 'loose_item_start': {
57894       var body = '';
57895
57896       while (this.next().type !== 'list_item_end') {
57897         body += this.tok();
57898       }
57899
57900       return this.renderer.listitem(body);
57901     }
57902     case 'html': {
57903       var html = !this.token.pre && !this.options.pedantic
57904         ? this.inline.output(this.token.text)
57905         : this.token.text;
57906       return this.renderer.html(html);
57907     }
57908     case 'paragraph': {
57909       return this.renderer.paragraph(this.inline.output(this.token.text));
57910     }
57911     case 'text': {
57912       return this.renderer.paragraph(this.parseText());
57913     }
57914   }
57915 };
57916
57917 /**
57918  * Helpers
57919  */
57920
57921 function escape(html, encode) {
57922   return html
57923     .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
57924     .replace(/</g, '&lt;')
57925     .replace(/>/g, '&gt;')
57926     .replace(/"/g, '&quot;')
57927     .replace(/'/g, '&#39;');
57928 }
57929
57930 function unescape(html) {
57931         // explicitly match decimal, hex, and named HTML entities 
57932   return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
57933     n = n.toLowerCase();
57934     if (n === 'colon') return ':';
57935     if (n.charAt(0) === '#') {
57936       return n.charAt(1) === 'x'
57937         ? String.fromCharCode(parseInt(n.substring(2), 16))
57938         : String.fromCharCode(+n.substring(1));
57939     }
57940     return '';
57941   });
57942 }
57943
57944 function replace(regex, opt) {
57945   regex = regex.source;
57946   opt = opt || '';
57947   return function self(name, val) {
57948     if (!name) return new RegExp(regex, opt);
57949     val = val.source || val;
57950     val = val.replace(/(^|[^\[])\^/g, '$1');
57951     regex = regex.replace(name, val);
57952     return self;
57953   };
57954 }
57955
57956 function noop() {}
57957 noop.exec = noop;
57958
57959 function merge(obj) {
57960   var i = 1
57961     , target
57962     , key;
57963
57964   for (; i < arguments.length; i++) {
57965     target = arguments[i];
57966     for (key in target) {
57967       if (Object.prototype.hasOwnProperty.call(target, key)) {
57968         obj[key] = target[key];
57969       }
57970     }
57971   }
57972
57973   return obj;
57974 }
57975
57976
57977 /**
57978  * Marked
57979  */
57980
57981 function marked(src, opt, callback) {
57982   if (callback || typeof opt === 'function') {
57983     if (!callback) {
57984       callback = opt;
57985       opt = null;
57986     }
57987
57988     opt = merge({}, marked.defaults, opt || {});
57989
57990     var highlight = opt.highlight
57991       , tokens
57992       , pending
57993       , i = 0;
57994
57995     try {
57996       tokens = Lexer.lex(src, opt);
57997     } catch (e) {
57998       return callback(e);
57999     }
58000
58001     pending = tokens.length;
58002
58003     var done = function(err) {
58004       if (err) {
58005         opt.highlight = highlight;
58006         return callback(err);
58007       }
58008
58009       var out;
58010
58011       try {
58012         out = Parser.parse(tokens, opt);
58013       } catch (e) {
58014         err = e;
58015       }
58016
58017       opt.highlight = highlight;
58018
58019       return err
58020         ? callback(err)
58021         : callback(null, out);
58022     };
58023
58024     if (!highlight || highlight.length < 3) {
58025       return done();
58026     }
58027
58028     delete opt.highlight;
58029
58030     if (!pending) return done();
58031
58032     for (; i < tokens.length; i++) {
58033       (function(token) {
58034         if (token.type !== 'code') {
58035           return --pending || done();
58036         }
58037         return highlight(token.text, token.lang, function(err, code) {
58038           if (err) return done(err);
58039           if (code == null || code === token.text) {
58040             return --pending || done();
58041           }
58042           token.text = code;
58043           token.escaped = true;
58044           --pending || done();
58045         });
58046       })(tokens[i]);
58047     }
58048
58049     return;
58050   }
58051   try {
58052     if (opt) opt = merge({}, marked.defaults, opt);
58053     return Parser.parse(Lexer.lex(src, opt), opt);
58054   } catch (e) {
58055     e.message += '\nPlease report this to https://github.com/chjj/marked.';
58056     if ((opt || marked.defaults).silent) {
58057       return '<p>An error occured:</p><pre>'
58058         + escape(e.message + '', true)
58059         + '</pre>';
58060     }
58061     throw e;
58062   }
58063 }
58064
58065 /**
58066  * Options
58067  */
58068
58069 marked.options =
58070 marked.setOptions = function(opt) {
58071   merge(marked.defaults, opt);
58072   return marked;
58073 };
58074
58075 marked.defaults = {
58076   gfm: true,
58077   tables: true,
58078   breaks: false,
58079   pedantic: false,
58080   sanitize: false,
58081   sanitizer: null,
58082   mangle: true,
58083   smartLists: false,
58084   silent: false,
58085   highlight: null,
58086   langPrefix: 'lang-',
58087   smartypants: false,
58088   headerPrefix: '',
58089   renderer: new Renderer,
58090   xhtml: false
58091 };
58092
58093 /**
58094  * Expose
58095  */
58096
58097 marked.Parser = Parser;
58098 marked.parser = Parser.parse;
58099
58100 marked.Renderer = Renderer;
58101
58102 marked.Lexer = Lexer;
58103 marked.lexer = Lexer.lex;
58104
58105 marked.InlineLexer = InlineLexer;
58106 marked.inlineLexer = InlineLexer.output;
58107
58108 marked.parse = marked;
58109
58110 {
58111   module.exports = marked;
58112 }
58113
58114 }).call(function() {
58115   return this || (typeof window !== 'undefined' ? window : commonjsGlobal);
58116 }());
58117 });
58118
58119 function pointBox(loc, context) {
58120     var rect = context.surfaceRect();
58121     var point = context.curtainProjection(loc);
58122     return {
58123         left: point[0] + rect.left - 40,
58124         top: point[1] + rect.top - 60,
58125         width: 80,
58126         height: 90
58127     };
58128 }
58129
58130
58131 function pad$1(locOrBox, padding, context) {
58132     var box;
58133     if (locOrBox instanceof Array) {
58134         var rect = context.surfaceRect();
58135         var point = context.curtainProjection(locOrBox);
58136         box = {
58137             left: point[0] + rect.left,
58138             top: point[1] + rect.top
58139         };
58140     } else {
58141         box = locOrBox;
58142     }
58143
58144     return {
58145         left: box.left - padding,
58146         top: box.top - padding,
58147         width: (box.width || 0) + 2 * padding,
58148         height: (box.width || 0) + 2 * padding
58149     };
58150 }
58151
58152
58153 function icon(name, svgklass) {
58154     return '<svg class="icon ' + (svgklass || '') + '">' +
58155          '<use xlink:href="' + name + '"></use></svg>';
58156 }
58157
58158
58159 function slugify(text$$1) {
58160     return text$$1.toString().toLowerCase()
58161         .replace(/\s+/g, '-')           // Replace spaces with -
58162         .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
58163         .replace(/\-\-+/g, '-')         // Replace multiple - with single -
58164         .replace(/^-+/, '')             // Trim - from start of text
58165         .replace(/-+$/, '');            // Trim - from end of text
58166 }
58167
58168
58169 // console warning for missing walkthrough names
58170 var missingStrings = {};
58171 function checkKey(key, text$$1) {
58172     if (t(key, { default: undefined}) === undefined) {
58173         if (missingStrings.hasOwnProperty(key)) return;  // warn once
58174         missingStrings[key] = text$$1;
58175         var missing = key + ': ' + text$$1;
58176         if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
58177     }
58178 }
58179
58180
58181 function localize(obj) {
58182     var key;
58183
58184     // Assign name if entity has one..
58185     var name = obj.tags && obj.tags.name;
58186     if (name) {
58187         key = 'intro.graph.name.' + slugify(name);
58188         obj.tags.name = t(key, { default: name });
58189         checkKey(key, name);
58190     }
58191
58192     // Assign street name if entity has one..
58193     var street = obj.tags && obj.tags['addr:street'];
58194     if (street) {
58195         key = 'intro.graph.name.' + slugify(street);
58196         obj.tags['addr:street'] = t(key, { default: street });
58197         checkKey(key, street);
58198
58199         // Add address details common across walkthrough..
58200         var addrTags = [
58201             'block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood',
58202             'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'
58203         ];
58204         addrTags.forEach(function(k) {
58205             var key = 'intro.graph.' + k,
58206                 tag = 'addr:' + k,
58207                 val = obj.tags && obj.tags[tag],
58208                 str = t(key, { default: val });
58209
58210             if (str) {
58211                 if (str.match(/^<.*>$/) !== null) {
58212                     delete obj.tags[tag];
58213                 } else {
58214                     obj.tags[tag] = str;
58215                 }
58216             }
58217         });
58218     }
58219
58220     return obj;
58221 }
58222
58223
58224 // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
58225 function isMostlySquare(points) {
58226     // note: uses 15 here instead of the 12 from actionOrthogonalize because
58227     // actionOrthogonalize can actually straighten some larger angles as it iterates
58228     var threshold = 15, // degrees within right or straight
58229         lowerBound = Math.cos((90 - threshold) * Math.PI / 180),  // near right
58230         upperBound = Math.cos(threshold * Math.PI / 180),         // near straight
58231         mag;
58232
58233     for (var i = 0; i < points.length; i++) {
58234         mag = Math.abs(normalizedDotProduct(i, points));
58235         if (mag > lowerBound && mag < upperBound) {
58236             return false;
58237         }
58238     }
58239
58240     return true;
58241
58242
58243     function normalizedDotProduct(i, points) {
58244         var a = points[(i - 1 + points.length) % points.length],
58245             b = points[i],
58246             c = points[(i + 1) % points.length],
58247             p = subtractPoints(a, b),
58248             q = subtractPoints(c, b);
58249
58250         p = normalizePoint(p);
58251         q = normalizePoint(q);
58252
58253         return p[0] * q[0] + p[1] * q[1];
58254
58255
58256         function subtractPoints(a, b) {
58257             return [a[0] - b[0], a[1] - b[1]];
58258         }
58259
58260         function normalizePoint(point) {
58261             var vector = [0, 0];
58262             var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
58263             if (length !== 0) {
58264                 vector[0] = point[0] / length;
58265                 vector[1] = point[1] / length;
58266             }
58267             return vector;
58268         }
58269     }
58270 }
58271
58272
58273 function selectMenuItem(operation) {
58274     var selector$$1 = '.edit-menu .edit-menu-item-' + operation +
58275         ', .radial-menu .radial-menu-item-' + operation;
58276     return select(selector$$1);
58277 }
58278
58279
58280 function transitionTime(point1, point2) {
58281     var distance = geoSphericalDistance(point1, point2);
58282     if (distance === 0)
58283         return 0;
58284     else if (distance < 80)
58285         return 500;
58286     else
58287         return 1000;
58288 }
58289
58290 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"}}};
58291
58292 // toggles the visibility of ui elements, using a combination of the
58293 // hide class, which sets display=none, and a d3 transition for opacity.
58294 // this will cause blinking when called repeatedly, so check that the
58295 // value actually changes between calls.
58296 function uiToggle(show, callback) {
58297     return function(selection$$1) {
58298         selection$$1
58299             .style('opacity', show ? 0 : 1)
58300             .classed('hide', false)
58301             .transition()
58302             .style('opacity', show ? 1 : 0)
58303             .on('end', function() {
58304                 select(this)
58305                     .classed('hide', !show)
58306                     .style('opacity', null);
58307                 if (callback) callback.apply(this);
58308             });
58309     };
58310 }
58311
58312 // Tooltips and svg mask used to highlight certain features
58313 function uiCurtain() {
58314
58315     var surface = select(null),
58316         tooltip = select(null),
58317         darkness = select(null);
58318
58319     function curtain(selection$$1) {
58320         surface = selection$$1
58321             .append('svg')
58322             .attr('id', 'curtain')
58323             .style('z-index', 1000)
58324             .style('pointer-events', 'none')
58325             .style('position', 'absolute')
58326             .style('top', 0)
58327             .style('left', 0);
58328
58329         darkness = surface.append('path')
58330             .attr('x', 0)
58331             .attr('y', 0)
58332             .attr('class', 'curtain-darkness');
58333
58334         select(window).on('resize.curtain', resize);
58335
58336         tooltip = selection$$1.append('div')
58337             .attr('class', 'tooltip')
58338             .style('z-index', 1002);
58339
58340         tooltip
58341             .append('div')
58342             .attr('class', 'tooltip-arrow');
58343
58344         tooltip
58345             .append('div')
58346             .attr('class', 'tooltip-inner');
58347
58348         resize();
58349
58350
58351         function resize() {
58352             surface
58353                 .attr('width', window.innerWidth)
58354                 .attr('height', window.innerHeight);
58355             curtain.cut(darkness.datum());
58356         }
58357     }
58358
58359
58360     /**
58361      * Reveal cuts the curtain to highlight the given box,
58362      * and shows a tooltip with instructions next to the box.
58363      *
58364      * @param  {String|ClientRect} [box]   box used to cut the curtain
58365      * @param  {String}    [text]          text for a tooltip
58366      * @param  {Object}    [options]
58367      * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
58368      * @param  {integer}   [options.duration]        transition time in milliseconds
58369      * @param  {string}    [options.buttonText]      if set, create a button with this text label
58370      * @param  {function}  [options.buttonCallback]  if set, the callback for the button
58371      * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
58372      */
58373     curtain.reveal = function(box, text$$1, options) {
58374         if (typeof box === 'string') {
58375             box = select(box).node();
58376         }
58377         if (box && box.getBoundingClientRect) {
58378             box = copyBox(box.getBoundingClientRect());
58379         }
58380
58381         options = options || {};
58382
58383         var tooltipBox;
58384         if (options.tooltipBox) {
58385             tooltipBox = options.tooltipBox;
58386             if (typeof tooltipBox === 'string') {
58387                 tooltipBox = select(tooltipBox).node();
58388             }
58389             if (tooltipBox && tooltipBox.getBoundingClientRect) {
58390                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
58391             }
58392         } else {
58393             tooltipBox = box;
58394         }
58395
58396         if (tooltipBox && text$$1) {
58397             // pseudo markdown bold text for the instruction section..
58398             var parts = text$$1.split('**');
58399             var html$$1 = parts[0] ? '<span>' + parts[0] + '</span>' : '';
58400             if (parts[1]) {
58401                 html$$1 += '<span class="instruction">' + parts[1] + '</span>';
58402             }
58403
58404             html$$1 = html$$1.replace(/\*(.*?)\*/g, '<em>$1</em>');   // emphasis
58405             html$$1 = html$$1.replace(/\{br\}/g, '<br/><br/>');       // linebreak
58406
58407             if (options.buttonText && options.buttonCallback) {
58408                 html$$1 += '<div class="button-section">' +
58409                     '<button href="#" class="button action col8">' + options.buttonText + '</button></div>';
58410             }
58411
58412             var classes = 'curtain-tooltip tooltip in ' + (options.tooltipClass || '');
58413             tooltip
58414                 .classed(classes, true)
58415                 .selectAll('.tooltip-inner')
58416                 .html(html$$1);
58417
58418             if (options.buttonText && options.buttonCallback) {
58419                 var button = tooltip.selectAll('.button-section .button.action');
58420                 button
58421                     .on('click', function() {
58422                         event.preventDefault();
58423                         options.buttonCallback();
58424                     });
58425             }
58426
58427             var tip = copyBox(tooltip.node().getBoundingClientRect()),
58428                 w = window.innerWidth,
58429                 h = window.innerHeight,
58430                 tooltipWidth = 200,
58431                 tooltipArrow = 5,
58432                 side, pos;
58433
58434
58435             // hack: this will have bottom placement,
58436             // so need to reserve extra space for the tooltip illustration.
58437             if (options.tooltipClass === 'intro-mouse') {
58438                 tip.height += 80;
58439             }
58440
58441             // trim box dimensions to just the portion that fits in the window..
58442             if (tooltipBox.top + tooltipBox.height > h) {
58443                 tooltipBox.height -= (tooltipBox.top + tooltipBox.height - h);
58444             }
58445             if (tooltipBox.left + tooltipBox.width > w) {
58446                 tooltipBox.width -= (tooltipBox.left + tooltipBox.width - w);
58447             }
58448
58449             // determine tooltip placement..
58450
58451             if (tooltipBox.top + tooltipBox.height < 100) {
58452                 // tooltip below box..
58453                 side = 'bottom';
58454                 pos = [
58455                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
58456                     tooltipBox.top + tooltipBox.height
58457                 ];
58458
58459             } else if (tooltipBox.top > h - 140) {
58460                 // tooltip above box..
58461                 side = 'top';
58462                 pos = [
58463                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
58464                     tooltipBox.top - tip.height
58465                 ];
58466
58467             } else {
58468                 // tooltip to the side of the tooltipBox..
58469                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
58470
58471                 if (textDirection === 'rtl') {
58472                     if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
58473                         side = 'right';
58474                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
58475
58476                     } else {
58477                         side = 'left';
58478                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
58479                     }
58480
58481                 } else {
58482                     if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
58483                         side = 'left';
58484                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
58485                     }
58486                     else {
58487                         side = 'right';
58488                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
58489                     }
58490                 }
58491             }
58492
58493             if (options.duration !== 0 || !tooltip.classed(side)) {
58494                 tooltip.call(uiToggle(true));
58495             }
58496
58497             tooltip
58498                 .style('top', pos[1] + 'px')
58499                 .style('left', pos[0] + 'px')
58500                 .attr('class', classes + ' ' + side);
58501
58502
58503             // shift tooltip-inner if it is very close to the top or bottom edge
58504             // (doesn't affect the placement of the tooltip-arrow)
58505             var shiftY = 0;
58506             if (side === 'left' || side === 'right') {
58507                 if (pos[1] < 60) {
58508                     shiftY = 60 - pos[1];
58509                 }
58510                 else if (pos[1] + tip.height > h - 100) {
58511                     shiftY = h - pos[1] - tip.height - 100;
58512                 }
58513             }
58514             tooltip.selectAll('.tooltip-inner')
58515                 .style('top', shiftY + 'px');
58516
58517         } else {
58518             tooltip
58519                 .classed('in', false)
58520                 .call(uiToggle(false));
58521         }
58522
58523         curtain.cut(box, options.duration);
58524
58525         return tooltip;
58526     };
58527
58528
58529     curtain.cut = function(datum, duration) {
58530         darkness.datum(datum)
58531             .interrupt();
58532
58533         var selection$$1;
58534         if (duration === 0) {
58535             selection$$1 = darkness;
58536         } else {
58537             selection$$1 = darkness
58538                 .transition()
58539                 .duration(duration || 600)
58540                 .ease(linear$1);
58541         }
58542
58543         selection$$1
58544             .attr('d', function(d) {
58545                 var string = 'M 0,0 L 0,' + window.innerHeight + ' L ' +
58546                     window.innerWidth + ',' + window.innerHeight + 'L' +
58547                     window.innerWidth + ',0 Z';
58548
58549                 if (!d) return string;
58550                 return string + 'M' +
58551                     d.left + ',' + d.top + 'L' +
58552                     d.left + ',' + (d.top + d.height) + 'L' +
58553                     (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
58554                     (d.left + d.width) + ',' + (d.top) + 'Z';
58555
58556             });
58557     };
58558
58559
58560     curtain.remove = function() {
58561         surface.remove();
58562         tooltip.remove();
58563         select(window).on('resize.curtain', null);
58564     };
58565
58566
58567     // ClientRects are immutable, so copy them to an object,
58568     // in case we need to trim the height/width.
58569     function copyBox(src) {
58570         return {
58571             top: src.top,
58572             right: src.right,
58573             bottom: src.bottom,
58574             left: src.left,
58575             width: src.width,
58576             height: src.height
58577         };
58578     }
58579
58580
58581     return curtain;
58582 }
58583
58584 function uiIntroWelcome(context, reveal) {
58585     var dispatch$$1 = dispatch('done'),
58586         listener = clickListener();
58587
58588     var chapter = {
58589         title: 'intro.welcome.title'
58590     };
58591
58592
58593     function welcome() {
58594         context.map().centerZoom([-85.63591, 41.94285], 19);
58595         reveal('.intro-nav-wrap .chapter-welcome',
58596             t('intro.welcome.welcome'),
58597             { buttonText: t('intro.ok'), buttonCallback: practice }
58598         );
58599     }
58600
58601     function practice() {
58602         reveal('.intro-nav-wrap .chapter-welcome',
58603             t('intro.welcome.practice'),
58604             { buttonText: t('intro.ok'), buttonCallback: words }
58605         );
58606     }
58607
58608     function words() {
58609         reveal('.intro-nav-wrap .chapter-welcome',
58610             t('intro.welcome.words'),
58611             { buttonText: t('intro.ok'), buttonCallback: mouse$$1 }
58612         );
58613     }
58614
58615
58616     function mouse$$1() {
58617         reveal('.intro-nav-wrap .chapter-welcome',
58618             t('intro.welcome.mouse'),
58619             { buttonText: t('intro.ok'), buttonCallback: leftClick }
58620         );
58621     }
58622
58623
58624     function leftClick() {
58625         var counter = 0,
58626             times = 5;
58627
58628         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
58629             t('intro.welcome.leftclick', { num: times }),
58630             { tooltipClass: 'intro-mouse' }
58631         );
58632
58633         tooltip.selectAll('.tooltip-inner')
58634             .insert('svg', 'span')
58635             .attr('class', 'tooltip-illustration')
58636             .append('use')
58637             .attr('xlink:href', '#walkthrough-mouse');
58638
58639         tooltip
58640             .append('div')
58641             .attr('class', 'counter');
58642
58643         tooltip.call(listener);
58644
58645         listener.on('click', function(which) {
58646             if (which === 'left') {
58647                 select('.curtain-tooltip.intro-mouse .counter')
58648                     .text(String(++counter));
58649
58650                 if (counter === times) {
58651                     window.setTimeout(function() { continueTo(rightClick); }, 1000);
58652                 }
58653             }
58654         });
58655
58656         function continueTo(nextStep) {
58657             listener.on('click', null);
58658             tooltip.call(listener.off);
58659             tooltip.select('.counter').remove();
58660             nextStep();
58661         }
58662     }
58663
58664
58665     function rightClick() {
58666         var counter = 0,
58667             times = 5;
58668
58669         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
58670             t('intro.welcome.rightclick', { num: times }),
58671             { tooltipClass: 'intro-mouse' }
58672         );
58673
58674         tooltip.selectAll('.tooltip-inner')
58675             .insert('svg', 'span')
58676             .attr('class', 'tooltip-illustration')
58677             .append('use')
58678             .attr('xlink:href', '#walkthrough-mouse');
58679
58680         tooltip
58681             .append('div')
58682             .attr('class', 'counter');
58683
58684         tooltip.call(listener);
58685
58686         listener.on('click', function(which) {
58687             if (which === 'right') {
58688                 select('.curtain-tooltip.intro-mouse .counter')
58689                     .text(String(++counter));
58690
58691                 if (counter === times) {
58692                     window.setTimeout(function() { continueTo(chapters); }, 1000);
58693                 }
58694             }
58695         });
58696
58697         function continueTo(nextStep) {
58698             listener.on('click', null);
58699             tooltip.call(listener.off);
58700             tooltip.select('.counter').remove();
58701             nextStep();
58702         }
58703     }
58704
58705
58706     function chapters() {
58707         dispatch$$1.call('done');
58708         reveal('.intro-nav-wrap .chapter-navigation',
58709             t('intro.welcome.chapters', { next: t('intro.navigation.title') })
58710         );
58711     }
58712
58713
58714     chapter.enter = function() {
58715         welcome();
58716     };
58717
58718
58719     chapter.exit = function() {
58720         listener.off();
58721     };
58722
58723
58724     chapter.restart = function() {
58725         chapter.exit();
58726         chapter.enter();
58727     };
58728
58729
58730     return utilRebind(chapter, dispatch$$1, 'on');
58731 }
58732
58733
58734
58735 function clickListener() {
58736     var dispatch$$1 = dispatch('click'),
58737         minTime = 120,
58738         tooltip = select(null),
58739         down = {};
58740
58741     // `down` keeps track of which buttons/keys are down.
58742     // Setting a property in `down` happens immediately.
58743     // Unsetting a property in `down` is delayed because
58744     //   on Windows a contextmenu event happens after keyup/mouseup
58745
58746     function keydown() {
58747         if (event.keyCode === 93)  {   // context menu
58748             event.preventDefault();
58749             event.stopPropagation();
58750             down.menu = event.timeStamp;
58751             tooltip.classed('rightclick', true);
58752         }
58753     }
58754
58755
58756     function keyup() {
58757         if (event.keyCode === 93)  {   // context menu
58758             event.preventDefault();
58759             event.stopPropagation();
58760             var endTime = event.timeStamp,
58761                 startTime = down.menu || endTime,
58762                 delay = (endTime - startTime < minTime) ? minTime : 0;
58763
58764             window.setTimeout(function() {
58765                 tooltip.classed('rightclick', false);
58766                 down.menu = undefined;  // delayed, for Windows
58767             }, delay);
58768
58769             dispatch$$1.call('click', this, 'right');
58770         }
58771     }
58772
58773
58774     function mousedown() {
58775         var button = event.button;
58776         if (button === 0 && !event.ctrlKey) {
58777             tooltip.classed('leftclick', true);
58778         } else if (button === 2) {
58779             tooltip.classed('rightclick', true);
58780         }
58781         down[button] = event.timeStamp;
58782     }
58783
58784
58785     function mouseup() {
58786         var button = event.button,
58787             endTime = event.timeStamp,
58788             startTime = down[button] || endTime,
58789             delay = (endTime - startTime < minTime) ? minTime : 0;
58790
58791         if (button === 0 && !event.ctrlKey) {
58792             window.setTimeout(function() {
58793                 tooltip.classed('leftclick', false);
58794                 down[button] = undefined;  // delayed, for Windows
58795             }, delay);
58796
58797             dispatch$$1.call('click', this, 'left');
58798
58799         } else if (button === 2) {
58800             window.setTimeout(function() {
58801                 tooltip.classed('rightclick', false);
58802                 down[button] = undefined;  // delayed, for Windows
58803             }, delay);
58804
58805             dispatch$$1.call('click', this, 'right');
58806
58807         } else {
58808             window.setTimeout(function() {
58809                 down[button] = undefined;  // delayed, for Windows
58810             }, delay);
58811         }
58812     }
58813
58814
58815     function contextmenu() {
58816         event.preventDefault();
58817         event.stopPropagation();
58818         if (!down[2] && !down.menu) {
58819             tooltip.classed('rightclick', true);
58820             window.setTimeout(function() {
58821                 tooltip.classed('rightclick', false);
58822             }, minTime);
58823             dispatch$$1.call('click', this, 'right');
58824         }
58825     }
58826
58827
58828     var behavior = function(selection$$1) {
58829         tooltip = selection$$1;
58830         down = {};
58831
58832         select(window)
58833             .on('keydown.intro', keydown)
58834             .on('keyup.intro', keyup)
58835             .on('mousedown.intro', mousedown)
58836             .on('mouseup.intro', mouseup)
58837             .on('contextmenu.intro', contextmenu);
58838     };
58839
58840
58841     behavior.off = function() {
58842         select(window)
58843             .on('keydown.intro', null)
58844             .on('keyup.intro', null)
58845             .on('mousedown.intro', null)
58846             .on('mouseup.intro', null)
58847             .on('contextmenu.intro', null);
58848
58849         tooltip
58850             .classed('leftclick', false)
58851             .classed('rightclick', false);
58852     };
58853
58854     return utilRebind(behavior, dispatch$$1, 'on');
58855 }
58856
58857 function uiIntroNavigation(context, reveal) {
58858     var dispatch$$1 = dispatch('done'),
58859         timeouts = [],
58860         hallId = 'n2061',
58861         townHall = [-85.63591, 41.94285],
58862         springStreetId = 'w397',
58863         springStreetEndId = 'n1834',
58864         springStreet = [-85.63582, 41.94255],
58865         onewayField = context.presets().field('oneway'),
58866         maxspeedField = context.presets().field('maxspeed');
58867
58868
58869     var chapter = {
58870         title: 'intro.navigation.title'
58871     };
58872
58873
58874     function timeout$$1(f, t$$1) {
58875         timeouts.push(window.setTimeout(f, t$$1));
58876     }
58877
58878
58879     function eventCancel() {
58880         event.stopPropagation();
58881         event.preventDefault();
58882     }
58883
58884
58885     function isTownHallSelected() {
58886         var ids = context.selectedIDs();
58887         return ids.length === 1 && ids[0] === hallId;
58888     }
58889
58890
58891     function dragMap() {
58892         context.enter(modeBrowse(context));
58893         context.history().reset('initial');
58894
58895         var msec = transitionTime(townHall, context.map().center());
58896         if (msec) { reveal(null, null, { duration: 0 }); }
58897         context.map().zoom(19).centerEase(townHall, msec);
58898
58899         timeout$$1(function() {
58900             var centerStart = context.map().center();
58901
58902             reveal('#surface', t('intro.navigation.drag'));
58903             context.map().on('drawn.intro', function() {
58904                 reveal('#surface', t('intro.navigation.drag'), { duration: 0 });
58905             });
58906
58907             context.map().on('move.intro', function() {
58908                 var centerNow = context.map().center();
58909                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
58910                     context.map().on('move.intro', null);
58911                     timeout$$1(function() { continueTo(zoomMap); }, 3000);
58912                 }
58913             });
58914
58915         }, msec + 100);
58916
58917         function continueTo(nextStep) {
58918             context.map().on('move.intro drawn.intro', null);
58919             nextStep();
58920         }
58921     }
58922
58923
58924     function zoomMap() {
58925         var zoomStart = context.map().zoom();
58926
58927         reveal('#surface',
58928             t('intro.navigation.zoom', {
58929                 plus: icon('#icon-plus', 'pre-text'),
58930                 minus: icon('#icon-minus', 'pre-text')
58931             })
58932         );
58933
58934         context.map().on('drawn.intro', function() {
58935             reveal('#surface',
58936                 t('intro.navigation.zoom', {
58937                     plus: icon('#icon-plus', 'pre-text'),
58938                     minus: icon('#icon-minus', 'pre-text')
58939                 }), { duration: 0 }
58940             );
58941         });
58942
58943         context.map().on('move.intro', function() {
58944             if (context.map().zoom() !== zoomStart) {
58945                 context.map().on('move.intro', null);
58946                 timeout$$1(function() { continueTo(features); }, 3000);
58947             }
58948         });
58949
58950         function continueTo(nextStep) {
58951             context.map().on('move.intro drawn.intro', null);
58952             nextStep();
58953         }
58954     }
58955
58956
58957     function features() {
58958         var onClick = function() { continueTo(pointsLinesAreas); };
58959
58960         reveal('#surface', t('intro.navigation.features'),
58961             { buttonText: t('intro.ok'), buttonCallback: onClick }
58962         );
58963
58964         context.map().on('drawn.intro', function() {
58965             reveal('#surface', t('intro.navigation.features'),
58966                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
58967             );
58968         });
58969
58970         function continueTo(nextStep) {
58971             context.map().on('drawn.intro', null);
58972             nextStep();
58973         }
58974     }
58975
58976     function pointsLinesAreas() {
58977         var onClick = function() { continueTo(nodesWays); };
58978
58979         reveal('#surface', t('intro.navigation.points_lines_areas'),
58980             { buttonText: t('intro.ok'), buttonCallback: onClick }
58981         );
58982
58983         context.map().on('drawn.intro', function() {
58984             reveal('#surface', t('intro.navigation.points_lines_areas'),
58985                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
58986             );
58987         });
58988
58989         function continueTo(nextStep) {
58990             context.map().on('drawn.intro', null);
58991             nextStep();
58992         }
58993     }
58994
58995     function nodesWays() {
58996         var onClick = function() { continueTo(clickTownHall); };
58997
58998         reveal('#surface', t('intro.navigation.nodes_ways'),
58999             { buttonText: t('intro.ok'), buttonCallback: onClick }
59000         );
59001
59002         context.map().on('drawn.intro', function() {
59003             reveal('#surface', t('intro.navigation.nodes_ways'),
59004                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59005             );
59006         });
59007
59008         function continueTo(nextStep) {
59009             context.map().on('drawn.intro', null);
59010             nextStep();
59011         }
59012     }
59013
59014     function clickTownHall() {
59015         context.enter(modeBrowse(context));
59016         context.history().reset('initial');
59017
59018         reveal(null, null, { duration: 0 });
59019         context.map().zoomEase(19, 500);
59020
59021         timeout$$1(function() {
59022             var entity = context.hasEntity(hallId);
59023             if (!entity) return;
59024             context.map().centerEase(entity.loc, 500);
59025
59026             timeout$$1(function() {
59027                 var entity = context.hasEntity(hallId);
59028                 if (!entity) return;
59029                 var box = pointBox(entity.loc, context);
59030                 reveal(box, t('intro.navigation.click_townhall'));
59031
59032                 context.map().on('move.intro drawn.intro', function() {
59033                     var entity = context.hasEntity(hallId);
59034                     if (!entity) return;
59035                     var box = pointBox(entity.loc, context);
59036                     reveal(box, t('intro.navigation.click_townhall'), { duration: 0 });
59037                 });
59038
59039                 context.on('enter.intro', function() {
59040                     if (isTownHallSelected()) continueTo(selectedTownHall);
59041                 });
59042
59043             }, 550);  // after centerEase
59044
59045         }, 550); // after zoomEase
59046
59047         context.history().on('change.intro', function() {
59048             if (!context.hasEntity(hallId)) {
59049                 continueTo(clickTownHall);
59050             }
59051         });
59052
59053         function continueTo(nextStep) {
59054             context.on('enter.intro', null);
59055             context.map().on('move.intro drawn.intro', null);
59056             context.history().on('change.intro', null);
59057             nextStep();
59058         }
59059     }
59060
59061
59062     function selectedTownHall() {
59063         if (!isTownHallSelected()) return clickTownHall();
59064
59065         var entity = context.hasEntity(hallId);
59066         if (!entity) return clickTownHall();
59067
59068         var box = pointBox(entity.loc, context);
59069         var onClick = function() { continueTo(editorTownHall); };
59070
59071         reveal(box, t('intro.navigation.selected_townhall'),
59072             { buttonText: t('intro.ok'), buttonCallback: onClick }
59073         );
59074
59075         context.map().on('move.intro drawn.intro', function() {
59076             var entity = context.hasEntity(hallId);
59077             if (!entity) return;
59078             var box = pointBox(entity.loc, context);
59079             reveal(box, t('intro.navigation.selected_townhall'),
59080                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59081             );
59082         });
59083
59084         context.history().on('change.intro', function() {
59085             if (!context.hasEntity(hallId)) {
59086                 continueTo(clickTownHall);
59087             }
59088         });
59089
59090         function continueTo(nextStep) {
59091             context.map().on('move.intro drawn.intro', null);
59092             context.history().on('change.intro', null);
59093             nextStep();
59094         }
59095     }
59096
59097
59098     function editorTownHall() {
59099         if (!isTownHallSelected()) return clickTownHall();
59100
59101         var onClick = function() { continueTo(presetTownHall); };
59102
59103         reveal('.entity-editor-pane',
59104             t('intro.navigation.editor_townhall'),
59105             { buttonText: t('intro.ok'), buttonCallback: onClick }
59106         );
59107
59108         context.on('exit.intro', function() {
59109             continueTo(clickTownHall);
59110         });
59111
59112         context.history().on('change.intro', function() {
59113             if (!context.hasEntity(hallId)) {
59114                 continueTo(clickTownHall);
59115             }
59116         });
59117
59118         function continueTo(nextStep) {
59119             context.on('exit.intro', null);
59120             context.history().on('change.intro', null);
59121             nextStep();
59122         }
59123     }
59124
59125
59126     function presetTownHall() {
59127         if (!isTownHallSelected()) return clickTownHall();
59128
59129         // reset pane, in case user happened to change it..
59130         select('.inspector-wrap .panewrap').style('right', '0%');
59131
59132         // preset match, in case the user happened to change it.
59133         var entity = context.entity(context.selectedIDs()[0]);
59134         var preset = context.presets().match(entity, context.graph());
59135
59136         var onClick = function() { continueTo(fieldsTownHall); };
59137
59138         context.on('exit.intro', function() {
59139             continueTo(clickTownHall);
59140         });
59141
59142         context.history().on('change.intro', function() {
59143             if (!context.hasEntity(hallId)) {
59144                 continueTo(clickTownHall);
59145             }
59146         });
59147
59148         reveal('.inspector-body .preset-list-item.inspector-inner',
59149             t('intro.navigation.preset_townhall', { preset: preset.name() }),
59150             { buttonText: t('intro.ok'), buttonCallback: onClick }
59151         );
59152
59153         function continueTo(nextStep) {
59154             context.on('exit.intro', null);
59155             context.history().on('change.intro', null);
59156             nextStep();
59157         }
59158     }
59159
59160
59161     function fieldsTownHall() {
59162         if (!isTownHallSelected()) return clickTownHall();
59163
59164         // reset pane, in case user happened to change it..
59165         select('.inspector-wrap .panewrap').style('right', '0%');
59166
59167         var onClick = function() { continueTo(closeTownHall); };
59168
59169         reveal('.inspector-body .inspector-preset',
59170             t('intro.navigation.fields_townhall'),
59171             { buttonText: t('intro.ok'), buttonCallback: onClick }
59172         );
59173
59174         context.on('exit.intro', function() {
59175             continueTo(clickTownHall);
59176         });
59177
59178         context.history().on('change.intro', function() {
59179             if (!context.hasEntity(hallId)) {
59180                 continueTo(clickTownHall);
59181             }
59182         });
59183
59184         function continueTo(nextStep) {
59185             context.on('exit.intro', null);
59186             context.history().on('change.intro', null);
59187             nextStep();
59188         }
59189     }
59190
59191
59192     function closeTownHall() {
59193         if (!isTownHallSelected()) return clickTownHall();
59194
59195         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59196         var href = select(selector$$1).attr('href') || '#icon-close';
59197
59198         reveal('.entity-editor-pane',
59199             t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') })
59200         );
59201
59202         context.on('exit.intro', function() {
59203             continueTo(searchStreet);
59204         });
59205
59206         context.history().on('change.intro', function() {
59207             // update the close icon in the tooltip if the user edits something.
59208             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59209             var href = select(selector$$1).attr('href') || '#icon-close';
59210
59211             reveal('.entity-editor-pane',
59212                 t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }),
59213                 { duration: 0 }
59214             );
59215         });
59216
59217         function continueTo(nextStep) {
59218             context.on('exit.intro', null);
59219             context.history().on('change.intro', null);
59220             nextStep();
59221         }
59222     }
59223
59224
59225     function searchStreet() {
59226         context.enter(modeBrowse(context));
59227         context.history().reset('initial');  // ensure spring street exists
59228
59229         var msec = transitionTime(springStreet, context.map().center());
59230         if (msec) { reveal(null, null, { duration: 0 }); }
59231         context.map().zoom(19).centerEase(springStreet, msec);  // ..and user can see it
59232
59233         timeout$$1(function() {
59234             reveal('.search-header input',
59235                 t('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') })
59236             );
59237
59238             select('.search-header input')
59239                 .on('keyup.intro', checkSearchResult);
59240         }, msec + 100);
59241     }
59242
59243
59244     function checkSearchResult() {
59245         var first = select('.feature-list-item:nth-child(0n+2)'),  // skip "No Results" item
59246             firstName = first.select('.entity-name'),
59247             name = t('intro.graph.name.spring-street');
59248
59249         if (!firstName.empty() && firstName.text() === name) {
59250             reveal(first.node(),
59251                 t('intro.navigation.choose_street', { name: name }),
59252                 { duration: 300 }
59253             );
59254
59255             context.on('exit.intro', function() {
59256                 continueTo(selectedStreet);
59257             });
59258
59259             select('.search-header input')
59260                 .on('keydown.intro', eventCancel, true)
59261                 .on('keyup.intro', null);
59262         }
59263
59264         function continueTo(nextStep) {
59265             context.on('exit.intro', null);
59266             select('.search-header input')
59267                 .on('keydown.intro', null)
59268                 .on('keyup.intro', null);
59269             nextStep();
59270         }
59271     }
59272
59273
59274     function selectedStreet() {
59275         if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
59276             return searchStreet();
59277         }
59278
59279         var onClick = function() { continueTo(editorStreet); };
59280         var entity = context.entity(springStreetEndId);
59281         var box = pointBox(entity.loc, context);
59282         box.height = 500;
59283
59284         reveal(box,
59285             t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
59286             { duration: 600, buttonText: t('intro.ok'), buttonCallback: onClick }
59287         );
59288
59289         timeout$$1(function() {
59290             context.map().on('move.intro drawn.intro', function() {
59291                 var entity = context.hasEntity(springStreetEndId);
59292                 if (!entity) return;
59293                 var box = pointBox(entity.loc, context);
59294                 box.height = 500;
59295                 reveal(box,
59296                     t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
59297                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59298                 );
59299             });
59300         }, 600);  // after reveal.
59301
59302         context.on('enter.intro', function(mode) {
59303             if (!context.hasEntity(springStreetId)) {
59304                 return continueTo(searchStreet);
59305             }
59306             var ids = context.selectedIDs();
59307             if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
59308                 // keep Spring Street selected..
59309                 context.enter(modeSelect(context, [springStreetId]));
59310             }
59311         });
59312
59313         context.history().on('change.intro', function() {
59314             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
59315                 timeout$$1(function() {
59316                     continueTo(searchStreet);
59317                 }, 300);  // after any transition (e.g. if user deleted intersection)
59318             }
59319         });
59320
59321         function continueTo(nextStep) {
59322             context.map().on('move.intro drawn.intro', null);
59323             context.on('enter.intro', null);
59324             context.history().on('change.intro', null);
59325             nextStep();
59326         }
59327     }
59328
59329
59330     function editorStreet() {
59331         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59332         var href = select(selector$$1).attr('href') || '#icon-close';
59333
59334         reveal('.entity-editor-pane',
59335             t('intro.navigation.editor_street', {
59336                 button: icon(href, 'pre-text'),
59337                 field1: onewayField.label(),
59338                 field2: maxspeedField.label()
59339             })
59340         );
59341
59342         context.on('exit.intro', function() {
59343             continueTo(play);
59344         });
59345
59346         context.history().on('change.intro', function() {
59347             // update the close icon in the tooltip if the user edits something.
59348             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59349             var href = select(selector$$1).attr('href') || '#icon-close';
59350
59351             reveal('.entity-editor-pane',
59352                 t('intro.navigation.editor_street', {
59353                     button: icon(href, 'pre-text'),
59354                     field1: onewayField.label().toLowerCase(),
59355                     field2: maxspeedField.label().toLowerCase()
59356                 }), { duration: 0 }
59357             );
59358         });
59359
59360         function continueTo(nextStep) {
59361             context.on('exit.intro', null);
59362             context.history().on('change.intro', null);
59363             nextStep();
59364         }
59365     }
59366
59367
59368     function play() {
59369         dispatch$$1.call('done');
59370         reveal('#id-container',
59371             t('intro.navigation.play', { next: t('intro.points.title') }), {
59372                 tooltipBox: '.intro-nav-wrap .chapter-point',
59373                 buttonText: t('intro.ok'),
59374                 buttonCallback: function() { reveal('#id-container'); }
59375             }
59376         );
59377     }
59378
59379
59380     chapter.enter = function() {
59381         dragMap();
59382     };
59383
59384
59385     chapter.exit = function() {
59386         timeouts.forEach(window.clearTimeout);
59387         context.on('enter.intro exit.intro', null);
59388         context.map().on('move.intro drawn.intro', null);
59389         context.history().on('change.intro', null);
59390         select('.search-header input').on('keydown.intro keyup.intro', null);
59391     };
59392
59393
59394     chapter.restart = function() {
59395         chapter.exit();
59396         chapter.enter();
59397     };
59398
59399
59400     return utilRebind(chapter, dispatch$$1, 'on');
59401 }
59402
59403 function uiIntroPoint(context, reveal) {
59404     var dispatch$$1 = dispatch('done'),
59405         timeouts = [],
59406         intersection = [-85.63279, 41.94394],
59407         building = [-85.632422, 41.944045],
59408         cafePreset = context.presets().item('amenity/cafe'),
59409         pointId = null;
59410
59411
59412     var chapter = {
59413         title: 'intro.points.title'
59414     };
59415
59416
59417     function timeout$$1(f, t$$1) {
59418         timeouts.push(window.setTimeout(f, t$$1));
59419     }
59420
59421
59422     function revealEditMenu(loc, text$$1, options) {
59423         var rect = context.surfaceRect();
59424         var point = context.curtainProjection(loc);
59425         var pad$$1 = 40;
59426         var width = 250 + (2 * pad$$1);
59427         var height = 250;
59428         var startX = rect.left + point[0];
59429         var left = (textDirection === 'rtl') ? (startX - width + pad$$1) : (startX - pad$$1);
59430         var box = {
59431             left: left,
59432             top: point[1] + rect.top - 60,
59433             width: width,
59434             height: height
59435         };
59436         reveal(box, text$$1, options);
59437     }
59438
59439
59440     function eventCancel() {
59441         event.stopPropagation();
59442         event.preventDefault();
59443     }
59444
59445
59446     function addPoint() {
59447         context.enter(modeBrowse(context));
59448         context.history().reset('initial');
59449
59450         var msec = transitionTime(intersection, context.map().center());
59451         if (msec) { reveal(null, null, { duration: 0 }); }
59452         context.map().zoom(19).centerEase(intersection, msec);
59453
59454         timeout$$1(function() {
59455             var tooltip = reveal('button.add-point',
59456                 t('intro.points.add_point', { button: icon('#icon-point', 'pre-text') }));
59457
59458             pointId = null;
59459
59460             tooltip.selectAll('.tooltip-inner')
59461                 .insert('svg', 'span')
59462                 .attr('class', 'tooltip-illustration')
59463                 .append('use')
59464                 .attr('xlink:href', '#poi-images');
59465
59466             context.on('enter.intro', function(mode) {
59467                 if (mode.id !== 'add-point') return;
59468                 continueTo(placePoint);
59469             });
59470         }, msec + 100);
59471
59472         function continueTo(nextStep) {
59473             context.on('enter.intro', null);
59474             nextStep();
59475         }
59476     }
59477
59478
59479     function placePoint() {
59480         if (context.mode().id !== 'add-point') {
59481             return chapter.restart();
59482         }
59483
59484         var pointBox$$1 = pad$1(building, 150, context);
59485         reveal(pointBox$$1, t('intro.points.place_point'));
59486
59487         context.map().on('move.intro drawn.intro', function() {
59488             pointBox$$1 = pad$1(building, 150, context);
59489             reveal(pointBox$$1, t('intro.points.place_point'), { duration: 0 });
59490         });
59491
59492         context.on('enter.intro', function(mode) {
59493             if (mode.id !== 'select') return chapter.restart();
59494             pointId = context.mode().selectedIDs()[0];
59495             continueTo(searchPreset);
59496         });
59497
59498         function continueTo(nextStep) {
59499             context.map().on('move.intro drawn.intro', null);
59500             context.on('enter.intro', null);
59501             nextStep();
59502         }
59503     }
59504
59505
59506     function searchPreset() {
59507         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59508             return addPoint();
59509         }
59510
59511         select('.preset-search-input')
59512             .on('keydown.intro', null)
59513             .on('keyup.intro', checkPresetSearch);
59514
59515         reveal('.preset-search-input',
59516             t('intro.points.search_cafe', { preset: cafePreset.name() })
59517         );
59518
59519         context.on('enter.intro', function(mode) {
59520             if (!pointId || !context.hasEntity(pointId)) {
59521                 return continueTo(addPoint);
59522             }
59523
59524             var ids = context.selectedIDs();
59525             if (mode.id !== 'select' || !ids.length || ids[0] !== pointId) {
59526                 // keep the user's point selected..
59527                 context.enter(modeSelect(context, [pointId]));
59528
59529                 select('.preset-search-input')
59530                     .on('keydown.intro', null)
59531                     .on('keyup.intro', checkPresetSearch);
59532
59533                 reveal('.preset-search-input',
59534                     t('intro.points.search_cafe', { preset: cafePreset.name() })
59535                 );
59536
59537                 context.history().on('change.intro', null);
59538             }
59539         });
59540
59541
59542         function checkPresetSearch() {
59543             var first = select('.preset-list-item:first-child');
59544
59545             if (first.classed('preset-amenity-cafe')) {
59546                 select('.preset-search-input')
59547                     .on('keydown.intro', eventCancel, true)
59548                     .on('keyup.intro', null);
59549
59550                 reveal(first.select('.preset-list-button').node(),
59551                     t('intro.points.choose_cafe', { preset: cafePreset.name() }),
59552                     { duration: 300 }
59553                 );
59554
59555                 context.history().on('change.intro', function() {
59556                     continueTo(aboutFeatureEditor);
59557                 });
59558             }
59559         }
59560
59561         function continueTo(nextStep) {
59562             context.on('enter.intro', null);
59563             context.history().on('change.intro', null);
59564             select('.preset-search-input').on('keydown.intro keyup.intro', null);
59565             nextStep();
59566         }
59567     }
59568
59569
59570     function aboutFeatureEditor() {
59571         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59572             return addPoint();
59573         }
59574
59575         timeout$$1(function() {
59576             reveal('.entity-editor-pane', t('intro.points.feature_editor'), {
59577                 tooltipClass: 'intro-points-describe',
59578                 buttonText: t('intro.ok'),
59579                 buttonCallback: function() { continueTo(addName); }
59580             });
59581         }, 400);
59582
59583         context.on('exit.intro', function() {
59584             // if user leaves select mode here, just continue with the tutorial.
59585             continueTo(reselectPoint);
59586         });
59587
59588         function continueTo(nextStep) {
59589             context.on('exit.intro', null);
59590             nextStep();
59591         }
59592     }
59593
59594
59595     function addName() {
59596         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59597             return addPoint();
59598         }
59599
59600         // reset pane, in case user happened to change it..
59601         select('.inspector-wrap .panewrap').style('right', '0%');
59602
59603         timeout$$1(function() {
59604             // It's possible for the user to add a name in a previous step..
59605             // If so, don't tell them to add the name in this step.
59606             // Give them an OK button instead.
59607             var entity = context.entity(pointId);
59608             if (entity.tags.name) {
59609                 var tooltip = reveal('.entity-editor-pane', t('intro.points.add_name'), {
59610                     tooltipClass: 'intro-points-describe',
59611                     buttonText: t('intro.ok'),
59612                     buttonCallback: function() { continueTo(addCloseEditor); }
59613                 });
59614                 tooltip.select('.instruction').style('display', 'none');
59615
59616             } else {
59617                 reveal('.entity-editor-pane', t('intro.points.add_name'),
59618                     { tooltipClass: 'intro-points-describe' }
59619                 );
59620             }
59621         }, 400);
59622
59623         context.history().on('change.intro', function() {
59624             continueTo(addCloseEditor);
59625         });
59626
59627         context.on('exit.intro', function() {
59628             // if user leaves select mode here, just continue with the tutorial.
59629             continueTo(reselectPoint);
59630         });
59631
59632         function continueTo(nextStep) {
59633             context.on('exit.intro', null);
59634             context.history().on('change.intro', null);
59635             nextStep();
59636         }
59637     }
59638
59639
59640     function addCloseEditor() {
59641         // reset pane, in case user happened to change it..
59642         select('.inspector-wrap .panewrap').style('right', '0%');
59643
59644         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59645         var href = select(selector$$1).attr('href') || '#icon-close';
59646
59647         context.on('exit.intro', function() {
59648             continueTo(reselectPoint);
59649         });
59650
59651         reveal('.entity-editor-pane',
59652             t('intro.points.add_close', { button: icon(href, 'pre-text') })
59653         );
59654
59655         function continueTo(nextStep) {
59656             context.on('exit.intro', null);
59657             nextStep();
59658         }
59659     }
59660
59661
59662     function reselectPoint() {
59663         if (!pointId) return chapter.restart();
59664         var entity = context.hasEntity(pointId);
59665         if (!entity) return chapter.restart();
59666
59667         // make sure it's still a cafe, in case user somehow changed it..
59668         var oldPreset = context.presets().match(entity, context.graph());
59669         context.replace(actionChangePreset(pointId, oldPreset, cafePreset));
59670
59671         context.enter(modeBrowse(context));
59672
59673         var msec = transitionTime(entity.loc, context.map().center());
59674         if (msec) { reveal(null, null, { duration: 0 }); }
59675         context.map().centerEase(entity.loc, msec);
59676
59677         timeout$$1(function() {
59678             var box = pointBox(entity.loc, context);
59679             reveal(box, t('intro.points.reselect'), { duration: 600 });
59680
59681             timeout$$1(function() {
59682                 context.map().on('move.intro drawn.intro', function() {
59683                     var entity = context.hasEntity(pointId);
59684                     if (!entity) return chapter.restart();
59685                     var box = pointBox(entity.loc, context);
59686                     reveal(box, t('intro.points.reselect'), { duration: 0 });
59687                 });
59688             }, 600); // after reveal..
59689
59690             context.on('enter.intro', function(mode) {
59691                 if (mode.id !== 'select') return;
59692                 continueTo(updatePoint);
59693             });
59694
59695         }, msec + 100);
59696
59697         function continueTo(nextStep) {
59698             context.map().on('move.intro drawn.intro', null);
59699             context.on('enter.intro', null);
59700             nextStep();
59701         }
59702     }
59703
59704
59705     function updatePoint() {
59706         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59707             return continueTo(reselectPoint);
59708         }
59709
59710         // reset pane, in case user happened to untag the point..
59711         select('.inspector-wrap .panewrap').style('right', '0%');
59712
59713         context.on('exit.intro', function() {
59714             continueTo(reselectPoint);
59715         });
59716
59717         context.history().on('change.intro', function() {
59718             continueTo(updateCloseEditor);
59719         });
59720
59721         timeout$$1(function() {
59722             reveal('.entity-editor-pane', t('intro.points.update'),
59723                 { tooltipClass: 'intro-points-describe' }
59724             );
59725         }, 400);
59726
59727         function continueTo(nextStep) {
59728             context.on('exit.intro', null);
59729             context.history().on('change.intro', null);
59730             nextStep();
59731         }
59732     }
59733
59734
59735     function updateCloseEditor() {
59736         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59737             return continueTo(reselectPoint);
59738         }
59739
59740         // reset pane, in case user happened to change it..
59741         select('.inspector-wrap .panewrap').style('right', '0%');
59742
59743         context.on('exit.intro', function() {
59744             continueTo(rightClickPoint);
59745         });
59746
59747         timeout$$1(function() {
59748             reveal('.entity-editor-pane',
59749                 t('intro.points.update_close', { button: icon('#icon-apply', 'pre-text') })
59750             );
59751         }, 500);
59752
59753         function continueTo(nextStep) {
59754             context.on('exit.intro', null);
59755             nextStep();
59756         }
59757     }
59758
59759
59760     function rightClickPoint() {
59761         if (!pointId) return chapter.restart();
59762         var entity = context.hasEntity(pointId);
59763         if (!entity) return chapter.restart();
59764
59765         context.enter(modeBrowse(context));
59766
59767         var box = pointBox(entity.loc, context);
59768         reveal(box, t('intro.points.rightclick'), { duration: 600 });
59769
59770         timeout$$1(function() {
59771             context.map().on('move.intro drawn.intro', function() {
59772                 var entity = context.hasEntity(pointId);
59773                 if (!entity) return chapter.restart();
59774                 var box = pointBox(entity.loc, context);
59775                 reveal(box, t('intro.points.rightclick'), { duration: 0 });
59776             });
59777         }, 600); // after reveal
59778
59779         context.on('enter.intro', function(mode) {
59780             if (mode.id !== 'select') return;
59781             var ids = context.selectedIDs();
59782             if (ids.length !== 1 || ids[0] !== pointId) return;
59783
59784             timeout$$1(function() {
59785                 var node = selectMenuItem('delete').node();
59786                 if (!node) return;
59787                 continueTo(enterDelete);
59788             }, 300);  // after menu visible
59789         });
59790
59791         function continueTo(nextStep) {
59792             context.on('enter.intro', null);
59793             context.map().on('move.intro drawn.intro', null);
59794             nextStep();
59795         }
59796     }
59797
59798
59799     function enterDelete() {
59800         if (!pointId) return chapter.restart();
59801         var entity = context.hasEntity(pointId);
59802         if (!entity) return chapter.restart();
59803
59804         var node = selectMenuItem('delete').node();
59805         if (!node) { return continueTo(rightClickPoint); }
59806
59807         revealEditMenu(entity.loc,
59808             t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') })
59809         );
59810
59811         timeout$$1(function() {
59812             context.map().on('move.intro drawn.intro', function() {
59813                 revealEditMenu(entity.loc,
59814                     t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') }),
59815                     { duration: 0}
59816                 );
59817             });
59818         }, 300); // after menu visible
59819
59820         context.on('exit.intro', function() {
59821             if (!pointId) return chapter.restart();
59822             var entity = context.hasEntity(pointId);
59823             if (entity) return continueTo(rightClickPoint);  // point still exists
59824         });
59825
59826         context.history().on('change.intro', function(changed) {
59827             if (changed.deleted().length) {
59828                 continueTo(undo);
59829             }
59830         });
59831
59832         function continueTo(nextStep) {
59833             context.map().on('move.intro drawn.intro', null);
59834             context.history().on('change.intro', null);
59835             context.on('exit.intro', null);
59836             nextStep();
59837         }
59838     }
59839
59840
59841     function undo() {
59842         context.history().on('change.intro', function() {
59843             continueTo(play);
59844         });
59845
59846         var iconName = '#icon-' + (textDirection === 'rtl' ? 'redo' : 'undo');
59847         reveal('#bar button.undo-button',
59848             t('intro.points.undo', { button: icon(iconName, 'pre-text') })
59849         );
59850
59851         function continueTo(nextStep) {
59852             context.history().on('change.intro', null);
59853             nextStep();
59854         }
59855     }
59856
59857
59858     function play() {
59859         dispatch$$1.call('done');
59860         reveal('#id-container',
59861             t('intro.points.play', { next: t('intro.areas.title') }), {
59862                 tooltipBox: '.intro-nav-wrap .chapter-area',
59863                 buttonText: t('intro.ok'),
59864                 buttonCallback: function() { reveal('#id-container'); }
59865             }
59866         );
59867     }
59868
59869
59870     chapter.enter = function() {
59871         addPoint();
59872     };
59873
59874
59875     chapter.exit = function() {
59876         timeouts.forEach(window.clearTimeout);
59877         context.on('enter.intro exit.intro', null);
59878         context.map().on('move.intro drawn.intro', null);
59879         context.history().on('change.intro', null);
59880         select('.preset-search-input').on('keydown.intro keyup.intro', null);
59881     };
59882
59883
59884     chapter.restart = function() {
59885         chapter.exit();
59886         chapter.enter();
59887     };
59888
59889
59890     return utilRebind(chapter, dispatch$$1, 'on');
59891 }
59892
59893 function uiIntroArea(context, reveal) {
59894     var dispatch$$1 = dispatch('done'),
59895         playground = [-85.63552, 41.94159],
59896         playgroundPreset = context.presets().item('leisure/playground'),
59897         descriptionField = context.presets().field('description'),
59898         timeouts = [],
59899         areaId;
59900
59901
59902     var chapter = {
59903         title: 'intro.areas.title'
59904     };
59905
59906
59907     function timeout$$1(f, t$$1) {
59908         timeouts.push(window.setTimeout(f, t$$1));
59909     }
59910
59911
59912     function eventCancel() {
59913         event.stopPropagation();
59914         event.preventDefault();
59915     }
59916
59917
59918     function revealPlayground(center, text$$1, options) {
59919         var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
59920         var box = pad$1(center, padding, context);
59921         reveal(box, text$$1, options);
59922     }
59923
59924
59925     function addArea() {
59926         context.enter(modeBrowse(context));
59927         context.history().reset('initial');
59928         areaId = null;
59929
59930         var msec = transitionTime(playground, context.map().center());
59931         if (msec) { reveal(null, null, { duration: 0 }); }
59932         context.map().zoom(19).centerEase(playground, msec);
59933
59934         timeout$$1(function() {
59935             var tooltip = reveal('button.add-area',
59936                 t('intro.areas.add_playground', { button: icon('#icon-area', 'pre-text') }));
59937
59938             tooltip.selectAll('.tooltip-inner')
59939                 .insert('svg', 'span')
59940                 .attr('class', 'tooltip-illustration')
59941                 .append('use')
59942                 .attr('xlink:href', '#landuse-images');
59943
59944             context.on('enter.intro', function(mode) {
59945                 if (mode.id !== 'add-area') return;
59946                 continueTo(startPlayground);
59947             });
59948         }, msec + 100);
59949
59950         function continueTo(nextStep) {
59951             context.on('enter.intro', null);
59952             nextStep();
59953         }
59954     }
59955
59956
59957     function startPlayground() {
59958         if (context.mode().id !== 'add-area') {
59959             return chapter.restart();
59960         }
59961
59962         areaId = null;
59963         context.map().zoomEase(19.5, 500);
59964
59965         timeout$$1(function() {
59966             revealPlayground(playground,
59967                 t('intro.areas.start_playground'), { duration: 250 }
59968             );
59969
59970             timeout$$1(function() {
59971                 context.map().on('move.intro drawn.intro', function() {
59972                     revealPlayground(playground,
59973                         t('intro.areas.start_playground'), { duration: 0 }
59974                     );
59975                 });
59976                 context.on('enter.intro', function(mode) {
59977                     if (mode.id !== 'draw-area') return chapter.restart();
59978                     continueTo(continuePlayground);
59979                 });
59980             }, 250);  // after reveal
59981
59982         }, 550);  // after easing
59983
59984         function continueTo(nextStep) {
59985             context.map().on('move.intro drawn.intro', null);
59986             context.on('enter.intro', null);
59987             nextStep();
59988         }
59989     }
59990
59991
59992     function continuePlayground() {
59993         if (context.mode().id !== 'draw-area') {
59994             return chapter.restart();
59995         }
59996
59997         areaId = null;
59998         revealPlayground(playground,
59999             t('intro.areas.continue_playground'), { duration: 250 }
60000         );
60001
60002         timeout$$1(function() {
60003             context.map().on('move.intro drawn.intro', function() {
60004                 revealPlayground(playground,
60005                     t('intro.areas.continue_playground'), { duration: 0 }
60006                 );
60007             });
60008         }, 250);  // after reveal
60009
60010         context.on('enter.intro', function(mode) {
60011             if (mode.id === 'draw-area') {
60012                 var entity = context.hasEntity(context.selectedIDs()[0]);
60013                 if (entity && entity.nodes.length >= 6) {
60014                     return continueTo(finishPlayground);
60015                 } else {
60016                     return;
60017                 }
60018             } else if (mode.id === 'select') {
60019                 areaId = context.selectedIDs()[0];
60020                 return continueTo(searchPresets);
60021             } else {
60022                 return chapter.restart();
60023             }
60024         });
60025
60026         function continueTo(nextStep) {
60027             context.map().on('move.intro drawn.intro', null);
60028             context.on('enter.intro', null);
60029             nextStep();
60030         }
60031     }
60032
60033
60034     function finishPlayground() {
60035         if (context.mode().id !== 'draw-area') {
60036             return chapter.restart();
60037         }
60038
60039         areaId = null;
60040         revealPlayground(playground,
60041             t('intro.areas.finish_playground'), { duration: 250 }
60042         );
60043
60044         timeout$$1(function() {
60045             context.map().on('move.intro drawn.intro', function() {
60046                 revealPlayground(playground,
60047                     t('intro.areas.finish_playground'), { duration: 0 }
60048                 );
60049             });
60050         }, 250);  // after reveal
60051
60052         context.on('enter.intro', function(mode) {
60053             if (mode.id === 'draw-area') {
60054                 return;
60055             } else if (mode.id === 'select') {
60056                 areaId = context.selectedIDs()[0];
60057                 return continueTo(searchPresets);
60058             } else {
60059                 return chapter.restart();
60060             }
60061         });
60062
60063         function continueTo(nextStep) {
60064             context.map().on('move.intro drawn.intro', null);
60065             context.on('enter.intro', null);
60066             nextStep();
60067         }
60068     }
60069
60070
60071     function searchPresets() {
60072         if (!areaId || !context.hasEntity(areaId)) {
60073             return addArea();
60074         }
60075         var ids = context.selectedIDs();
60076         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60077             context.enter(modeSelect(context, [areaId]));
60078         }
60079
60080         timeout$$1(function() {
60081             // reset pane, in case user somehow happened to change it..
60082             select('.inspector-wrap .panewrap').style('right', '-100%');
60083
60084             select('.preset-search-input')
60085                 .on('keydown.intro', null)
60086                 .on('keyup.intro', checkPresetSearch);
60087
60088             reveal('.preset-search-input',
60089                 t('intro.areas.search_playground', { preset: playgroundPreset.name() })
60090             );
60091         }, 400);  // after preset list pane visible..
60092
60093         context.on('enter.intro', function(mode) {
60094             if (!areaId || !context.hasEntity(areaId)) {
60095                 return continueTo(addArea);
60096             }
60097
60098             var ids = context.selectedIDs();
60099             if (mode.id !== 'select' || !ids.length || ids[0] !== areaId) {
60100                 // keep the user's area selected..
60101                 context.enter(modeSelect(context, [areaId]));
60102
60103                 // reset pane, in case user somehow happened to change it..
60104                 select('.inspector-wrap .panewrap').style('right', '-100%');
60105
60106                 select('.preset-search-input')
60107                     .on('keydown.intro', null)
60108                     .on('keyup.intro', checkPresetSearch);
60109
60110                 reveal('.preset-search-input',
60111                     t('intro.areas.search_playground', { preset: playgroundPreset.name() })
60112                 );
60113
60114                 context.history().on('change.intro', null);
60115             }
60116         });
60117
60118         function checkPresetSearch() {
60119             var first = select('.preset-list-item:first-child');
60120
60121             if (first.classed('preset-leisure-playground')) {
60122                 reveal(first.select('.preset-list-button').node(),
60123                     t('intro.areas.choose_playground', { preset: playgroundPreset.name() }),
60124                     { duration: 300 }
60125                 );
60126
60127                 select('.preset-search-input')
60128                     .on('keydown.intro', eventCancel, true)
60129                     .on('keyup.intro', null);
60130
60131                 context.history().on('change.intro', function() {
60132                     continueTo(clickAddField);
60133                 });
60134             }
60135         }
60136
60137         function continueTo(nextStep) {
60138             context.on('enter.intro', null);
60139             context.history().on('change.intro', null);
60140             select('.preset-search-input').on('keydown.intro keyup.intro', null);
60141             nextStep();
60142         }
60143     }
60144
60145
60146     function clickAddField() {
60147         if (!areaId || !context.hasEntity(areaId)) {
60148             return addArea();
60149         }
60150         var ids = context.selectedIDs();
60151         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60152             return searchPresets();
60153         }
60154
60155         timeout$$1(function() {
60156             // reset pane, in case user somehow happened to change it..
60157             select('.inspector-wrap .panewrap').style('right', '0%');
60158
60159             // It's possible for the user to add a description in a previous step..
60160             // If they did this already, just continue to next step.
60161             var entity = context.entity(areaId);
60162             if (entity.tags.description) {
60163                 return continueTo(play);
60164             }
60165
60166             reveal('.more-fields .combobox-input',
60167                 t('intro.areas.add_field'),
60168                 { duration: 300 }
60169             );
60170
60171             select('.more-fields .combobox-input')
60172                 .on('click.intro', function() {
60173                     continueTo(chooseDescriptionField);
60174                 });
60175         }, 400);  // after editor pane visible
60176
60177         context.on('exit.intro', function() {
60178             return continueTo(searchPresets);
60179         });
60180
60181         function continueTo(nextStep) {
60182             select('.more-fields .combobox-input').on('click.intro', null);
60183             context.on('exit.intro', null);
60184             nextStep();
60185         }
60186     }
60187
60188
60189     function chooseDescriptionField() {
60190         if (!areaId || !context.hasEntity(areaId)) {
60191             return addArea();
60192         }
60193         var ids = context.selectedIDs();
60194         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60195             return searchPresets();
60196         }
60197
60198         // Make sure combobox is ready..
60199         if (select('div.combobox').empty()) {
60200             return continueTo(clickAddField);
60201         }
60202         // Watch for the combobox to go away..
60203         var watcher;
60204         watcher = window.setInterval(function() {
60205             if (select('div.combobox').empty()) {
60206                 window.clearInterval(watcher);
60207                 timeout$$1(function() {
60208                     if (select('.form-field-description').empty()) {
60209                         continueTo(retryChooseDescription);
60210                     } else {
60211                         continueTo(describePlayground);
60212                     }
60213                 }, 300);  // after description field added.
60214             }
60215         }, 300);
60216
60217         reveal('div.combobox',
60218             t('intro.areas.choose_field', { field: descriptionField.label() }),
60219             { duration: 300 }
60220         );
60221
60222         context.on('exit.intro', function() {
60223             return continueTo(searchPresets);
60224         });
60225
60226         function continueTo(nextStep) {
60227             if (watcher) window.clearInterval(watcher);
60228             context.on('exit.intro', null);
60229             nextStep();
60230         }
60231     }
60232
60233
60234     function describePlayground() {
60235         if (!areaId || !context.hasEntity(areaId)) {
60236             return addArea();
60237         }
60238         var ids = context.selectedIDs();
60239         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60240             return searchPresets();
60241         }
60242
60243         // reset pane, in case user happened to change it..
60244         select('.inspector-wrap .panewrap').style('right', '0%');
60245
60246         if (select('.form-field-description').empty()) {
60247             return continueTo(retryChooseDescription);
60248         }
60249
60250         context.on('exit.intro', function() {
60251             continueTo(play);
60252         });
60253
60254         reveal('.entity-editor-pane',
60255             t('intro.areas.describe_playground', { button: icon('#icon-apply', 'pre-text') }),
60256             { duration: 300 }
60257         );
60258
60259         function continueTo(nextStep) {
60260             context.on('exit.intro', null);
60261             nextStep();
60262         }
60263     }
60264
60265
60266     function retryChooseDescription() {
60267         if (!areaId || !context.hasEntity(areaId)) {
60268             return addArea();
60269         }
60270         var ids = context.selectedIDs();
60271         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60272             return searchPresets();
60273         }
60274
60275         // reset pane, in case user happened to change it..
60276         select('.inspector-wrap .panewrap').style('right', '0%');
60277
60278         reveal('.entity-editor-pane',
60279             t('intro.areas.retry_add_field', { field: descriptionField.label() }), {
60280             buttonText: t('intro.ok'),
60281             buttonCallback: function() { continueTo(clickAddField); }
60282         });
60283
60284         context.on('exit.intro', function() {
60285             return continueTo(searchPresets);
60286         });
60287
60288         function continueTo(nextStep) {
60289             context.on('exit.intro', null);
60290             nextStep();
60291         }
60292     }
60293
60294
60295     function play() {
60296         dispatch$$1.call('done');
60297         reveal('#id-container',
60298             t('intro.areas.play', { next: t('intro.lines.title') }), {
60299                 tooltipBox: '.intro-nav-wrap .chapter-line',
60300                 buttonText: t('intro.ok'),
60301                 buttonCallback: function() { reveal('#id-container'); }
60302             }
60303         );
60304     }
60305
60306
60307     chapter.enter = function() {
60308         addArea();
60309     };
60310
60311
60312     chapter.exit = function() {
60313         timeouts.forEach(window.clearTimeout);
60314         context.on('enter.intro exit.intro', null);
60315         context.map().on('move.intro drawn.intro', null);
60316         context.history().on('change.intro', null);
60317         select('.preset-search-input').on('keydown.intro keyup.intro', null);
60318         select('.more-fields .combobox-input').on('click.intro', null);
60319     };
60320
60321
60322     chapter.restart = function() {
60323         chapter.exit();
60324         chapter.enter();
60325     };
60326
60327
60328     return utilRebind(chapter, dispatch$$1, 'on');
60329 }
60330
60331 function uiIntroLine(context, reveal) {
60332     var dispatch$$1 = dispatch('done'),
60333         timeouts = [],
60334         tulipRoadId = null,
60335         flowerRoadId = 'w646',
60336         tulipRoadStart = [-85.6297754121684, 41.95805253325314],
60337         tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204],
60338         tulipRoadIntersection = [-85.62974496187628, 41.95742515554585],
60339         roadCategory = context.presets().item('category-road'),
60340         residentialPreset = context.presets().item('highway/residential'),
60341         woodRoadId = 'w525',
60342         woodRoadEndId = 'n2862',
60343         woodRoadAddNode = [-85.62390110349587, 41.95397111462291],
60344         woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487],
60345         woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872],
60346         washingtonStreetId = 'w522',
60347         twelfthAvenueId = 'w1',
60348         eleventhAvenueEndId = 'n3550',
60349         twelfthAvenueEndId = 'n5',
60350         washingtonSegmentId = null,
60351         eleventhAvenueEnd = context.entity(eleventhAvenueEndId).loc,
60352         twelfthAvenueEnd = context.entity(twelfthAvenueEndId).loc,
60353         deleteLinesLoc = [-85.6219395542764, 41.95228033922477],
60354         twelfthAvenue = [-85.62219310052491, 41.952505413152956];
60355
60356
60357     var chapter = {
60358         title: 'intro.lines.title'
60359     };
60360
60361
60362     function timeout$$1(f, t$$1) {
60363         timeouts.push(window.setTimeout(f, t$$1));
60364     }
60365
60366
60367     function eventCancel() {
60368         event.stopPropagation();
60369         event.preventDefault();
60370     }
60371
60372
60373     function revealEditMenu(loc, text$$1, options) {
60374         var rect = context.surfaceRect();
60375         var point = context.curtainProjection(loc);
60376         var pad$$1 = 40;
60377         var width = 250 + (2 * pad$$1);
60378         var height = 350;
60379         var startX = rect.left + point[0];
60380         var left = (textDirection === 'rtl') ? (startX - width + pad$$1) : (startX - pad$$1);
60381         var box = {
60382             left: left,
60383             top: point[1] + rect.top - 60,
60384             width: width,
60385             height: height
60386         };
60387         reveal(box, text$$1, options);
60388     }
60389
60390
60391     function addLine() {
60392         context.enter(modeBrowse(context));
60393         context.history().reset('initial');
60394
60395         var msec = transitionTime(tulipRoadStart, context.map().center());
60396         if (msec) { reveal(null, null, { duration: 0 }); }
60397         context.map().zoom(18.5).centerEase(tulipRoadStart, msec);
60398
60399         timeout$$1(function() {
60400             var tooltip = reveal('button.add-line',
60401                 t('intro.lines.add_line', { button: icon('#icon-line', 'pre-text') }));
60402
60403             tooltip.selectAll('.tooltip-inner')
60404                 .insert('svg', 'span')
60405                 .attr('class', 'tooltip-illustration')
60406                 .append('use')
60407                 .attr('xlink:href', '#feature-images');
60408
60409             context.on('enter.intro', function(mode) {
60410                 if (mode.id !== 'add-line') return;
60411                 continueTo(startLine);
60412             });
60413         }, msec + 100);
60414
60415         function continueTo(nextStep) {
60416             context.on('enter.intro', null);
60417             nextStep();
60418         }
60419     }
60420
60421
60422     function startLine() {
60423         if (context.mode().id !== 'add-line') {
60424             return chapter.restart();
60425         }
60426
60427         tulipRoadId = null;
60428
60429         var padding = 70 * Math.pow(2, context.map().zoom() - 18);
60430         var box = pad$1(tulipRoadStart, padding, context);
60431         box.height = box.height + 100;
60432         reveal(box, t('intro.lines.start_line'));
60433
60434         context.map().on('move.intro drawn.intro', function() {
60435             padding = 70 * Math.pow(2, context.map().zoom() - 18);
60436             box = pad$1(tulipRoadStart, padding, context);
60437             box.height = box.height + 100;
60438             reveal(box, t('intro.lines.start_line'), { duration: 0 });
60439         });
60440
60441         context.on('enter.intro', function(mode) {
60442             if (mode.id !== 'draw-line') return chapter.restart();
60443             continueTo(drawLine);
60444         });
60445
60446         function continueTo(nextStep) {
60447             context.map().on('move.intro drawn.intro', null);
60448             context.on('enter.intro', null);
60449             nextStep();
60450         }
60451     }
60452
60453
60454     function drawLine() {
60455         if (context.mode().id !== 'draw-line') {
60456             return chapter.restart();
60457         }
60458
60459         tulipRoadId = context.mode().selectedIDs()[0];
60460         context.map().centerEase(tulipRoadMidpoint, 500);
60461
60462         timeout$$1(function() {
60463             var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
60464             var box = pad$1(tulipRoadMidpoint, padding, context);
60465             box.height = box.height * 2;
60466             reveal(box,
60467                 t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') })
60468             );
60469
60470             context.map().on('move.intro drawn.intro', function() {
60471                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
60472                 box = pad$1(tulipRoadMidpoint, padding, context);
60473                 box.height = box.height * 2;
60474                 reveal(box,
60475                     t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') }),
60476                     { duration: 0 }
60477                 );
60478             });
60479         }, 550);  // after easing..
60480
60481         context.history().on('change.intro', function() {
60482             var entity = tulipRoadId && context.hasEntity(tulipRoadId);
60483             if (!entity) return chapter.restart();
60484
60485             if (isLineConnected()) {
60486                 continueTo(continueLine);
60487             }
60488         });
60489
60490         context.on('enter.intro', function(mode) {
60491             if (mode.id === 'draw-line')
60492                 return;
60493             else if (mode.id === 'select') {
60494                 continueTo(retryIntersect);
60495                 return;
60496             }
60497             else
60498                 return chapter.restart();
60499         });
60500
60501         function continueTo(nextStep) {
60502             context.map().on('move.intro drawn.intro', null);
60503             context.history().on('change.intro', null);
60504             context.on('enter.intro', null);
60505             nextStep();
60506         }
60507     }
60508
60509
60510     function isLineConnected() {
60511         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
60512         if (!entity) return false;
60513
60514         var drawNodes = context.graph().childNodes(entity);
60515         return lodash.some(drawNodes, function(node) {
60516             return lodash.some(context.graph().parentWays(node), function(parent) {
60517                 return parent.id === flowerRoadId;
60518             });
60519         });
60520     }
60521
60522
60523     function retryIntersect() {
60524         select(window).on('mousedown.intro', eventCancel, true);
60525
60526         var box = pad$1(tulipRoadIntersection, 80, context);
60527         reveal(box,
60528             t('intro.lines.retry_intersect', { name: t('intro.graph.name.flower-street') })
60529         );
60530
60531         timeout$$1(chapter.restart, 3000);
60532     }
60533
60534
60535     function continueLine() {
60536         if (context.mode().id !== 'draw-line') return chapter.restart();
60537         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
60538         if (!entity) return chapter.restart();
60539
60540         context.map().centerEase(tulipRoadIntersection, 500);
60541
60542         reveal('#surface', t('intro.lines.continue_line'));
60543
60544         context.on('enter.intro', function(mode) {
60545             if (mode.id === 'draw-line')
60546                 return;
60547             else if (mode.id === 'select')
60548                 return continueTo(chooseCategoryRoad);
60549             else
60550                 return chapter.restart();
60551         });
60552
60553         function continueTo(nextStep) {
60554             context.on('enter.intro', null);
60555             nextStep();
60556         }
60557     }
60558
60559
60560     function chooseCategoryRoad() {
60561         if (context.mode().id !== 'select') {
60562             return chapter.restart();
60563         }
60564
60565         context.on('exit.intro', function() {
60566             return chapter.restart();
60567         });
60568
60569         var button = select('.preset-category-road .preset-list-button');
60570         if (button.empty()) return chapter.restart();
60571
60572         timeout$$1(function() {
60573             reveal(button.node(),
60574                 t('intro.lines.choose_category_road', { category: roadCategory.name() })
60575             );
60576             button.on('click.intro', function() { continueTo(choosePresetResidential); });
60577         }, 500);
60578
60579         function continueTo(nextStep) {
60580             select('.preset-list-button').on('click.intro', null);
60581             context.on('exit.intro', null);
60582             nextStep();
60583         }
60584     }
60585
60586
60587     function choosePresetResidential() {
60588         if (context.mode().id !== 'select') {
60589             return chapter.restart();
60590         }
60591
60592         context.on('exit.intro', function() {
60593             return chapter.restart();
60594         });
60595
60596         var subgrid = select('.preset-category-road .subgrid');
60597         if (subgrid.empty()) return chapter.restart();
60598
60599         subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button')
60600             .on('click.intro', function() {
60601                 continueTo(retryPresetResidential);
60602             });
60603
60604         subgrid.selectAll('.preset-highway-residential .preset-list-button')
60605             .on('click.intro', function() {
60606                 continueTo(nameRoad);
60607             });
60608
60609         timeout$$1(function() {
60610             reveal(subgrid.node(),
60611                 t('intro.lines.choose_preset_residential', { preset: residentialPreset.name() }),
60612                 { tooltipBox: '.preset-highway-residential .preset-list-button', duration: 300 }
60613             );
60614         }, 300);
60615
60616         function continueTo(nextStep) {
60617             select('.preset-list-button').on('click.intro', null);
60618             context.on('exit.intro', null);
60619             nextStep();
60620         }
60621     }
60622
60623
60624     // selected wrong road type
60625     function retryPresetResidential() {
60626         if (context.mode().id !== 'select') {
60627             return chapter.restart();
60628         }
60629
60630         context.on('exit.intro', function() {
60631             return chapter.restart();
60632         });
60633
60634         timeout$$1(function() {
60635             var button = select('.entity-editor-pane .preset-list-button');
60636             reveal(button.node(),
60637                 t('intro.lines.retry_preset_residential', { preset: residentialPreset.name() })
60638             );
60639             button.on('click.intro', function() {
60640                 continueTo(chooseCategoryRoad);
60641             });
60642         }, 500);
60643
60644         function continueTo(nextStep) {
60645             select('.preset-list-button').on('click.intro', null);
60646             context.on('exit.intro', null);
60647             nextStep();
60648         }
60649     }
60650
60651
60652     function nameRoad() {
60653         context.on('exit.intro', function() {
60654             continueTo(didNameRoad);
60655         });
60656
60657         timeout$$1(function() {
60658             reveal('.entity-editor-pane',
60659                 t('intro.lines.name_road', { button: icon('#icon-apply', 'pre-text') }),
60660                 { tooltipClass: 'intro-lines-name_road' }
60661             );
60662         }, 500);
60663
60664         function continueTo(nextStep) {
60665             context.on('exit.intro', null);
60666             nextStep();
60667         }
60668     }
60669
60670
60671     function didNameRoad() {
60672         context.history().checkpoint('doneAddLine');
60673
60674         timeout$$1(function() {
60675             reveal('#surface', t('intro.lines.did_name_road'), {
60676                 buttonText: t('intro.ok'),
60677                 buttonCallback: function() { continueTo(updateLine); }
60678             });
60679         }, 500);
60680
60681         function continueTo(nextStep) {
60682             nextStep();
60683         }
60684     }
60685
60686
60687     function updateLine() {
60688         context.history().reset('doneAddLine');
60689         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60690             return chapter.restart();
60691         }
60692
60693         var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
60694         if (msec) { reveal(null, null, { duration: 0 }); }
60695         context.map().zoom(19).centerEase(woodRoadDragMidpoint, msec);
60696
60697         timeout$$1(function() {
60698             var padding = 250 * Math.pow(2, context.map().zoom() - 19);
60699             var box = pad$1(woodRoadDragMidpoint, padding, context);
60700             var advance = function() { continueTo(addNode); };
60701
60702             reveal(box, t('intro.lines.update_line'),
60703                 { buttonText: t('intro.ok'), buttonCallback: advance }
60704             );
60705
60706             context.map().on('move.intro drawn.intro', function() {
60707                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
60708                 var box = pad$1(woodRoadDragMidpoint, padding, context);
60709                 reveal(box, t('intro.lines.update_line'),
60710                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
60711                 );
60712             });
60713         }, msec + 100);
60714
60715         function continueTo(nextStep) {
60716             context.map().on('move.intro drawn.intro', null);
60717             nextStep();
60718         }
60719     }
60720
60721
60722     function addNode() {
60723         context.history().reset('doneAddLine');
60724         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60725             return chapter.restart();
60726         }
60727
60728         var padding = 40 * Math.pow(2, context.map().zoom() - 19);
60729         var box = pad$1(woodRoadAddNode, padding, context);
60730         reveal(box, t('intro.lines.add_node'));
60731
60732         context.map().on('move.intro drawn.intro', function() {
60733             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
60734             var box = pad$1(woodRoadAddNode, padding, context);
60735             reveal(box, t('intro.lines.add_node'), { duration: 0 });
60736         });
60737
60738         context.history().on('change.intro', function(changed) {
60739             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60740                 return continueTo(updateLine);
60741             }
60742             if (changed.created().length === 1) {
60743                 timeout$$1(function() { continueTo(startDragEndpoint); }, 500);
60744             }
60745         });
60746
60747         context.on('enter.intro', function(mode) {
60748             if (mode.id !== 'select') {
60749                 continueTo(updateLine);
60750             }
60751         });
60752
60753         function continueTo(nextStep) {
60754             context.map().on('move.intro drawn.intro', null);
60755             context.history().on('change.intro', null);
60756             context.on('enter.intro', null);
60757             nextStep();
60758         }
60759     }
60760
60761
60762     function startDragEndpoint() {
60763         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60764             return continueTo(updateLine);
60765         }
60766         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
60767             context.enter(modeSelect(context, [woodRoadId]));
60768         }
60769
60770         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
60771         var box = pad$1(woodRoadDragEndpoint, padding, context);
60772         reveal(box, t('intro.lines.start_drag_endpoint'));
60773
60774         context.map().on('move.intro drawn.intro', function() {
60775             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60776                 return continueTo(updateLine);
60777             }
60778             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
60779             var box = pad$1(woodRoadDragEndpoint, padding, context);
60780             reveal(box, t('intro.lines.start_drag_endpoint'), { duration: 0 });
60781
60782             var entity = context.entity(woodRoadEndId);
60783             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
60784                 continueTo(finishDragEndpoint);
60785             }
60786         });
60787
60788         context.on('enter.intro', function(mode) {
60789             if (mode.id !== 'select') {
60790                 // keep Wood Road selected so endpoint stays draggable..
60791                 context.enter(modeSelect(context, [woodRoadId]));
60792             }
60793         });
60794
60795         function continueTo(nextStep) {
60796             context.map().on('move.intro drawn.intro', null);
60797             context.on('enter.intro', null);
60798             nextStep();
60799         }
60800     }
60801
60802
60803     function finishDragEndpoint() {
60804         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60805             return continueTo(updateLine);
60806         }
60807
60808         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
60809         var box = pad$1(woodRoadDragEndpoint, padding, context);
60810         reveal(box, t('intro.lines.finish_drag_endpoint'));
60811
60812         context.map().on('move.intro drawn.intro', function() {
60813             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60814                 return continueTo(updateLine);
60815             }
60816             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
60817             var box = pad$1(woodRoadDragEndpoint, padding, context);
60818             reveal(box, t('intro.lines.finish_drag_endpoint'), { duration: 0 });
60819
60820             var entity = context.entity(woodRoadEndId);
60821             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
60822                 continueTo(startDragEndpoint);
60823             }
60824         });
60825
60826         context.on('enter.intro', function() {
60827             continueTo(startDragMidpoint);
60828         });
60829
60830         function continueTo(nextStep) {
60831             context.map().on('move.intro drawn.intro', null);
60832             context.on('enter.intro', null);
60833             nextStep();
60834         }
60835     }
60836
60837
60838     function startDragMidpoint() {
60839         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60840             return continueTo(updateLine);
60841         }
60842         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
60843             context.enter(modeSelect(context, [woodRoadId]));
60844         }
60845
60846         var padding = 80 * Math.pow(2, context.map().zoom() - 19);
60847         var box = pad$1(woodRoadDragMidpoint, padding, context);
60848         reveal(box, t('intro.lines.start_drag_midpoint'));
60849
60850         context.map().on('move.intro drawn.intro', function() {
60851             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60852                 return continueTo(updateLine);
60853             }
60854             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
60855             var box = pad$1(woodRoadDragMidpoint, padding, context);
60856             reveal(box, t('intro.lines.start_drag_midpoint'), { duration: 0 });
60857         });
60858
60859         context.history().on('change.intro', function(changed) {
60860             if (changed.created().length === 1) {
60861                 continueTo(continueDragMidpoint);
60862             }
60863         });
60864
60865         context.on('enter.intro', function(mode) {
60866             if (mode.id !== 'select') {
60867                 // keep Wood Road selected so midpoint triangles are drawn..
60868                 context.enter(modeSelect(context, [woodRoadId]));
60869             }
60870         });
60871
60872         function continueTo(nextStep) {
60873             context.map().on('move.intro drawn.intro', null);
60874             context.history().on('change.intro', null);
60875             context.on('enter.intro', null);
60876             nextStep();
60877         }
60878     }
60879
60880
60881     function continueDragMidpoint() {
60882         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60883             return continueTo(updateLine);
60884         }
60885
60886         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
60887         var box = pad$1(woodRoadDragEndpoint, padding, context);
60888         box.height += 400;
60889
60890         var advance = function() {
60891             context.history().checkpoint('doneUpdateLine');
60892             continueTo(deleteLines);
60893         };
60894
60895         reveal(box, t('intro.lines.continue_drag_midpoint'),
60896             { buttonText: t('intro.ok'), buttonCallback: advance }
60897         );
60898
60899         context.map().on('move.intro drawn.intro', function() {
60900             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60901                 return continueTo(updateLine);
60902             }
60903             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
60904             var box = pad$1(woodRoadDragEndpoint, padding, context);
60905             box.height += 400;
60906             reveal(box, t('intro.lines.continue_drag_midpoint'),
60907                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
60908             );
60909         });
60910
60911         function continueTo(nextStep) {
60912             context.map().on('move.intro drawn.intro', null);
60913             nextStep();
60914         }
60915     }
60916
60917
60918     function deleteLines() {
60919         context.history().reset('doneUpdateLine');
60920         context.enter(modeBrowse(context));
60921
60922         if (!context.hasEntity(washingtonStreetId) ||
60923             !context.hasEntity(twelfthAvenueId) ||
60924             !context.hasEntity(eleventhAvenueEndId)) {
60925             return chapter.restart();
60926         }
60927
60928         var msec = transitionTime(deleteLinesLoc, context.map().center());
60929         if (msec) { reveal(null, null, { duration: 0 }); }
60930         context.map().zoom(18).centerEase(deleteLinesLoc, msec);
60931
60932         timeout$$1(function() {
60933             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
60934             var box = pad$1(deleteLinesLoc, padding, context);
60935             box.top -= 200;
60936             box.height += 400;
60937             var advance = function() { continueTo(rightClickIntersection); };
60938
60939             reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
60940                 { buttonText: t('intro.ok'), buttonCallback: advance }
60941             );
60942
60943             context.map().on('move.intro drawn.intro', function() {
60944                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
60945                 var box = pad$1(deleteLinesLoc, padding, context);
60946                 box.top -= 200;
60947                 box.height += 400;
60948                 reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
60949                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
60950                 );
60951             });
60952
60953             context.history().on('change.intro', function() {
60954                 timeout$$1(function() {
60955                     continueTo(deleteLines);
60956                 }, 500);  // after any transition (e.g. if user deleted intersection)
60957             });
60958
60959         }, msec + 100);
60960
60961         function continueTo(nextStep) {
60962             context.map().on('move.intro drawn.intro', null);
60963             context.history().on('change.intro', null);
60964             nextStep();
60965         }
60966     }
60967
60968
60969     function rightClickIntersection() {
60970         context.history().reset('doneUpdateLine');
60971         context.enter(modeBrowse(context));
60972
60973         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
60974
60975         timeout$$1(function() {
60976             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
60977             var box = pad$1(eleventhAvenueEnd, padding, context);
60978             reveal(box, t('intro.lines.rightclick_intersection',
60979                 { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') })
60980             );
60981
60982             context.map().on('move.intro drawn.intro', function() {
60983                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
60984                 var box = pad$1(eleventhAvenueEnd, padding, context);
60985                 reveal(box, t('intro.lines.rightclick_intersection',
60986                     { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') }),
60987                     { duration: 0 }
60988                 );
60989             });
60990
60991             context.on('enter.intro', function(mode) {
60992                 if (mode.id !== 'select') return;
60993                 var ids = context.selectedIDs();
60994                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndId) return;
60995
60996                 timeout$$1(function() {
60997                     var node = selectMenuItem('split').node();
60998                     if (!node) return;
60999                     continueTo(splitIntersection);
61000                 }, 300);  // after menu visible
61001             });
61002
61003             context.history().on('change.intro', function() {
61004                 timeout$$1(function() {
61005                     continueTo(deleteLines);
61006                 }, 300);  // after any transition (e.g. if user deleted intersection)
61007             });
61008
61009         }, 600);
61010
61011         function continueTo(nextStep) {
61012             context.map().on('move.intro drawn.intro', null);
61013             context.on('enter.intro', null);
61014             context.history().on('change.intro', null);
61015             nextStep();
61016         }
61017     }
61018
61019
61020     function splitIntersection() {
61021         if (!context.hasEntity(washingtonStreetId) ||
61022             !context.hasEntity(twelfthAvenueId) ||
61023             !context.hasEntity(eleventhAvenueEndId)) {
61024             return continueTo(deleteLines);
61025         }
61026
61027         var node = selectMenuItem('split').node();
61028         if (!node) { return continueTo(rightClickIntersection); }
61029
61030         var wasChanged = false;
61031         var menuCoords = context.map().mouseCoordinates();
61032         washingtonSegmentId = null;
61033
61034         revealEditMenu(menuCoords, t('intro.lines.split_intersection',
61035             { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') })
61036         );
61037
61038         context.map().on('move.intro drawn.intro', function() {
61039             var node = selectMenuItem('split').node();
61040             if (!wasChanged && !node) { return continueTo(rightClickIntersection); }
61041
61042             revealEditMenu(menuCoords, t('intro.lines.split_intersection',
61043                 { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') }),
61044                 { duration: 0 }
61045             );
61046         });
61047
61048         context.history().on('change.intro', function(changed) {
61049             wasChanged = true;
61050             timeout$$1(function() {
61051                 if (context.history().undoAnnotation() === t('operations.split.annotation.line')) {
61052                     washingtonSegmentId = changed.created()[0].id;
61053                     continueTo(didSplit);
61054                 } else {
61055                     washingtonSegmentId = null;
61056                     continueTo(retrySplit);
61057                 }
61058             }, 300);  // after any transition (e.g. if user deleted intersection)
61059         });
61060
61061         function continueTo(nextStep) {
61062             context.map().on('move.intro drawn.intro', null);
61063             context.history().on('change.intro', null);
61064             nextStep();
61065         }
61066     }
61067
61068
61069     function retrySplit() {
61070         context.enter(modeBrowse(context));
61071         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
61072         var advance = function() { continueTo(rightClickIntersection); };
61073
61074         var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61075         var box = pad$1(eleventhAvenueEnd, padding, context);
61076         reveal(box, t('intro.lines.retry_split'),
61077             { buttonText: t('intro.ok'), buttonCallback: advance }
61078         );
61079
61080         context.map().on('move.intro drawn.intro', function() {
61081             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61082             var box = pad$1(eleventhAvenueEnd, padding, context);
61083             reveal(box, t('intro.lines.retry_split'),
61084                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
61085             );
61086         });
61087
61088         function continueTo(nextStep) {
61089             context.map().on('move.intro drawn.intro', null);
61090             nextStep();
61091         }
61092     }
61093
61094
61095     function didSplit() {
61096         if (!washingtonSegmentId ||
61097             !context.hasEntity(washingtonSegmentId) ||
61098             !context.hasEntity(washingtonStreetId) ||
61099             !context.hasEntity(twelfthAvenueId) ||
61100             !context.hasEntity(eleventhAvenueEndId)) {
61101             return continueTo(rightClickIntersection);
61102         }
61103
61104         var ids = context.selectedIDs();
61105         var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
61106         var street = t('intro.graph.name.washington-street');
61107
61108         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61109         var box = pad$1(twelfthAvenue, padding, context);
61110         box.width = box.width / 2;
61111         reveal(box, t(string, { street1: street, street2: street }),
61112             { duration: 500 }
61113         );
61114
61115         timeout$$1(function() {
61116             context.map().zoom(18).centerEase(twelfthAvenue, 500);
61117
61118             context.map().on('move.intro drawn.intro', function() {
61119                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61120                 var box = pad$1(twelfthAvenue, padding, context);
61121                 box.width = box.width / 2;
61122                 reveal(box, t(string, { street1: street, street2: street }),
61123                     { duration: 0 }
61124                 );
61125             });
61126         }, 600);  // after initial reveal and curtain cut
61127
61128         context.on('enter.intro', function() {
61129             var ids = context.selectedIDs();
61130             if (ids.length === 1 && ids[0] === washingtonSegmentId) {
61131                 continueTo(multiSelect);
61132             }
61133         });
61134
61135         context.history().on('change.intro', function() {
61136             if (!washingtonSegmentId ||
61137                 !context.hasEntity(washingtonSegmentId) ||
61138                 !context.hasEntity(washingtonStreetId) ||
61139                 !context.hasEntity(twelfthAvenueId) ||
61140                 !context.hasEntity(eleventhAvenueEndId)) {
61141                 return continueTo(rightClickIntersection);
61142             }
61143         });
61144
61145         function continueTo(nextStep) {
61146             context.map().on('move.intro drawn.intro', null);
61147             context.on('enter.intro', null);
61148             context.history().on('change.intro', null);
61149             nextStep();
61150         }
61151     }
61152
61153
61154     function multiSelect() {
61155         if (!washingtonSegmentId ||
61156             !context.hasEntity(washingtonSegmentId) ||
61157             !context.hasEntity(washingtonStreetId) ||
61158             !context.hasEntity(twelfthAvenueId) ||
61159             !context.hasEntity(eleventhAvenueEndId)) {
61160             return continueTo(rightClickIntersection);
61161         }
61162
61163         var ids = context.selectedIDs();
61164         var hasWashington = ids.indexOf(washingtonSegmentId) !== -1;
61165         var hasTwelfth = ids.indexOf(twelfthAvenueId) !== -1;
61166
61167         if (hasWashington && hasTwelfth) {
61168             return continueTo(multiRightClick);
61169         } else if (!hasWashington && !hasTwelfth) {
61170             return continueTo(didSplit);
61171         }
61172
61173         context.map().zoom(18).centerEase(twelfthAvenue, 500);
61174
61175         timeout$$1(function() {
61176             var selected, other, padding, box;
61177             if (hasWashington) {
61178                 selected = t('intro.graph.name.washington-street');
61179                 other = t('intro.graph.name.12th-avenue');
61180                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
61181                 box = pad$1(twelfthAvenueEnd, padding, context);
61182                 box.width *= 3;
61183             } else {
61184                 selected = t('intro.graph.name.12th-avenue');
61185                 other = t('intro.graph.name.washington-street');
61186                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
61187                 box = pad$1(twelfthAvenue, padding, context);
61188                 box.width /= 2;
61189             }
61190
61191             reveal(box,
61192                 t('intro.lines.multi_select', { selected: selected, other1: other, other2: other })
61193             );
61194
61195             context.map().on('move.intro drawn.intro', function() {
61196                 if (hasWashington) {
61197                     selected = t('intro.graph.name.washington-street');
61198                     other = t('intro.graph.name.12th-avenue');
61199                     padding = 60 * Math.pow(2, context.map().zoom() - 18);
61200                     box = pad$1(twelfthAvenueEnd, padding, context);
61201                     box.width *= 3;
61202                 } else {
61203                     selected = t('intro.graph.name.12th-avenue');
61204                     other = t('intro.graph.name.washington-street');
61205                     padding = 200 * Math.pow(2, context.map().zoom() - 18);
61206                     box = pad$1(twelfthAvenue, padding, context);
61207                     box.width /= 2;
61208                 }
61209
61210                 reveal(box,
61211                     t('intro.lines.multi_select', { selected: selected, other1: other, other2: other }),
61212                     { duration: 0 }
61213                 );
61214             });
61215
61216             context.on('enter.intro', function() {
61217                 continueTo(multiSelect);
61218             });
61219
61220             context.history().on('change.intro', function() {
61221                 if (!washingtonSegmentId ||
61222                     !context.hasEntity(washingtonSegmentId) ||
61223                     !context.hasEntity(washingtonStreetId) ||
61224                     !context.hasEntity(twelfthAvenueId) ||
61225                     !context.hasEntity(eleventhAvenueEndId)) {
61226                     return continueTo(rightClickIntersection);
61227                 }
61228             });
61229         }, 600);
61230
61231         function continueTo(nextStep) {
61232             context.map().on('move.intro drawn.intro', null);
61233             context.on('enter.intro', null);
61234             context.history().on('change.intro', null);
61235             nextStep();
61236         }
61237     }
61238
61239
61240     function multiRightClick() {
61241         if (!washingtonSegmentId ||
61242             !context.hasEntity(washingtonSegmentId) ||
61243             !context.hasEntity(washingtonStreetId) ||
61244             !context.hasEntity(twelfthAvenueId) ||
61245             !context.hasEntity(eleventhAvenueEndId)) {
61246             return continueTo(rightClickIntersection);
61247         }
61248
61249         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61250         var box = pad$1(twelfthAvenue, padding, context);
61251         reveal(box, t('intro.lines.multi_rightclick'));
61252
61253         context.map().on('move.intro drawn.intro', function() {
61254             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61255             var box = pad$1(twelfthAvenue, padding, context);
61256             reveal(box, t('intro.lines.multi_rightclick'), { duration: 0 });
61257         });
61258
61259         select(window).on('click.intro contextmenu.intro', function() {
61260             timeout$$1(function() {
61261                 var ids = context.selectedIDs();
61262                 if (ids.length === 2 &&
61263                     ids.indexOf(twelfthAvenueId) !== -1 &&
61264                     ids.indexOf(washingtonSegmentId) !== -1) {
61265                         var node = selectMenuItem('delete').node();
61266                         if (!node) return;
61267                         continueTo(multiDelete);
61268                 } else if (ids.length === 1 &&
61269                     ids.indexOf(washingtonSegmentId) !== -1) {
61270                     return continueTo(multiSelect);
61271                 } else {
61272                     return continueTo(didSplit);
61273                 }
61274             }, 300);  // after edit menu visible
61275         }, true);
61276
61277         context.history().on('change.intro', function() {
61278             if (!washingtonSegmentId ||
61279                 !context.hasEntity(washingtonSegmentId) ||
61280                 !context.hasEntity(washingtonStreetId) ||
61281                 !context.hasEntity(twelfthAvenueId) ||
61282                 !context.hasEntity(eleventhAvenueEndId)) {
61283                 return continueTo(rightClickIntersection);
61284             }
61285         });
61286
61287         function continueTo(nextStep) {
61288             context.map().on('move.intro drawn.intro', null);
61289             select(window).on('click.intro contextmenu.intro', null, true);
61290             context.history().on('change.intro', null);
61291             nextStep();
61292         }
61293     }
61294
61295
61296     function multiDelete() {
61297         if (!washingtonSegmentId ||
61298             !context.hasEntity(washingtonSegmentId) ||
61299             !context.hasEntity(washingtonStreetId) ||
61300             !context.hasEntity(twelfthAvenueId) ||
61301             !context.hasEntity(eleventhAvenueEndId)) {
61302             return continueTo(rightClickIntersection);
61303         }
61304
61305         var node = selectMenuItem('delete').node();
61306         if (!node) return continueTo(multiRightClick);
61307
61308         var menuCoords = context.map().mouseCoordinates();
61309         revealEditMenu(menuCoords,
61310             t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') })
61311         );
61312
61313         context.map().on('move.intro drawn.intro', function() {
61314             revealEditMenu(menuCoords,
61315                 t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') }),
61316                 { duration: 0 }
61317             );
61318         });
61319
61320         context.on('exit.intro', function() {
61321             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
61322                 return continueTo(multiSelect);  // left select mode but roads still exist
61323             }
61324         });
61325
61326         context.history().on('change.intro', function() {
61327             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
61328                 continueTo(retryDelete);         // changed something but roads still exist
61329             } else {
61330                 continueTo(play);
61331             }
61332         });
61333
61334         function continueTo(nextStep) {
61335             context.map().on('move.intro drawn.intro', null);
61336             context.on('exit.intro', null);
61337             context.history().on('change.intro', null);
61338             nextStep();
61339         }
61340     }
61341
61342
61343     function retryDelete() {
61344         context.enter(modeBrowse(context));
61345
61346         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61347         var box = pad$1(twelfthAvenue, padding, context);
61348         reveal(box, t('intro.lines.retry_delete'), {
61349             buttonText: t('intro.ok'),
61350             buttonCallback: function() { continueTo(multiSelect); }
61351         });
61352
61353         function continueTo(nextStep) {
61354             nextStep();
61355         }
61356     }
61357
61358
61359     function play() {
61360         dispatch$$1.call('done');
61361         reveal('#id-container',
61362             t('intro.lines.play', { next: t('intro.buildings.title') }), {
61363                 tooltipBox: '.intro-nav-wrap .chapter-building',
61364                 buttonText: t('intro.ok'),
61365                 buttonCallback: function() { reveal('#id-container'); }
61366             }
61367         );
61368    }
61369
61370
61371     chapter.enter = function() {
61372         addLine();
61373     };
61374
61375
61376     chapter.exit = function() {
61377         timeouts.forEach(window.clearTimeout);
61378         select(window).on('mousedown.intro', null, true);
61379         context.on('enter.intro exit.intro', null);
61380         context.map().on('move.intro drawn.intro', null);
61381         context.history().on('change.intro', null);
61382         select('.preset-list-button').on('click.intro', null);
61383     };
61384
61385
61386     chapter.restart = function() {
61387         chapter.exit();
61388         chapter.enter();
61389     };
61390
61391
61392     return utilRebind(chapter, dispatch$$1, 'on');
61393 }
61394
61395 function uiIntroBuilding(context, reveal) {
61396     var dispatch$$1 = dispatch('done'),
61397         house = [-85.62815, 41.95638],
61398         tank = [-85.62732, 41.95347],
61399         buildingCatetory = context.presets().item('category-building'),
61400         housePreset = context.presets().item('building/house'),
61401         tankPreset = context.presets().item('man_made/storage_tank'),
61402         timeouts = [],
61403         houseId = null,
61404         tankId = null;
61405
61406
61407     var chapter = {
61408         title: 'intro.buildings.title'
61409     };
61410
61411
61412     function timeout$$1(f, t$$1) {
61413         timeouts.push(window.setTimeout(f, t$$1));
61414     }
61415
61416
61417     function eventCancel() {
61418         event.stopPropagation();
61419         event.preventDefault();
61420     }
61421
61422
61423     function revealHouse(center, text$$1, options) {
61424         var padding = 160 * Math.pow(2, context.map().zoom() - 20);
61425         var box = pad$1(center, padding, context);
61426         reveal(box, text$$1, options);
61427     }
61428
61429
61430     function revealTank(center, text$$1, options) {
61431         var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
61432         var box = pad$1(center, padding, context);
61433         reveal(box, text$$1, options);
61434     }
61435
61436
61437     function revealEditMenu(loc, text$$1, options) {
61438         var rect = context.surfaceRect();
61439         var point = context.curtainProjection(loc);
61440         var pad$$1 = 40;
61441         var width = 250 + (2 * pad$$1);
61442         var height = 350;
61443         var startX = rect.left + point[0];
61444         var left = (textDirection === 'rtl') ? (startX - width + pad$$1) : (startX - pad$$1);
61445         var box = {
61446             left: left,
61447             top: point[1] + rect.top - 60,
61448             width: width,
61449             height: height
61450         };
61451         reveal(box, text$$1, options);
61452     }
61453
61454
61455     function addHouse() {
61456         context.enter(modeBrowse(context));
61457         context.history().reset('initial');
61458         houseId = null;
61459
61460         var msec = transitionTime(house, context.map().center());
61461         if (msec) { reveal(null, null, { duration: 0 }); }
61462         context.map().zoom(19).centerEase(house, msec);
61463
61464         timeout$$1(function() {
61465             var tooltip = reveal('button.add-area',
61466                 t('intro.buildings.add_building', { button: icon('#icon-area', 'pre-text') }));
61467
61468             tooltip.selectAll('.tooltip-inner')
61469                 .insert('svg', 'span')
61470                 .attr('class', 'tooltip-illustration')
61471                 .append('use')
61472                 .attr('xlink:href', '#building-images');
61473
61474             context.on('enter.intro', function(mode) {
61475                 if (mode.id !== 'add-area') return;
61476                 continueTo(startHouse);
61477             });
61478         }, msec + 100);
61479
61480         function continueTo(nextStep) {
61481             context.on('enter.intro', null);
61482             nextStep();
61483         }
61484     }
61485
61486
61487     function startHouse() {
61488         if (context.mode().id !== 'add-area') {
61489             return continueTo(addHouse);
61490         }
61491
61492         houseId = null;
61493         context.map().zoomEase(20, 500);
61494
61495         timeout$$1(function() {
61496             revealHouse(house, t('intro.buildings.start_building'));
61497
61498             context.map().on('move.intro drawn.intro', function() {
61499                 revealHouse(house, t('intro.buildings.start_building'), { duration: 0 });
61500             });
61501
61502             context.on('enter.intro', function(mode) {
61503                 if (mode.id !== 'draw-area') return chapter.restart();
61504                 continueTo(continueHouse);
61505             });
61506
61507         }, 550);  // after easing
61508
61509         function continueTo(nextStep) {
61510             context.map().on('move.intro drawn.intro', null);
61511             context.on('enter.intro', null);
61512             nextStep();
61513         }
61514     }
61515
61516
61517     function continueHouse() {
61518         if (context.mode().id !== 'draw-area') {
61519             return continueTo(addHouse);
61520         }
61521
61522         houseId = null;
61523
61524         revealHouse(house, t('intro.buildings.continue_building'));
61525
61526         context.map().on('move.intro drawn.intro', function() {
61527             revealHouse(house, t('intro.buildings.continue_building'), { duration: 0 });
61528         });
61529
61530         context.on('enter.intro', function(mode) {
61531             if (mode.id === 'draw-area') {
61532                 return;
61533             } else if (mode.id === 'select') {
61534                 var graph = context.graph(),
61535                     way = context.entity(context.selectedIDs()[0]),
61536                     nodes = graph.childNodes(way),
61537                     points = lodash.uniq(nodes).map(function(n) { return context.projection(n.loc); });
61538
61539                 if (isMostlySquare(points)) {
61540                     houseId = way.id;
61541                     return continueTo(chooseCategoryBuilding);
61542                 } else {
61543                     return continueTo(retryHouse);
61544                 }
61545
61546             } else {
61547                 return chapter.restart();
61548             }
61549         });
61550
61551         function continueTo(nextStep) {
61552             context.map().on('move.intro drawn.intro', null);
61553             context.on('enter.intro', null);
61554             nextStep();
61555         }
61556     }
61557
61558
61559     function retryHouse() {
61560         var onClick = function() { continueTo(addHouse); };
61561
61562         revealHouse(house, t('intro.buildings.retry_building'),
61563             { buttonText: t('intro.ok'), buttonCallback: onClick }
61564         );
61565
61566         context.map().on('move.intro drawn.intro', function() {
61567             revealHouse(house, t('intro.buildings.retry_building'),
61568                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
61569             );
61570         });
61571
61572         function continueTo(nextStep) {
61573             context.map().on('move.intro drawn.intro', null);
61574             nextStep();
61575         }
61576     }
61577
61578
61579     function chooseCategoryBuilding() {
61580         if (!houseId || !context.hasEntity(houseId)) {
61581             return addHouse();
61582         }
61583         var ids = context.selectedIDs();
61584         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
61585             context.enter(modeSelect(context, [houseId]));
61586         }
61587
61588         timeout$$1(function() {
61589             // reset pane, in case user somehow happened to change it..
61590             select('.inspector-wrap .panewrap').style('right', '-100%');
61591
61592             var button = select('.preset-category-building .preset-list-button');
61593
61594             reveal(button.node(),
61595                 t('intro.buildings.choose_category_building', { category: buildingCatetory.name() })
61596             );
61597
61598             button.on('click.intro', function() {
61599                 button.on('click.intro', null);
61600                 continueTo(choosePresetHouse);
61601             });
61602
61603         }, 400);  // after preset list pane visible..
61604
61605
61606         context.on('enter.intro', function(mode) {
61607             if (!houseId || !context.hasEntity(houseId)) {
61608                 return continueTo(addHouse);
61609             }
61610             var ids = context.selectedIDs();
61611             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
61612                 return continueTo(chooseCategoryBuilding);
61613             }
61614         });
61615
61616         function continueTo(nextStep) {
61617             select('.preset-list-button').on('click.intro', null);
61618             context.on('enter.intro', null);
61619             nextStep();
61620         }
61621     }
61622
61623
61624     function choosePresetHouse() {
61625         if (!houseId || !context.hasEntity(houseId)) {
61626             return addHouse();
61627         }
61628         var ids = context.selectedIDs();
61629         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
61630             context.enter(modeSelect(context, [houseId]));
61631         }
61632
61633         timeout$$1(function() {
61634             // reset pane, in case user somehow happened to change it..
61635             select('.inspector-wrap .panewrap').style('right', '-100%');
61636
61637             var button = select('.preset-building-house .preset-list-button');
61638
61639             reveal(button.node(),
61640                 t('intro.buildings.choose_preset_house', { preset: housePreset.name() }),
61641                 { duration: 300 }
61642             );
61643
61644             button.on('click.intro', function() {
61645                 button.on('click.intro', null);
61646                 continueTo(closeEditorHouse);
61647             });
61648         }, 400);  // after preset list pane visible..
61649
61650         context.on('enter.intro', function(mode) {
61651             if (!houseId || !context.hasEntity(houseId)) {
61652                 return continueTo(addHouse);
61653             }
61654             var ids = context.selectedIDs();
61655             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
61656                 return continueTo(chooseCategoryBuilding);
61657             }
61658         });
61659
61660         function continueTo(nextStep) {
61661             select('.preset-list-button').on('click.intro', null);
61662             context.on('enter.intro', null);
61663             nextStep();
61664         }
61665     }
61666
61667
61668     function closeEditorHouse() {
61669         if (!houseId || !context.hasEntity(houseId)) {
61670             return addHouse();
61671         }
61672         var ids = context.selectedIDs();
61673         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
61674             context.enter(modeSelect(context, [houseId]));
61675         }
61676
61677         context.history().checkpoint('hasHouse');
61678
61679         context.on('exit.intro', function() {
61680             continueTo(rightClickHouse);
61681         });
61682
61683         timeout$$1(function() {
61684             reveal('.entity-editor-pane',
61685                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
61686             );
61687         }, 500);
61688
61689         function continueTo(nextStep) {
61690             context.on('exit.intro', null);
61691             nextStep();
61692         }
61693     }
61694
61695
61696     function rightClickHouse() {
61697         if (!houseId) return chapter.restart();
61698
61699         context.enter(modeBrowse(context));
61700         context.history().reset('hasHouse');
61701         context.map().centerEase(house, 500);
61702
61703         timeout$$1(function() {
61704             if (context.map().zoom() < 20) {
61705                 context.map().zoomEase(20, 500);
61706             }
61707         }, 520);
61708
61709         context.on('enter.intro', function(mode) {
61710             if (mode.id !== 'select') return;
61711             var ids = context.selectedIDs();
61712             if (ids.length !== 1 || ids[0] !== houseId) return;
61713
61714             timeout$$1(function() {
61715                 var node = selectMenuItem('orthogonalize').node();
61716                 if (!node) return;
61717                 continueTo(clickSquare);
61718             }, 300);  // after menu visible
61719         });
61720
61721         context.map().on('move.intro drawn.intro', function() {
61722             revealHouse(house, t('intro.buildings.rightclick_building'), { duration: 0 });
61723         });
61724
61725         context.history().on('change.intro', function() {
61726             continueTo(rightClickHouse);
61727         });
61728
61729         function continueTo(nextStep) {
61730             context.on('enter.intro', null);
61731             context.map().on('move.intro drawn.intro', null);
61732             context.history().on('change.intro', null);
61733             nextStep();
61734         }
61735     }
61736
61737
61738     function clickSquare() {
61739         if (!houseId) return chapter.restart();
61740         var entity = context.hasEntity(houseId);
61741         if (!entity) return continueTo(rightClickHouse);
61742
61743         var node = selectMenuItem('orthogonalize').node();
61744         if (!node) { return continueTo(rightClickHouse); }
61745
61746         var wasChanged = false;
61747         var menuCoords = context.map().mouseCoordinates();
61748
61749         revealEditMenu(menuCoords,
61750             t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') })
61751         );
61752
61753         context.on('enter.intro', function(mode) {
61754             if (mode.id === 'browse') {
61755                 continueTo(rightClickHouse);
61756             } else if (mode.id === 'move' || mode.id === 'rotate') {
61757                 continueTo(retryClickSquare);
61758             }
61759         });
61760
61761         context.map().on('move.intro drawn.intro', function() {
61762             var node = selectMenuItem('orthogonalize').node();
61763             if (!wasChanged && !node) { return continueTo(rightClickHouse); }
61764
61765             revealEditMenu(menuCoords,
61766                 t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') }),
61767                 { duration: 0 }
61768             );
61769         });
61770
61771         context.history().on('change.intro', function() {
61772             wasChanged = true;
61773             context.history().on('change.intro', null);
61774
61775             // Something changed.  Wait for transition to complete and check undo annotation.
61776             timeout$$1(function() {
61777                 if (context.history().undoAnnotation() === t('operations.orthogonalize.annotation.area')) {
61778                     continueTo(doneSquare);
61779                 } else {
61780                     continueTo(retryClickSquare);
61781                 }
61782             }, 500);  // after transitioned actions
61783         });
61784
61785         function continueTo(nextStep) {
61786             context.on('enter.intro', null);
61787             context.map().on('move.intro drawn.intro', null);
61788             context.history().on('change.intro', null);
61789             nextStep();
61790         }
61791     }
61792
61793
61794     function retryClickSquare() {
61795         context.enter(modeBrowse(context));
61796
61797         revealHouse(house, t('intro.buildings.retry_square'), {
61798             buttonText: t('intro.ok'),
61799             buttonCallback: function() { continueTo(rightClickHouse); }
61800         });
61801
61802         function continueTo(nextStep) {
61803             nextStep();
61804         }
61805     }
61806
61807
61808     function doneSquare() {
61809         context.history().checkpoint('doneSquare');
61810
61811         revealHouse(house, t('intro.buildings.done_square'), {
61812             buttonText: t('intro.ok'),
61813             buttonCallback: function() { continueTo(addTank); }
61814         });
61815
61816         function continueTo(nextStep) {
61817             nextStep();
61818         }
61819     }
61820
61821
61822     function addTank() {
61823         context.enter(modeBrowse(context));
61824         context.history().reset('doneSquare');
61825         tankId = null;
61826
61827         var msec = transitionTime(tank, context.map().center());
61828         if (msec) { reveal(null, null, { duration: 0 }); }
61829         context.map().zoom(19.5).centerEase(tank, msec);
61830
61831         timeout$$1(function() {
61832             reveal('button.add-area',
61833                 t('intro.buildings.add_tank', { button: icon('#icon-area', 'pre-text') })
61834             );
61835
61836             context.on('enter.intro', function(mode) {
61837                 if (mode.id !== 'add-area') return;
61838                 continueTo(startTank);
61839             });
61840         }, msec + 100);
61841
61842         function continueTo(nextStep) {
61843             context.on('enter.intro', null);
61844             nextStep();
61845         }
61846     }
61847
61848
61849     function startTank() {
61850         if (context.mode().id !== 'add-area') {
61851             return continueTo(addTank);
61852         }
61853
61854         tankId = null;
61855
61856         timeout$$1(function() {
61857             revealTank(tank, t('intro.buildings.start_tank'));
61858
61859             context.map().on('move.intro drawn.intro', function() {
61860                 revealTank(tank, t('intro.buildings.start_tank'), { duration: 0 });
61861             });
61862
61863             context.on('enter.intro', function(mode) {
61864                 if (mode.id !== 'draw-area') return chapter.restart();
61865                 continueTo(continueTank);
61866             });
61867
61868         }, 550);  // after easing
61869
61870         function continueTo(nextStep) {
61871             context.map().on('move.intro drawn.intro', null);
61872             context.on('enter.intro', null);
61873             nextStep();
61874         }
61875     }
61876
61877
61878     function continueTank() {
61879         if (context.mode().id !== 'draw-area') {
61880             return continueTo(addTank);
61881         }
61882
61883         tankId = null;
61884
61885         revealTank(tank, t('intro.buildings.continue_tank'));
61886
61887         context.map().on('move.intro drawn.intro', function() {
61888             revealTank(tank, t('intro.buildings.continue_tank'), { duration: 0 });
61889         });
61890
61891         context.on('enter.intro', function(mode) {
61892             if (mode.id === 'draw-area') {
61893                 return;
61894             } else if (mode.id === 'select') {
61895                 tankId = context.selectedIDs()[0];
61896                 return continueTo(searchPresetTank);
61897             } else {
61898                 return continueTo(addTank);
61899             }
61900         });
61901
61902         function continueTo(nextStep) {
61903             context.map().on('move.intro drawn.intro', null);
61904             context.on('enter.intro', null);
61905             nextStep();
61906         }
61907     }
61908
61909
61910     function searchPresetTank() {
61911         if (!tankId || !context.hasEntity(tankId)) {
61912             return addTank();
61913         }
61914         var ids = context.selectedIDs();
61915         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
61916             context.enter(modeSelect(context, [tankId]));
61917         }
61918
61919         timeout$$1(function() {
61920             // reset pane, in case user somehow happened to change it..
61921             select('.inspector-wrap .panewrap').style('right', '-100%');
61922
61923             select('.preset-search-input')
61924                 .on('keydown.intro', null)
61925                 .on('keyup.intro', checkPresetSearch);
61926
61927             reveal('.preset-search-input',
61928                 t('intro.buildings.search_tank', { preset: tankPreset.name() })
61929             );
61930         }, 400);  // after preset list pane visible..
61931
61932         context.on('enter.intro', function(mode) {
61933             if (!tankId || !context.hasEntity(tankId)) {
61934                 return continueTo(addTank);
61935             }
61936
61937             var ids = context.selectedIDs();
61938             if (mode.id !== 'select' || !ids.length || ids[0] !== tankId) {
61939                 // keep the user's area selected..
61940                 context.enter(modeSelect(context, [tankId]));
61941
61942                 // reset pane, in case user somehow happened to change it..
61943                 select('.inspector-wrap .panewrap').style('right', '-100%');
61944
61945                 select('.preset-search-input')
61946                     .on('keydown.intro', null)
61947                     .on('keyup.intro', checkPresetSearch);
61948
61949                 reveal('.preset-search-input',
61950                     t('intro.buildings.search_tank', { preset: tankPreset.name() })
61951                 );
61952
61953                 context.history().on('change.intro', null);
61954             }
61955         });
61956
61957         function checkPresetSearch() {
61958             var first = select('.preset-list-item:first-child');
61959
61960             if (first.classed('preset-man_made-storage_tank')) {
61961                 reveal(first.select('.preset-list-button').node(),
61962                     t('intro.buildings.choose_tank', { preset: tankPreset.name() }),
61963                     { duration: 300 }
61964                 );
61965
61966                 select('.preset-search-input')
61967                     .on('keydown.intro', eventCancel, true)
61968                     .on('keyup.intro', null);
61969
61970                 context.history().on('change.intro', function() {
61971                     continueTo(closeEditorTank);
61972                 });
61973             }
61974         }
61975
61976         function continueTo(nextStep) {
61977             context.on('enter.intro', null);
61978             context.history().on('change.intro', null);
61979             select('.preset-search-input').on('keydown.intro keyup.intro', null);
61980             nextStep();
61981         }
61982     }
61983
61984
61985     function closeEditorTank() {
61986         if (!tankId || !context.hasEntity(tankId)) {
61987             return addTank();
61988         }
61989         var ids = context.selectedIDs();
61990         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
61991             context.enter(modeSelect(context, [tankId]));
61992         }
61993
61994         context.history().checkpoint('hasTank');
61995
61996         context.on('exit.intro', function() {
61997             continueTo(rightClickTank);
61998         });
61999
62000         timeout$$1(function() {
62001             reveal('.entity-editor-pane',
62002                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
62003             );
62004         }, 500);
62005
62006         function continueTo(nextStep) {
62007             context.on('exit.intro', null);
62008             nextStep();
62009         }
62010     }
62011
62012
62013     function rightClickTank() {
62014         if (!tankId) return continueTo(addTank);
62015
62016         context.enter(modeBrowse(context));
62017         context.history().reset('hasTank');
62018         context.map().centerEase(tank, 500);
62019
62020         timeout$$1(function() {
62021             context.on('enter.intro', function(mode) {
62022                 if (mode.id !== 'select') return;
62023                 var ids = context.selectedIDs();
62024                 if (ids.length !== 1 || ids[0] !== tankId) return;
62025
62026                 timeout$$1(function() {
62027                     var node = selectMenuItem('circularize').node();
62028                     if (!node) return;
62029                     continueTo(clickCircle);
62030                 }, 300);  // after menu visible
62031             });
62032
62033             revealTank(tank, t('intro.buildings.rightclick_tank'));
62034
62035             context.map().on('move.intro drawn.intro', function() {
62036                 revealTank(tank, t('intro.buildings.rightclick_tank'), { duration: 0 });
62037             });
62038
62039             context.history().on('change.intro', function() {
62040                 continueTo(rightClickTank);
62041             });
62042
62043         }, 600);
62044
62045         function continueTo(nextStep) {
62046             context.on('enter.intro', null);
62047             context.map().on('move.intro drawn.intro', null);
62048             context.history().on('change.intro', null);
62049             nextStep();
62050         }
62051     }
62052
62053
62054     function clickCircle() {
62055         if (!tankId) return chapter.restart();
62056         var entity = context.hasEntity(tankId);
62057         if (!entity) return continueTo(rightClickTank);
62058
62059         var node = selectMenuItem('circularize').node();
62060         if (!node) { return continueTo(rightClickTank); }
62061
62062         var wasChanged = false;
62063         var menuCoords = context.map().mouseCoordinates();
62064
62065         revealEditMenu(menuCoords,
62066             t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') })
62067         );
62068
62069         context.on('enter.intro', function(mode) {
62070             if (mode.id === 'browse') {
62071                 continueTo(rightClickTank);
62072             } else if (mode.id === 'move' || mode.id === 'rotate') {
62073                 continueTo(retryClickCircle);
62074             }
62075         });
62076
62077         context.map().on('move.intro drawn.intro', function() {
62078             var node = selectMenuItem('circularize').node();
62079             if (!wasChanged && !node) { return continueTo(rightClickTank); }
62080
62081             revealEditMenu(menuCoords,
62082                 t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') }),
62083                 { duration: 0 }
62084             );
62085         });
62086
62087         context.history().on('change.intro', function() {
62088             wasChanged = true;
62089             context.history().on('change.intro', null);
62090
62091             // Something changed.  Wait for transition to complete and check undo annotation.
62092             timeout$$1(function() {
62093                 if (context.history().undoAnnotation() === t('operations.circularize.annotation.area')) {
62094                     continueTo(play);
62095                 } else {
62096                     continueTo(retryClickCircle);
62097                 }
62098             }, 500);  // after transitioned actions
62099         });
62100
62101         function continueTo(nextStep) {
62102             context.on('enter.intro', null);
62103             context.map().on('move.intro drawn.intro', null);
62104             context.history().on('change.intro', null);
62105             nextStep();
62106         }
62107     }
62108
62109
62110     function retryClickCircle() {
62111         context.enter(modeBrowse(context));
62112
62113         revealTank(tank, t('intro.buildings.retry_circle'), {
62114             buttonText: t('intro.ok'),
62115             buttonCallback: function() { continueTo(rightClickTank); }
62116         });
62117
62118         function continueTo(nextStep) {
62119             nextStep();
62120         }
62121     }
62122
62123
62124     function play() {
62125         dispatch$$1.call('done');
62126         reveal('#id-container',
62127             t('intro.buildings.play', { next: t('intro.startediting.title') }), {
62128                 tooltipBox: '.intro-nav-wrap .chapter-startEditing',
62129                 buttonText: t('intro.ok'),
62130                 buttonCallback: function() { reveal('#id-container'); }
62131             }
62132         );
62133     }
62134
62135
62136     chapter.enter = function() {
62137         addHouse();
62138     };
62139
62140
62141     chapter.exit = function() {
62142         timeouts.forEach(window.clearTimeout);
62143         context.on('enter.intro exit.intro', null);
62144         context.map().on('move.intro drawn.intro', null);
62145         context.history().on('change.intro', null);
62146         select('.preset-search-input').on('keydown.intro keyup.intro', null);
62147         select('.more-fields .combobox-input').on('click.intro', null);
62148     };
62149
62150
62151     chapter.restart = function() {
62152         chapter.exit();
62153         chapter.enter();
62154     };
62155
62156
62157     return utilRebind(chapter, dispatch$$1, 'on');
62158 }
62159
62160 function uiIntroStartEditing(context, reveal) {
62161     var dispatch$$1 = dispatch('done', 'startEditing'),
62162         modalSelection = select(null);
62163
62164
62165     var chapter = {
62166         title: 'intro.startediting.title'
62167     };
62168
62169
62170     function showHelp() {
62171         reveal('.map-control.help-control',
62172             t('intro.startediting.help', { button: icon('#icon-help', 'pre-text') }), {
62173                 buttonText: t('intro.ok'),
62174                 buttonCallback: function() { showSave(); }
62175             }
62176         );
62177     }
62178
62179     function showSave() {
62180         reveal('#bar button.save',
62181             t('intro.startediting.save'), {
62182                 buttonText: t('intro.ok'),
62183                 buttonCallback: function() { showStart(); }
62184             }
62185         );
62186     }
62187
62188     function showStart() {
62189         modalSelection = uiModal(context.container());
62190
62191         modalSelection.select('.modal')
62192             .attr('class', 'modal-splash modal col6');
62193
62194         modalSelection.selectAll('.close').remove();
62195
62196         var startbutton = modalSelection.select('.content')
62197             .attr('class', 'fillL')
62198             .append('button')
62199                 .attr('class', 'modal-section huge-modal-button')
62200                 .on('click', function() {
62201                     modalSelection.remove();
62202                 });
62203
62204             startbutton
62205                 .append('svg')
62206                 .attr('class', 'illustration')
62207                 .append('use')
62208                 .attr('xlink:href', '#logo-walkthrough');
62209
62210             startbutton
62211                 .append('h2')
62212                 .text(t('intro.startediting.start'));
62213
62214         dispatch$$1.call('startEditing');
62215     }
62216
62217
62218     chapter.enter = function() {
62219         showHelp();
62220     };
62221
62222
62223     chapter.exit = function() {
62224         modalSelection.remove();
62225     };
62226
62227
62228     return utilRebind(chapter, dispatch$$1, 'on');
62229 }
62230
62231 var chapterUi = {
62232     welcome: uiIntroWelcome,
62233     navigation: uiIntroNavigation,
62234     point: uiIntroPoint,
62235     area: uiIntroArea,
62236     line: uiIntroLine,
62237     building: uiIntroBuilding,
62238     startEditing: uiIntroStartEditing
62239 };
62240
62241 var chapterFlow = [
62242     'welcome',
62243     'navigation',
62244     'point',
62245     'area',
62246     'line',
62247     'building',
62248     'startEditing'
62249 ];
62250
62251
62252 function uiIntro(context) {
62253     var introGraph = {},
62254         currChapter;
62255
62256
62257     // create entities for intro graph and localize names
62258     for (var id in dataIntroGraph) {
62259         introGraph[id] = osmEntity$$1(localize(dataIntroGraph[id]));
62260     }
62261
62262
62263     function intro(selection$$1) {
62264         context.enter(modeBrowse(context));
62265
62266         // Save current map state
62267         var history = context.history().toJSON(),
62268             hash = window.location.hash,
62269             center = context.map().center(),
62270             zoom$$1 = context.map().zoom(),
62271             background = context.background().baseLayerSource(),
62272             overlays = context.background().overlayLayerSources(),
62273             opacity = selectAll('#map .layer-background').style('opacity'),
62274             loadedTiles = context.connection().loadedTiles(),
62275             baseEntities = context.history().graph().base().entities,
62276             countryCode = services.geocoder.countryCode;
62277
62278         // Block saving
62279         context.inIntro(true);
62280
62281         // Load semi-real data used in intro
62282         context.connection().toggle(false).reset();
62283         context.history().reset();
62284         context.history().merge(values(coreGraph$$1().load(introGraph).entities));
62285         context.history().checkpoint('initial');
62286         context.background().bing();
62287         overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
62288
62289         // Mock geocoder
62290         services.geocoder.countryCode = function(location, callback) {
62291             callback(null, t('intro.graph.countrycode'));
62292         };
62293
62294         selectAll('#map .layer-background').style('opacity', 1);
62295
62296         var curtain = uiCurtain();
62297         selection$$1.call(curtain);
62298
62299         var chapters = chapterFlow.map(function(chapter, i) {
62300             var s = chapterUi[chapter](context, curtain.reveal)
62301                 .on('done', function() {
62302                     context.presets().init();  // clear away "recent" presets
62303
62304                     buttons.filter(function(d) {
62305                         return d.title === s.title;
62306                     }).classed('finished', true);
62307
62308                     if (i < chapterFlow.length - 1) {
62309                         var next = chapterFlow[i + 1];
62310                         select('button.chapter-' + next)
62311                             .classed('next', true);
62312                     }
62313                 });
62314             return s;
62315         });
62316
62317         chapters[chapters.length - 1].on('startEditing', function() {
62318             curtain.remove();
62319             navwrap.remove();
62320             selectAll('#map .layer-background').style('opacity', opacity);
62321             context.connection().toggle(true).reset().loadedTiles(loadedTiles);
62322             context.history().reset().merge(values(baseEntities));
62323             context.background().baseLayerSource(background);
62324             overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
62325             if (history) context.history().fromJSON(history, false);
62326             context.map().centerZoom(center, zoom$$1);
62327             window.location.replace(hash);
62328             services.geocoder.countryCode = countryCode;
62329             context.inIntro(false);
62330         });
62331
62332         var navwrap = selection$$1
62333             .append('div')
62334             .attr('class', 'intro-nav-wrap fillD');
62335
62336         navwrap
62337             .append('svg')
62338             .attr('class', 'intro-nav-wrap-logo')
62339             .append('use')
62340             .attr('xlink:href', '#logo-walkthrough');
62341
62342         var buttonwrap = navwrap
62343             .append('div')
62344             .attr('class', 'joined')
62345             .selectAll('button.chapter');
62346
62347         var buttons = buttonwrap
62348             .data(chapters)
62349             .enter()
62350             .append('button')
62351             .attr('class', function(d, i) { return 'chapter chapter-' + chapterFlow[i]; })
62352             .on('click', enterChapter);
62353
62354         buttons
62355             .append('span')
62356             .text(function(d) { return t(d.title); });
62357
62358         buttons
62359             .append('span')
62360             .attr('class', 'status')
62361             .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'));
62362
62363         enterChapter(chapters[0]);
62364
62365
62366         function enterChapter(newChapter) {
62367             if (currChapter) { currChapter.exit(); }
62368             context.enter(modeBrowse(context));
62369
62370             currChapter = newChapter;
62371             currChapter.enter();
62372
62373             buttons
62374                 .classed('next', false)
62375                 .classed('active', function(d) {
62376                     return d.title === currChapter.title;
62377                 });
62378         }
62379     }
62380
62381
62382     return intro;
62383 }
62384
62385 function uiHelp(context) {
62386     var key = 'H';
62387
62388     var docKeys = [
62389         'help.help',
62390         'help.editing_saving',
62391         'help.roads',
62392         'help.gps',
62393         'help.imagery',
62394         'help.addresses',
62395         'help.inspector',
62396         'help.buildings',
62397         'help.relations'];
62398
62399     var docs = docKeys.map(function(key) {
62400         var text$$1 = t(key);
62401         return {
62402             title: text$$1.split('\n')[0].replace('#', '').trim(),
62403             html: marked(text$$1.split('\n').slice(1).join('\n'))
62404         };
62405     });
62406
62407
62408     function help(selection$$1) {
62409
62410         function hide() {
62411             setVisible(false);
62412         }
62413
62414
62415         function toggle() {
62416             if (event) event.preventDefault();
62417             tooltipBehavior.hide(button);
62418             setVisible(!button.classed('active'));
62419         }
62420
62421
62422         function setVisible(show) {
62423             if (show !== shown) {
62424                 button.classed('active', show);
62425                 shown = show;
62426
62427                 if (show) {
62428                     selection$$1.on('mousedown.help-inside', function() {
62429                         return event.stopPropagation();
62430                     });
62431                     pane.style('display', 'block')
62432                         .style('right', '-500px')
62433                         .transition()
62434                         .duration(200)
62435                         .style('right', '0px');
62436                 } else {
62437                     pane.style('right', '0px')
62438                         .transition()
62439                         .duration(200)
62440                         .style('right', '-500px')
62441                         .on('end', function() {
62442                             select(this).style('display', 'none');
62443                         });
62444                     selection$$1.on('mousedown.help-inside', null);
62445                 }
62446             }
62447         }
62448
62449
62450         function clickHelp(d, i) {
62451             var rtl = (textDirection === 'rtl');
62452             pane.property('scrollTop', 0);
62453             doctitle.html(d.title);
62454
62455             body.html(d.html);
62456             body.selectAll('a')
62457                 .attr('target', '_blank');
62458             menuItems.classed('selected', function(m) {
62459                 return m.title === d.title;
62460             });
62461
62462             nav.html('');
62463             if (rtl) {
62464                 nav.call(drawNext).call(drawPrevious);
62465             } else {
62466                 nav.call(drawPrevious).call(drawNext);
62467             }
62468
62469
62470             function drawNext(selection$$1) {
62471                 if (i < docs.length - 1) {
62472                     var nextLink = selection$$1
62473                         .append('a')
62474                         .attr('class', 'next')
62475                         .on('click', function() {
62476                             clickHelp(docs[i + 1], i + 1);
62477                         });
62478
62479                     nextLink
62480                         .append('span')
62481                         .text(docs[i + 1].title)
62482                         .call(svgIcon((rtl ? '#icon-backward' : '#icon-forward'), 'inline'));
62483                 }
62484             }
62485
62486
62487             function drawPrevious(selection$$1) {
62488                 if (i > 0) {
62489                     var prevLink = selection$$1
62490                         .append('a')
62491                         .attr('class', 'previous')
62492                         .on('click', function() {
62493                             clickHelp(docs[i - 1], i - 1);
62494                         });
62495
62496                     prevLink
62497                         .call(svgIcon((rtl ? '#icon-forward' : '#icon-backward'), 'inline'))
62498                         .append('span')
62499                         .text(docs[i - 1].title);
62500                 }
62501             }
62502         }
62503
62504
62505         function clickWalkthrough() {
62506             if (context.inIntro()) return;
62507             context.container().call(uiIntro(context));
62508             setVisible(false);
62509         }
62510
62511
62512         var pane = selection$$1.append('div')
62513                 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
62514             tooltipBehavior = tooltip()
62515                 .placement((textDirection === 'rtl') ? 'right' : 'left')
62516                 .html(true)
62517                 .title(uiTooltipHtml(t('help.title'), key)),
62518             button = selection$$1.append('button')
62519                 .attr('tabindex', -1)
62520                 .on('click', toggle)
62521                 .call(svgIcon('#icon-help', 'light'))
62522                 .call(tooltipBehavior),
62523             shown = false;
62524
62525
62526         var toc = pane.append('ul')
62527             .attr('class', 'toc');
62528
62529         var menuItems = toc.selectAll('li')
62530             .data(docs)
62531             .enter()
62532             .append('li')
62533             .append('a')
62534             .html(function(d) { return d.title; })
62535             .on('click', clickHelp);
62536
62537         var walkthrough = toc
62538             .append('li')
62539             .attr('class', 'walkthrough')
62540             .append('a')
62541             .on('click', clickWalkthrough);
62542
62543         walkthrough
62544             .append('svg')
62545             .attr('class', 'logo logo-walkthrough')
62546             .append('use')
62547             .attr('xlink:href', '#logo-walkthrough');
62548
62549         walkthrough
62550             .append('div')
62551             .text(t('splash.walkthrough'));
62552
62553
62554         var content = pane.append('div')
62555             .attr('class', 'left-content');
62556
62557         var doctitle = content.append('h2')
62558             .text(t('help.title'));
62559
62560         var body = content.append('div')
62561             .attr('class', 'body');
62562
62563         var nav = content.append('div')
62564             .attr('class', 'nav');
62565
62566         clickHelp(docs[0], 0);
62567
62568         var keybinding = d3keybinding('help')
62569             .on(key, toggle)
62570             .on('B', hide)
62571             .on('F', hide);
62572
62573         select(document)
62574             .call(keybinding);
62575
62576         context.surface().on('mousedown.help-outside', hide);
62577         context.container().on('mousedown.help-outside', hide);
62578     }
62579
62580     return help;
62581 }
62582
62583 function uiInfo(context) {
62584     var key = uiCmd('⌘I'),
62585         isImperial = (utilDetect().locale.toLowerCase() === 'en-us'),
62586         isHidden = true;
62587
62588
62589     function info(selection$$1) {
62590
62591         function radiansToMeters(r) {
62592             // using WGS84 authalic radius (6371007.1809 m)
62593             return r * 6371007.1809;
62594         }
62595
62596         function steradiansToSqmeters(r) {
62597             // http://gis.stackexchange.com/a/124857/40446
62598             return r / (4 * Math.PI) * 510065621724000;
62599         }
62600
62601
62602         function toLineString(feature) {
62603             if (feature.type === 'LineString') return feature;
62604
62605             var result = { type: 'LineString', coordinates: [] };
62606             if (feature.type === 'Polygon') {
62607                 result.coordinates = feature.coordinates[0];
62608             } else if (feature.type === 'MultiPolygon') {
62609                 result.coordinates = feature.coordinates[0][0];
62610             }
62611
62612             return result;
62613         }
62614
62615
62616         function displayLength(m) {
62617             var d = m * (isImperial ? 3.28084 : 1),
62618                 p, unit;
62619
62620             if (isImperial) {
62621                 if (d >= 5280) {
62622                     d /= 5280;
62623                     unit = 'mi';
62624                 } else {
62625                     unit = 'ft';
62626                 }
62627             } else {
62628                 if (d >= 1000) {
62629                     d /= 1000;
62630                     unit = 'km';
62631                 } else {
62632                     unit = 'm';
62633                 }
62634             }
62635
62636             // drop unnecessary precision
62637             p = d > 1000 ? 0 : d > 100 ? 1 : 2;
62638
62639             return String(d.toFixed(p)) + ' ' + unit;
62640         }
62641
62642
62643         function displayArea(m2) {
62644             var d = m2 * (isImperial ? 10.7639111056 : 1),
62645                 d1, d2, p1, p2, unit1, unit2;
62646
62647             if (isImperial) {
62648                 if (d >= 6969600) {     // > 0.25mi² show mi²
62649                     d1 = d / 27878400;
62650                     unit1 = 'mi²';
62651                 } else {
62652                     d1 = d;
62653                     unit1 = 'ft²';
62654                 }
62655
62656                 if (d > 4356 && d < 43560000) {   // 0.1 - 1000 acres
62657                     d2 = d / 43560;
62658                     unit2 = 'ac';
62659                 }
62660
62661             } else {
62662                 if (d >= 250000) {    // > 0.25km² show km²
62663                     d1 = d / 1000000;
62664                     unit1 = 'km²';
62665                 } else {
62666                     d1 = d;
62667                     unit1 = 'm²';
62668                 }
62669
62670                 if (d > 1000 && d < 10000000) {   // 0.1 - 1000 hectares
62671                     d2 = d / 10000;
62672                     unit2 = 'ha';
62673                 }
62674             }
62675
62676             // drop unnecessary precision
62677             p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
62678             p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
62679
62680             return String(d1.toFixed(p1)) + ' ' + unit1 +
62681                 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
62682         }
62683
62684
62685         function redraw() {
62686             if (isHidden) return;
62687
62688             var resolver = context.graph(),
62689                 selected = lodash.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
62690                 singular = selected.length === 1 ? selected[0] : null,
62691                 extent$$1 = geoExtent$$1(),
62692                 entity;
62693
62694             wrap.html('');
62695             wrap.append('h4')
62696                 .attr('class', 'infobox-heading fillD')
62697                 .text(singular || t('infobox.selected', { n: selected.length }));
62698
62699             if (!selected.length) return;
62700
62701             var center;
62702             for (var i = 0; i < selected.length; i++) {
62703                 entity = context.entity(selected[i]);
62704                 extent$$1._extend(entity.extent(resolver));
62705             }
62706             center = extent$$1.center();
62707
62708
62709             var list = wrap.append('ul');
62710
62711             // multiple features, just display extent center..
62712             if (!singular) {
62713                 list.append('li')
62714                     .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
62715                 return;
62716             }
62717
62718             // single feature, display details..
62719             if (!entity) return;
62720             var geometry = entity.geometry(resolver);
62721
62722             if (geometry === 'line' || geometry === 'area') {
62723                 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
62724                     feature = entity.asGeoJSON(resolver),
62725                     length = radiansToMeters(d3GeoLength(toLineString(feature))),
62726                     lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
62727                     centroid = d3GeoCentroid(feature);
62728
62729                 list.append('li')
62730                     .text(t('infobox.geometry') + ': ' +
62731                         (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
62732
62733                 if (closed) {
62734                     var area$$1 = steradiansToSqmeters(entity.area(resolver));
62735                     list.append('li')
62736                         .text(t('infobox.area') + ': ' + displayArea(area$$1));
62737                 }
62738
62739                 list.append('li')
62740                     .text(lengthLabel + ': ' + displayLength(length));
62741
62742                 list.append('li')
62743                     .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
62744
62745
62746                 var toggle  = isImperial ? 'imperial' : 'metric';
62747                 wrap.append('a')
62748                     .text(t('infobox.' + toggle))
62749                     .attr('href', '#')
62750                     .attr('class', 'button')
62751                     .on('click', function() {
62752                         event.preventDefault();
62753                         isImperial = !isImperial;
62754                         redraw();
62755                     });
62756
62757             } else {
62758                 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
62759
62760                 list.append('li')
62761                     .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
62762
62763                 list.append('li')
62764                     .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
62765             }
62766         }
62767
62768
62769         function toggle() {
62770             if (event) {
62771                 event.preventDefault();
62772             }
62773
62774             isHidden = !isHidden;
62775
62776             if (isHidden) {
62777                 wrap
62778                     .style('display', 'block')
62779                     .style('opacity', 1)
62780                     .transition()
62781                     .duration(200)
62782                     .style('opacity', 0)
62783                     .on('end', function() {
62784                         select(this).style('display', 'none');
62785                     });
62786             } else {
62787                 wrap
62788                     .style('display', 'block')
62789                     .style('opacity', 0)
62790                     .transition()
62791                     .duration(200)
62792                     .style('opacity', 1)
62793                     .on('end', function() {
62794                         redraw();
62795                     });
62796             }
62797         }
62798
62799
62800         var wrap = selection$$1.selectAll('.infobox')
62801             .data([0]);
62802
62803         wrap = wrap.enter()
62804             .append('div')
62805             .attr('class', 'infobox fillD2')
62806             .style('display', (isHidden ? 'none' : 'block'))
62807             .merge(wrap);
62808
62809         context.map()
62810             .on('drawn.info', redraw);
62811
62812         redraw();
62813
62814         var keybinding = d3keybinding('info')
62815             .on(key, toggle);
62816
62817         select(document)
62818             .call(keybinding);
62819     }
62820
62821     return info;
62822 }
62823
62824 function uiMapData(context) {
62825     var key = 'F',
62826         features = context.features().keys(),
62827         layers = context.layers(),
62828         fills = ['wireframe', 'partial', 'full'],
62829         fillDefault = context.storage('area-fill') || 'partial',
62830         fillSelected = fillDefault;
62831
62832
62833     function map_data(selection$$1) {
62834
62835         function showsFeature(d) {
62836             return context.features().enabled(d);
62837         }
62838
62839
62840         function autoHiddenFeature(d) {
62841             return context.features().autoHidden(d);
62842         }
62843
62844
62845         function clickFeature(d) {
62846             context.features().toggle(d);
62847             update();
62848         }
62849
62850
62851         function showsFill(d) {
62852             return fillSelected === d;
62853         }
62854
62855
62856         function setFill(d) {
62857             lodash.each(fills, function(opt) {
62858                 context.surface().classed('fill-' + opt, Boolean(opt === d));
62859             });
62860
62861             fillSelected = d;
62862             if (d !== 'wireframe') {
62863                 fillDefault = d;
62864                 context.storage('area-fill', d);
62865             }
62866             update();
62867         }
62868
62869
62870         function showsLayer(which) {
62871             var layer = layers.layer(which);
62872             if (layer) {
62873                 return layer.enabled();
62874             }
62875             return false;
62876         }
62877
62878
62879         function setLayer(which, enabled) {
62880             var layer = layers.layer(which);
62881             if (layer) {
62882                 layer.enabled(enabled);
62883                 update();
62884             }
62885         }
62886
62887
62888         function toggleLayer(which) {
62889             setLayer(which, !showsLayer(which));
62890         }
62891
62892
62893         function clickGpx() {
62894             toggleLayer('gpx');
62895         }
62896
62897
62898         function clickMapillaryImages() {
62899             toggleLayer('mapillary-images');
62900             if (!showsLayer('mapillary-images')) {
62901                 setLayer('mapillary-signs', false);
62902             }
62903         }
62904
62905
62906         function clickMapillarySigns() {
62907             toggleLayer('mapillary-signs');
62908         }
62909
62910
62911         function drawMapillaryItems(selection$$1) {
62912             var mapillaryImages = layers.layer('mapillary-images'),
62913                 mapillarySigns = layers.layer('mapillary-signs'),
62914                 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
62915                 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
62916                 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
62917                 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
62918
62919             var mapillaryList = selection$$1
62920                 .selectAll('.layer-list-mapillary')
62921                 .data([0]);
62922
62923             mapillaryList = mapillaryList.enter()
62924                 .append('ul')
62925                 .attr('class', 'layer-list layer-list-mapillary')
62926                 .merge(mapillaryList);
62927
62928
62929             var mapillaryImageLayerItem = mapillaryList
62930                 .selectAll('.list-item-mapillary-images')
62931                 .data(supportsMapillaryImages ? [0] : []);
62932
62933             mapillaryImageLayerItem.exit()
62934                 .remove();
62935
62936             var enterImages = mapillaryImageLayerItem.enter()
62937                 .append('li')
62938                 .attr('class', 'list-item-mapillary-images');
62939
62940             var labelImages = enterImages
62941                 .append('label')
62942                 .call(tooltip()
62943                     .title(t('mapillary_images.tooltip'))
62944                     .placement('top'));
62945
62946             labelImages
62947                 .append('input')
62948                 .attr('type', 'checkbox')
62949                 .on('change', clickMapillaryImages);
62950
62951             labelImages
62952                 .append('span')
62953                 .text(t('mapillary_images.title'));
62954
62955
62956             var mapillarySignLayerItem = mapillaryList
62957                 .selectAll('.list-item-mapillary-signs')
62958                 .data(supportsMapillarySigns ? [0] : []);
62959
62960             mapillarySignLayerItem.exit()
62961                 .remove();
62962
62963             var enterSigns = mapillarySignLayerItem.enter()
62964                 .append('li')
62965                 .attr('class', 'list-item-mapillary-signs');
62966
62967             var labelSigns = enterSigns
62968                 .append('label')
62969                 .call(tooltip()
62970                     .title(t('mapillary_signs.tooltip'))
62971                     .placement('top'));
62972
62973             labelSigns
62974                 .append('input')
62975                 .attr('type', 'checkbox')
62976                 .on('change', clickMapillarySigns);
62977
62978             labelSigns
62979                 .append('span')
62980                 .text(t('mapillary_signs.title'));
62981
62982
62983             // Updates
62984             mapillaryImageLayerItem = mapillaryImageLayerItem
62985                 .merge(enterImages);
62986
62987             mapillaryImageLayerItem
62988                 .classed('active', showsMapillaryImages)
62989                 .selectAll('input')
62990                 .property('checked', showsMapillaryImages);
62991
62992
62993             mapillarySignLayerItem = mapillarySignLayerItem
62994                 .merge(enterSigns);
62995
62996             mapillarySignLayerItem
62997                 .classed('active', showsMapillarySigns)
62998                 .selectAll('input')
62999                 .property('disabled', !showsMapillaryImages)
63000                 .property('checked', showsMapillarySigns);
63001
63002             mapillarySignLayerItem
63003                 .selectAll('label')
63004                 .classed('deemphasize', !showsMapillaryImages);
63005         }
63006
63007
63008         function drawGpxItem(selection$$1) {
63009             var gpx = layers.layer('gpx'),
63010                 hasGpx = gpx && gpx.hasGpx(),
63011                 showsGpx = hasGpx && gpx.enabled();
63012
63013             var gpxLayerItem = selection$$1
63014                 .selectAll('.layer-list-gpx')
63015                 .data(gpx ? [0] : []);
63016
63017             // Exit
63018             gpxLayerItem.exit()
63019                 .remove();
63020
63021             // Enter
63022             var enter = gpxLayerItem.enter()
63023                 .append('ul')
63024                 .attr('class', 'layer-list layer-list-gpx')
63025                 .append('li')
63026                 .classed('list-item-gpx', true);
63027
63028             enter
63029                 .append('button')
63030                 .attr('class', 'list-item-gpx-extent')
63031                 .call(tooltip()
63032                     .title(t('gpx.zoom'))
63033                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
63034                 .on('click', function() {
63035                     event.preventDefault();
63036                     event.stopPropagation();
63037                     gpx.fitZoom();
63038                 })
63039                 .call(svgIcon('#icon-search'));
63040
63041             enter
63042                 .append('button')
63043                 .attr('class', 'list-item-gpx-browse')
63044                 .call(tooltip()
63045                     .title(t('gpx.browse'))
63046                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
63047                 .on('click', function() {
63048                     select(document.createElement('input'))
63049                         .attr('type', 'file')
63050                         .on('change', function() {
63051                             gpx.files(event.target.files);
63052                         })
63053                         .node().click();
63054                 })
63055                 .call(svgIcon('#icon-geolocate'));
63056
63057             var labelGpx = enter
63058                 .append('label')
63059                 .call(tooltip().title(t('gpx.drag_drop')).placement('top'));
63060
63061             labelGpx
63062                 .append('input')
63063                 .attr('type', 'checkbox')
63064                 .on('change', clickGpx);
63065
63066             labelGpx
63067                 .append('span')
63068                 .text(t('gpx.local_layer'));
63069
63070
63071             // Update
63072             gpxLayerItem = gpxLayerItem
63073                 .merge(enter);
63074
63075             gpxLayerItem
63076                 .classed('active', showsGpx)
63077                 .selectAll('input')
63078                 .property('disabled', !hasGpx)
63079                 .property('checked', showsGpx);
63080
63081             gpxLayerItem
63082                 .selectAll('label')
63083                 .classed('deemphasize', !hasGpx);
63084         }
63085
63086
63087         function drawList(selection$$1, data, type, name, change, active$$1) {
63088             var items = selection$$1.selectAll('li')
63089                 .data(data);
63090
63091             // Exit
63092             items.exit()
63093                 .remove();
63094
63095             // Enter
63096             var enter = items.enter()
63097                 .append('li')
63098                 .attr('class', 'layer')
63099                 .call(tooltip()
63100                     .html(true)
63101                     .title(function(d) {
63102                         var tip = t(name + '.' + d + '.tooltip'),
63103                             key = (d === 'wireframe' ? 'W' : null);
63104
63105                         if (name === 'feature' && autoHiddenFeature(d)) {
63106                             tip += '<div>' + t('map_data.autohidden') + '</div>';
63107                         }
63108                         return uiTooltipHtml(tip, key);
63109                     })
63110                     .placement('top')
63111                 );
63112
63113             var label = enter
63114                 .append('label');
63115
63116             label
63117                 .append('input')
63118                 .attr('type', type)
63119                 .attr('name', name)
63120                 .on('change', change);
63121
63122             label
63123                 .append('span')
63124                 .text(function(d) { return t(name + '.' + d + '.description'); });
63125
63126             // Update
63127             items = items
63128                 .merge(enter);
63129
63130             items
63131                 .classed('active', active$$1)
63132                 .selectAll('input')
63133                 .property('checked', active$$1)
63134                 .property('indeterminate', function(d) {
63135                     return (name === 'feature' && autoHiddenFeature(d));
63136                 });
63137         }
63138
63139
63140         function update() {
63141             dataLayerContainer.call(drawMapillaryItems);
63142             dataLayerContainer.call(drawGpxItem);
63143
63144             fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
63145             featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
63146         }
63147
63148
63149         function hidePanel() {
63150             setVisible(false);
63151         }
63152
63153
63154         function togglePanel() {
63155             if (event) event.preventDefault();
63156             tooltipBehavior.hide(button);
63157             setVisible(!button.classed('active'));
63158         }
63159
63160
63161         function toggleWireframe() {
63162             if (event) {
63163                 event.preventDefault();
63164                 event.stopPropagation();
63165             }
63166             setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
63167             context.map().pan([0,0]);  // trigger a redraw
63168         }
63169
63170
63171         function setVisible(show) {
63172             if (show !== shown) {
63173                 button.classed('active', show);
63174                 shown = show;
63175
63176                 if (show) {
63177                     update();
63178                     selection$$1.on('mousedown.map_data-inside', function() {
63179                         return event.stopPropagation();
63180                     });
63181                     content.style('display', 'block')
63182                         .style('right', '-300px')
63183                         .transition()
63184                         .duration(200)
63185                         .style('right', '0px');
63186                 } else {
63187                     content.style('display', 'block')
63188                         .style('right', '0px')
63189                         .transition()
63190                         .duration(200)
63191                         .style('right', '-300px')
63192                         .on('end', function() {
63193                             select(this).style('display', 'none');
63194                         });
63195                     selection$$1.on('mousedown.map_data-inside', null);
63196                 }
63197             }
63198         }
63199
63200
63201         var content = selection$$1
63202                 .append('div')
63203                 .attr('class', 'fillL map-overlay col3 content hide'),
63204             tooltipBehavior = tooltip()
63205                 .placement((textDirection === 'rtl') ? 'right' : 'left')
63206                 .html(true)
63207                 .title(uiTooltipHtml(t('map_data.description'), key)),
63208             button = selection$$1
63209                 .append('button')
63210                 .attr('tabindex', -1)
63211                 .on('click', togglePanel)
63212                 .call(svgIcon('#icon-data', 'light'))
63213                 .call(tooltipBehavior),
63214             shown = false;
63215
63216         content
63217             .append('h4')
63218             .text(t('map_data.title'));
63219
63220
63221         // data layers
63222         content
63223             .append('a')
63224             .text(t('map_data.data_layers'))
63225             .attr('href', '#')
63226             .classed('hide-toggle', true)
63227             .classed('expanded', true)
63228             .on('click', function() {
63229                 var exp = select(this).classed('expanded');
63230                 dataLayerContainer.style('display', exp ? 'none' : 'block');
63231                 select(this).classed('expanded', !exp);
63232                 event.preventDefault();
63233             });
63234
63235         var dataLayerContainer = content
63236             .append('div')
63237             .attr('class', 'data-data-layers')
63238             .style('display', 'block');
63239
63240
63241         // area fills
63242         content
63243             .append('a')
63244             .text(t('map_data.fill_area'))
63245             .attr('href', '#')
63246             .classed('hide-toggle', true)
63247             .classed('expanded', false)
63248             .on('click', function() {
63249                 var exp = select(this).classed('expanded');
63250                 fillContainer.style('display', exp ? 'none' : 'block');
63251                 select(this).classed('expanded', !exp);
63252                 event.preventDefault();
63253             });
63254
63255         var fillContainer = content
63256             .append('div')
63257             .attr('class', 'data-area-fills')
63258             .style('display', 'none');
63259
63260         var fillList = fillContainer
63261             .append('ul')
63262             .attr('class', 'layer-list layer-fill-list');
63263
63264
63265         // feature filters
63266         content
63267             .append('a')
63268             .text(t('map_data.map_features'))
63269             .attr('href', '#')
63270             .classed('hide-toggle', true)
63271             .classed('expanded', false)
63272             .on('click', function() {
63273                 var exp = select(this).classed('expanded');
63274                 featureContainer.style('display', exp ? 'none' : 'block');
63275                 select(this).classed('expanded', !exp);
63276                 event.preventDefault();
63277             });
63278
63279         var featureContainer = content
63280             .append('div')
63281             .attr('class', 'data-feature-filters')
63282             .style('display', 'none');
63283
63284         var featureList = featureContainer
63285             .append('ul')
63286             .attr('class', 'layer-list layer-feature-list');
63287
63288
63289         context.features()
63290             .on('change.map_data-update', update);
63291
63292         setFill(fillDefault);
63293
63294         var keybinding = d3keybinding('features')
63295             .on(key, togglePanel)
63296             .on('W', toggleWireframe)
63297             .on('B', hidePanel)
63298             .on('H', hidePanel);
63299
63300         select(document)
63301             .call(keybinding);
63302
63303         context.surface().on('mousedown.map_data-outside', hidePanel);
63304         context.container().on('mousedown.map_data-outside', hidePanel);
63305     }
63306
63307
63308     return map_data;
63309 }
63310
63311 function uiModes(context) {
63312     var modes = [
63313         modeAddPoint$$1(context),
63314         modeAddLine$$1(context),
63315         modeAddArea$$1(context)
63316     ];
63317
63318
63319     function editable() {
63320         return context.editable() && context.mode().id !== 'save';
63321     }
63322
63323
63324     return function(selection$$1) {
63325         var buttons = selection$$1.selectAll('button.add-button')
63326             .data(modes);
63327
63328         buttons = buttons.enter()
63329             .append('button')
63330             .attr('tabindex', -1)
63331             .attr('class', function(mode) { return mode.id + ' add-button col4'; })
63332             .on('click.mode-buttons', function(mode) {
63333                 if (mode.id === context.mode().id) {
63334                     context.enter(modeBrowse(context));
63335                 } else {
63336                     context.enter(mode);
63337                 }
63338             })
63339             .call(tooltip()
63340                 .placement('bottom')
63341                 .html(true)
63342                 .title(function(mode) {
63343                     return uiTooltipHtml(mode.description, mode.key);
63344                 })
63345             );
63346
63347         context.map()
63348             .on('move.modes', lodash.debounce(update, 500));
63349
63350         context
63351             .on('enter.modes', update);
63352
63353         buttons
63354             .each(function(d) {
63355                 select(this)
63356                     .call(svgIcon('#icon-' + d.button, 'pre-text'));
63357             });
63358
63359         buttons
63360             .append('span')
63361             .attr('class', 'label')
63362             .text(function(mode) { return mode.title; });
63363
63364         context
63365             .on('enter.editor', function(entered) {
63366                 selection$$1.selectAll('button.add-button')
63367                     .classed('active', function(mode) { return entered.button === mode.button; });
63368                 context.container()
63369                     .classed('mode-' + entered.id, true);
63370             });
63371
63372         context
63373             .on('exit.editor', function(exited) {
63374                 context.container()
63375                     .classed('mode-' + exited.id, false);
63376             });
63377
63378         var keybinding = d3keybinding('mode-buttons');
63379
63380         modes.forEach(function(mode) {
63381             keybinding.on(mode.key, function() {
63382                 if (editable()) {
63383                     if (mode.id === context.mode().id) {
63384                         context.enter(modeBrowse(context));
63385                     } else {
63386                         context.enter(mode);
63387                     }
63388                 }
63389             });
63390         });
63391
63392         select(document)
63393             .call(keybinding);
63394
63395
63396         function update() {
63397             selection$$1.selectAll('button.add-button')
63398                 .property('disabled', !editable());
63399         }
63400     };
63401 }
63402
63403 function uiRestore(context) {
63404
63405     return function(selection) {
63406         if (!context.history().lock() || !context.history().restorableChanges())
63407             return;
63408
63409         var modalSelection = uiModal(selection, true);
63410
63411         modalSelection.select('.modal')
63412             .attr('class', 'modal fillL col6');
63413
63414         var introModal = modalSelection.select('.content');
63415
63416         introModal
63417             .attr('class','cf');
63418
63419         introModal
63420             .append('div')
63421             .attr('class', 'modal-section')
63422             .append('h3')
63423             .text(t('restore.heading'));
63424
63425         introModal
63426             .append('div')
63427             .attr('class','modal-section')
63428             .append('p')
63429             .text(t('restore.description'));
63430
63431         var buttonWrap = introModal
63432             .append('div')
63433             .attr('class', 'modal-actions cf');
63434
63435         var restore = buttonWrap
63436             .append('button')
63437             .attr('class', 'restore col6')
63438             .on('click', function() {
63439                 context.history().restore();
63440                 modalSelection.remove();
63441             });
63442
63443         restore
63444             .append('svg')
63445             .attr('class', 'logo logo-restore')
63446             .append('use')
63447             .attr('xlink:href', '#logo-restore');
63448
63449         restore
63450             .append('div')
63451             .text(t('restore.restore'));
63452
63453         var reset = buttonWrap
63454             .append('button')
63455             .attr('class', 'reset col6')
63456             .on('click', function() {
63457                 context.history().clearSaved();
63458                 modalSelection.remove();
63459             });
63460
63461         reset
63462             .append('svg')
63463             .attr('class', 'logo logo-reset')
63464             .append('use')
63465             .attr('xlink:href', '#logo-reset');
63466
63467         reset
63468             .append('div')
63469             .text(t('restore.reset'));
63470
63471         restore.node().focus();
63472     };
63473 }
63474
63475 function uiSave(context) {
63476     var history = context.history(),
63477         key = uiCmd('⌘S');
63478
63479
63480     function saving() {
63481         return context.mode().id === 'save';
63482     }
63483
63484
63485     function save() {
63486         event.preventDefault();
63487         if (!context.inIntro() && !saving() && history.hasChanges()) {
63488             context.enter(modeSave$$1(context));
63489         }
63490     }
63491
63492
63493     function getBackground(numChanges) {
63494         var step;
63495         if (numChanges === 0) {
63496             return null;
63497         } else if (numChanges <= 50) {
63498             step = numChanges / 50;
63499             return interpolateRgb('#fff', '#ff8')(step);  // white -> yellow
63500         } else {
63501             step = Math.min((numChanges - 50) / 50, 1.0);
63502             return interpolateRgb('#ff8', '#f88')(step);  // yellow -> red
63503         }
63504     }
63505
63506
63507     return function(selection$$1) {
63508         var numChanges = 0;
63509
63510         function updateCount() {
63511             var _ = history.difference().summary().length;
63512             if (_ === numChanges) return;
63513             numChanges = _;
63514
63515             tooltipBehavior
63516                 .title(uiTooltipHtml(
63517                     t(numChanges > 0 ? 'save.help' : 'save.no_changes'), key)
63518                 );
63519
63520             var background = getBackground(numChanges);
63521
63522             button
63523                 .classed('disabled', numChanges === 0)
63524                 .classed('has-count', numChanges > 0)
63525                 .style('background', background);
63526
63527             button.select('span.count')
63528                 .text(numChanges)
63529                 .style('background', background)
63530                 .style('border-color', background);
63531         }
63532
63533
63534         var tooltipBehavior = tooltip()
63535             .placement('bottom')
63536             .html(true)
63537             .title(uiTooltipHtml(t('save.no_changes'), key));
63538
63539         var button = selection$$1
63540             .append('button')
63541             .attr('class', 'save col12 disabled')
63542             .attr('tabindex', -1)
63543             .on('click', save)
63544             .call(tooltipBehavior);
63545
63546         button
63547             .call(svgIcon('#icon-save', 'pre-text'))
63548             .append('span')
63549             .attr('class', 'label')
63550             .text(t('save.title'));
63551
63552         button
63553             .append('span')
63554             .attr('class', 'count')
63555             .text('0');
63556
63557         updateCount();
63558
63559
63560         var keybinding = d3keybinding('save')
63561             .on(key, save, true);
63562
63563         select(document)
63564             .call(keybinding);
63565
63566         context.history()
63567             .on('change.save', updateCount);
63568
63569         context
63570             .on('enter.save', function() {
63571                 button.property('disabled', saving());
63572                 if (saving()) button.call(tooltipBehavior.hide);
63573             });
63574     };
63575 }
63576
63577 function uiScale(context) {
63578     var projection = context.projection,
63579         isImperial = (utilDetect().locale.toLowerCase() === 'en-us'),
63580         maxLength = 180,
63581         tickHeight = 8;
63582
63583
63584     function scaleDefs(loc1, loc2) {
63585         var lat = (loc2[1] + loc1[1]) / 2,
63586             conversion = (isImperial ? 3.28084 : 1),
63587             dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
63588             scale = { dist: 0, px: 0, text: '' },
63589             buckets, i, val, dLon;
63590
63591         if (isImperial) {
63592             buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
63593         } else {
63594             buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
63595         }
63596
63597         // determine a user-friendly endpoint for the scale
63598         for (i = 0; i < buckets.length; i++) {
63599             val = buckets[i];
63600             if (dist >= val) {
63601                 scale.dist = Math.floor(dist / val) * val;
63602                 break;
63603             } else {
63604                 scale.dist = +dist.toFixed(2);
63605             }
63606         }
63607
63608         dLon = geoMetersToLon(scale.dist / conversion, lat);
63609         scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
63610
63611         if (isImperial) {
63612             if (scale.dist >= 5280) {
63613                 scale.dist /= 5280;
63614                 scale.text = String(scale.dist) + ' mi';
63615             } else {
63616                 scale.text = String(scale.dist) + ' ft';
63617             }
63618         } else {
63619             if (scale.dist >= 1000) {
63620                 scale.dist /= 1000;
63621                 scale.text = String(scale.dist) + ' km';
63622             } else {
63623                 scale.text = String(scale.dist) + ' m';
63624             }
63625         }
63626
63627         return scale;
63628     }
63629
63630
63631     function update(selection) {
63632         // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
63633         var dims = context.map().dimensions(),
63634             loc1 = projection.invert([0, dims[1]]),
63635             loc2 = projection.invert([maxLength, dims[1]]),
63636             scale = scaleDefs(loc1, loc2);
63637
63638         selection.select('#scale-path')
63639             .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
63640
63641         selection.select('#scale-textgroup')
63642             .attr('transform', 'translate(' + (scale.px + 8) + ',' + tickHeight + ')');
63643
63644         selection.select('#scale-text')
63645             .text(scale.text);
63646     }
63647
63648
63649     return function(selection) {
63650         function switchUnits() {
63651             isImperial = !isImperial;
63652             selection.call(update);
63653         }
63654
63655         var scalegroup = selection.append('svg')
63656             .attr('id', 'scale')
63657             .on('click', switchUnits)
63658             .append('g')
63659             .attr('transform', 'translate(10,11)');
63660
63661         scalegroup
63662             .append('path')
63663             .attr('id', 'scale-path');
63664
63665         scalegroup
63666             .append('g')
63667             .attr('id', 'scale-textgroup')
63668             .append('text')
63669             .attr('id', 'scale-text');
63670
63671         selection.call(update);
63672
63673         context.map().on('move.scale', function() {
63674             update(selection);
63675         });
63676     };
63677 }
63678
63679 var pair_1 = pair$1;
63680 function search(x, dims, r) {
63681   if (!dims) dims = 'NSEW';
63682   if (typeof x !== 'string') return { val: null, regex: r };
63683   r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
63684   var m = r.exec(x);
63685   if (!m) return { val: null, regex: r };
63686   else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
63687   else return {
63688     val: (((m[1]) ? parseFloat(m[1]) : 0) +
63689           ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
63690           ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
63691           ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
63692     regex: r,
63693     raw: m[0],
63694     dim: m[4]
63695   };
63696 }
63697
63698 function pair$1(x, dims) {
63699   x = x.trim();
63700   var one = search(x, dims);
63701   if (one.val === null) return null;
63702   var two = search(x, dims, one.regex);
63703   if (two.val === null) return null;
63704   // null if one/two are not contiguous.
63705   if (one.raw + two.raw !== x) return null;
63706   if (one.dim) {
63707     return swapdim(one.val, two.val, one.dim);
63708   } else {
63709     return [one.val, two.val];
63710   }
63711 }
63712
63713 function swapdim(a, b, dim) {
63714   if (dim === 'N' || dim === 'S') return [a, b];
63715   if (dim === 'W' || dim === 'E') return [b, a];
63716 }
63717
63718 function uiFeatureList(context) {
63719     var geocodeResults;
63720
63721
63722     function featureList(selection$$1) {
63723         var header = selection$$1
63724             .append('div')
63725             .attr('class', 'header fillL cf');
63726
63727         header.append('h3')
63728             .text(t('inspector.feature_list'));
63729
63730         var searchWrap = selection$$1
63731             .append('div')
63732             .attr('class', 'search-header');
63733
63734         var search = searchWrap
63735             .append('input')
63736             .attr('placeholder', t('inspector.search'))
63737             .attr('type', 'search')
63738             .call(utilNoAuto)
63739             .on('keypress', keypress)
63740             .on('input', inputevent);
63741
63742         searchWrap
63743             .call(svgIcon('#icon-search', 'pre-text'));
63744
63745         var listWrap = selection$$1
63746             .append('div')
63747             .attr('class', 'inspector-body');
63748
63749         var list = listWrap
63750             .append('div')
63751             .attr('class', 'feature-list cf');
63752
63753         context
63754             .on('exit.feature-list', clearSearch);
63755         context.map()
63756             .on('drawn.feature-list', mapDrawn);
63757
63758
63759         function keypress() {
63760             var q = search.property('value'),
63761                 items = list.selectAll('.feature-list-item');
63762             if (event.keyCode === 13 && q.length && items.size()) {
63763                 click(items.datum());
63764             }
63765         }
63766
63767
63768         function inputevent() {
63769             geocodeResults = undefined;
63770             drawList();
63771         }
63772
63773
63774         function clearSearch() {
63775             search.property('value', '');
63776             drawList();
63777         }
63778
63779
63780         function mapDrawn(e) {
63781             if (e.full) {
63782                 drawList();
63783             }
63784         }
63785
63786
63787         function features() {
63788             var entities = {},
63789                 result = [],
63790                 graph = context.graph(),
63791                 q = search.property('value').toLowerCase();
63792
63793             if (!q) return result;
63794
63795             var idMatch = q.match(/^([nwr])([0-9]+)$/);
63796
63797             if (idMatch) {
63798                 result.push({
63799                     id: idMatch[0],
63800                     geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
63801                     type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
63802                     name: idMatch[2]
63803                 });
63804             }
63805
63806             var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
63807
63808             if (locationMatch) {
63809                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
63810                 result.push({
63811                     id: -1,
63812                     geometry: 'point',
63813                     type: t('inspector.location'),
63814                     name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
63815                     location: loc
63816                 });
63817             }
63818
63819             function addEntity(entity) {
63820                 if (entity.id in entities || result.length > 200)
63821                     return;
63822
63823                 entities[entity.id] = true;
63824
63825                 var name = utilDisplayName(entity) || '';
63826                 if (name.toLowerCase().indexOf(q) >= 0) {
63827                     var matched = context.presets().match(entity, graph),
63828                         type = (matched && matched.name()) || utilDisplayType(entity.id);
63829                     result.push({
63830                         id: entity.id,
63831                         entity: entity,
63832                         geometry: context.geometry(entity.id),
63833                         type: type,
63834                         name: name
63835                     });
63836                 }
63837
63838                 graph.parentRelations(entity).forEach(function(parent) {
63839                     addEntity(parent);
63840                 });
63841             }
63842
63843             var visible = context.surface().selectAll('.point, .line, .area').nodes();
63844             for (var i = 0; i < visible.length && result.length <= 200; i++) {
63845                 addEntity(visible[i].__data__);
63846             }
63847
63848             (geocodeResults || []).forEach(function(d) {
63849                 // https://github.com/openstreetmap/iD/issues/1890
63850                 if (d.osm_type && d.osm_id) {
63851                     result.push({
63852                         id: osmEntity$$1.id.fromOSM(d.osm_type, d.osm_id),
63853                         geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
63854                         type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
63855                                                : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
63856                         name: d.display_name,
63857                         extent: new geoExtent$$1(
63858                             [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
63859                             [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
63860                     });
63861                 }
63862             });
63863
63864             return result;
63865         }
63866
63867
63868         function drawList() {
63869             var value = search.property('value'),
63870                 results = features();
63871
63872             list.classed('filtered', value.length);
63873
63874             var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
63875
63876             var resultsIndicator = list.selectAll('.no-results-item')
63877                 .data([0])
63878                 .enter().append('button')
63879                 .property('disabled', true)
63880                 .attr('class', 'no-results-item')
63881                 .call(svgIcon('#icon-alert', 'pre-text'));
63882
63883             resultsIndicator.append('span')
63884                 .attr('class', 'entity-name');
63885
63886             list.selectAll('.no-results-item .entity-name')
63887                 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
63888
63889             list.selectAll('.geocode-item')
63890                 .data([0])
63891                 .enter().append('button')
63892                 .attr('class', 'geocode-item')
63893                 .on('click', geocoderSearch)
63894                 .append('div')
63895                 .attr('class', 'label')
63896                 .append('span')
63897                 .attr('class', 'entity-name')
63898                 .text(t('geocoder.search'));
63899
63900             list.selectAll('.no-results-item')
63901                 .style('display', (value.length && !results.length) ? 'block' : 'none');
63902
63903             list.selectAll('.geocode-item')
63904                 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
63905
63906             list.selectAll('.feature-list-item')
63907                 .data([-1])
63908                 .remove();
63909
63910             var items = list.selectAll('.feature-list-item')
63911                 .data(results, function(d) { return d.id; });
63912
63913             var enter = items.enter()
63914                 .insert('button', '.geocode-item')
63915                 .attr('class', 'feature-list-item')
63916                 .on('mouseover', mouseover)
63917                 .on('mouseout', mouseout)
63918                 .on('click', click);
63919
63920             var label = enter
63921                 .append('div')
63922                 .attr('class', 'label');
63923
63924             label.each(function(d) {
63925                 select(this)
63926                     .call(svgIcon('#icon-' + d.geometry, 'pre-text'));
63927             });
63928
63929             label.append('span')
63930                 .attr('class', 'entity-type')
63931                 .text(function(d) { return d.type; });
63932
63933             label.append('span')
63934                 .attr('class', 'entity-name')
63935                 .text(function(d) { return d.name; });
63936
63937             enter.style('opacity', 0)
63938                 .transition()
63939                 .style('opacity', 1);
63940
63941             items.order();
63942
63943             items.exit()
63944                 .remove();
63945         }
63946
63947
63948         function mouseover(d) {
63949             if (d.id === -1) return;
63950
63951             context.surface().selectAll(utilEntityOrMemberSelector([d.id], context.graph()))
63952                 .classed('hover', true);
63953         }
63954
63955
63956         function mouseout() {
63957             context.surface().selectAll('.hover')
63958                 .classed('hover', false);
63959         }
63960
63961
63962         function click(d) {
63963             event.preventDefault();
63964             if (d.location) {
63965                 context.map().centerZoom([d.location[1], d.location[0]], 20);
63966             }
63967             else if (d.entity) {
63968                 if (d.entity.type === 'node') {
63969                     context.map().center(d.entity.loc);
63970                 } else if (d.entity.type === 'way') {
63971                     var center = context.projection(context.map().center()),
63972                         edge = geoChooseEdge(context.childNodes(d.entity), center, context.projection);
63973                     context.map().center(edge.loc);
63974                 }
63975                 context.enter(modeSelect(context, [d.entity.id]));
63976             } else {
63977                 context.zoomToEntity(d.id);
63978             }
63979         }
63980
63981
63982         function geocoderSearch() {
63983             services.geocoder.search(search.property('value'), function (err, resp) {
63984                 geocodeResults = resp || [];
63985                 drawList();
63986             });
63987         }
63988     }
63989
63990
63991     return featureList;
63992 }
63993
63994 function uiPresetIcon() {
63995     var preset, geometry;
63996
63997
63998     function presetIcon(selection$$1) {
63999         selection$$1.each(render);
64000     }
64001
64002
64003     function getIcon(p, geom) {
64004         if (p.icon)
64005             return p.icon;
64006         else if (geom === 'line')
64007             return 'other-line';
64008         else if (geom === 'vertex')
64009             return p.isFallback() ? '' : 'poi-vertex';
64010         else
64011             return 'marker-stroked';
64012     }
64013
64014
64015     function render() {
64016         var selection$$1 = select(this),
64017             p = preset.apply(this, arguments),
64018             geom = geometry.apply(this, arguments),
64019             picon = getIcon(p, geom),
64020             isPoi = picon.match(/^poi-/) !== null,
64021             isMaki = dataFeatureIcons.indexOf(picon) !== -1,
64022             isFramed = (geom === 'area' || geom === 'verex');
64023
64024
64025         function tag_classes(p) {
64026             var s = '';
64027             for (var i in p.tags) {
64028                 s += ' tag-' + i;
64029                 if (p.tags[i] !== '*') {
64030                     s += ' tag-' + i + '-' + p.tags[i];
64031                 }
64032             }
64033             return s;
64034         }
64035
64036
64037         var fill = selection$$1.selectAll('.preset-icon-fill')
64038             .data([0]);
64039
64040         fill = fill.enter()
64041             .append('div')
64042             .merge(fill);
64043
64044         fill
64045             .attr('class', function() {
64046                 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
64047             });
64048
64049
64050         var areaFrame = selection$$1.selectAll('.preset-icon-frame')
64051             .data((geom === 'area') ? [0] : []);
64052
64053         areaFrame.exit()
64054             .remove();
64055
64056         areaFrame = areaFrame.enter()
64057             .append('div')
64058             .attr('class', 'preset-icon-frame')
64059             .call(svgIcon('#preset-icon-frame'));
64060
64061
64062         var icon = selection$$1.selectAll('.preset-icon')
64063             .data([0]);
64064
64065         icon = icon.enter()
64066             .append('div')
64067             .attr('class', 'preset-icon')
64068             .call(svgIcon(''))
64069             .merge(icon);
64070
64071         icon
64072             .attr('class', 'preset-icon preset-icon-' +
64073                 ((isMaki || isPoi) ? (isFramed ? '24' : '28') : (isFramed ? '44' : '60'))
64074             );
64075
64076         icon.selectAll('svg')
64077             .attr('class', function() {
64078                 return 'icon ' + picon + (isMaki || isPoi ? '' : tag_classes(p));
64079             });
64080
64081         icon.selectAll('use')
64082             .attr('href', '#' + picon + (isMaki ? '-15' : ''));
64083     }
64084
64085
64086     presetIcon.preset = function(_) {
64087         if (!arguments.length) return preset;
64088         preset = utilFunctor(_);
64089         return presetIcon;
64090     };
64091
64092
64093     presetIcon.geometry = function(_) {
64094         if (!arguments.length) return geometry;
64095         geometry = utilFunctor(_);
64096         return presetIcon;
64097     };
64098
64099     return presetIcon;
64100 }
64101
64102 function d3combobox() {
64103     var dispatch$$1 = dispatch('accept'),
64104         container = select(document.body),
64105         data = [],
64106         suggestions = [],
64107         minItems = 2,
64108         caseSensitive = false;
64109
64110     var fetcher = function(val, cb) {
64111         cb(data.filter(function(d) {
64112             return d.value
64113                 .toString()
64114                 .toLowerCase()
64115                 .indexOf(val.toLowerCase()) !== -1;
64116         }));
64117     };
64118
64119     var combobox = function(input, attachTo) {
64120         var idx = -1,
64121             wrapper = container
64122                 .selectAll('div.combobox')
64123                 .filter(function(d) { return d === input.node(); }),
64124             shown = !wrapper.empty();
64125
64126         input
64127             .classed('combobox-input', true)
64128             .on('focus.typeahead', focus)
64129             .on('blur.typeahead', blur)
64130             .on('keydown.typeahead', keydown)
64131             .on('keyup.typeahead', keyup)
64132             .on('input.typeahead', change)
64133             .each(function() {
64134                 var parent = this.parentNode,
64135                     sibling = this.nextSibling;
64136
64137                 var caret = select(parent).selectAll('.combobox-caret')
64138                     .filter(function(d) { return d === input.node(); })
64139                     .data([input.node()]);
64140
64141                 caret = caret.enter()
64142                   .insert('div', function() { return sibling; })
64143                     .attr('class', 'combobox-caret')
64144                   .merge(caret);
64145
64146                 caret
64147                     .on('mousedown', function () {
64148                         // prevent the form element from blurring. it blurs
64149                         // on mousedown
64150                         event.stopPropagation();
64151                         event.preventDefault();
64152                         if (!shown) {
64153                             input.node().focus();
64154                             fetch('', render);
64155                         } else {
64156                             hide();
64157                         }
64158                     });
64159             });
64160
64161         function focus() {
64162             fetch(value(), render);
64163         }
64164
64165         function blur() {
64166             window.setTimeout(hide, 150);
64167         }
64168
64169         function show() {
64170             if (!shown) {
64171                 wrapper = container
64172                     .insert('div', ':first-child')
64173                     .datum(input.node())
64174                     .attr('class', 'combobox')
64175                     .style('position', 'absolute')
64176                     .style('display', 'block')
64177                     .style('left', '0px')
64178                     .on('mousedown', function () {
64179                         // prevent moving focus out of the text field
64180                         event.preventDefault();
64181                     });
64182
64183                 select('body')
64184                     .on('scroll.combobox', render, true);
64185
64186                 shown = true;
64187             }
64188         }
64189
64190         function hide() {
64191             if (shown) {
64192                 idx = -1;
64193                 wrapper.remove();
64194
64195                 select('body')
64196                     .on('scroll.combobox', null);
64197
64198                 shown = false;
64199             }
64200         }
64201
64202         function keydown() {
64203            switch (event.keyCode) {
64204                // backspace, delete
64205                case 8:
64206                case 46:
64207                    input.on('input.typeahead', function() {
64208                        idx = -1;
64209                        render();
64210                        var start = input.property('selectionStart');
64211                        input.node().setSelectionRange(start, start);
64212                        input.on('input.typeahead', change);
64213                    });
64214                    break;
64215                // tab
64216                case 9:
64217                    wrapper.selectAll('a.selected').each(function (d) {
64218                        dispatch$$1.call('accept', this, d);
64219                    });
64220                    hide();
64221                    break;
64222                // return
64223                case 13:
64224                    event.preventDefault();
64225                    break;
64226                // up arrow
64227                case 38:
64228                    nav(-1);
64229                    event.preventDefault();
64230                    break;
64231                // down arrow
64232                case 40:
64233                    nav(+1);
64234                    event.preventDefault();
64235                    break;
64236            }
64237            event.stopPropagation();
64238         }
64239
64240         function keyup() {
64241             switch (event.keyCode) {
64242                 // escape
64243                 case 27:
64244                     hide();
64245                     break;
64246                 // return
64247                 case 13:
64248                     wrapper.selectAll('a.selected').each(function (d) {
64249                        dispatch$$1.call('accept', this, d);
64250                     });
64251                     hide();
64252                     break;
64253             }
64254         }
64255
64256         function change() {
64257             fetch(value(), function() {
64258                 if (input.property('selectionEnd') === input.property('value').length) {
64259                     autocomplete();
64260                 }
64261                 render();
64262             });
64263         }
64264
64265         function nav(dir) {
64266             if (!suggestions.length) return;
64267             idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
64268             input.property('value', suggestions[idx].value);
64269             render();
64270             ensureVisible();
64271         }
64272
64273         function value() {
64274             var value = input.property('value'),
64275                 start = input.property('selectionStart'),
64276                 end = input.property('selectionEnd');
64277
64278             if (start && end) {
64279                 value = value.substring(0, start);
64280             }
64281
64282             return value;
64283         }
64284
64285         function fetch(v, cb) {
64286             fetcher.call(input, v, function(_) {
64287                 suggestions = _;
64288                 cb();
64289             });
64290         }
64291
64292         function autocomplete() {
64293             var v = caseSensitive ? value() : value().toLowerCase();
64294             idx = -1;
64295             if (!v) return;
64296
64297             for (var i = 0; i < suggestions.length; i++) {
64298                 var suggestion = suggestions[i].value,
64299                     compare = caseSensitive ? suggestion : suggestion.toLowerCase();
64300
64301                 if (compare.indexOf(v) === 0) {
64302                     idx = i;
64303                     input.property('value', suggestion);
64304                     input.node().setSelectionRange(v.length, suggestion.length);
64305                     return;
64306                 }
64307             }
64308         }
64309
64310         function render() {
64311             if (suggestions.length >= minItems && document.activeElement === input.node()) {
64312                 show();
64313             } else {
64314                 hide();
64315                 return;
64316             }
64317
64318             var options = wrapper
64319                 .selectAll('a.combobox-option')
64320                 .data(suggestions, function(d) { return d.value; });
64321
64322             options.exit()
64323                 .remove();
64324
64325             options.enter()
64326                 .append('a')
64327                 .attr('class', 'combobox-option')
64328                 .text(function(d) { return d.value; })
64329                 .merge(options)
64330                 .attr('title', function(d) { return d.title; })
64331                 .classed('selected', function(d, i) { return i === idx; })
64332                 .on('mouseover', select$$1)
64333                 .on('click', accept)
64334                 .order();
64335
64336
64337             var node = attachTo ? attachTo.node() : input.node(),
64338                 rect = node.getBoundingClientRect();
64339
64340             wrapper
64341                 .style('left', rect.left + 'px')
64342                 .style('width', rect.width + 'px')
64343                 .style('top', rect.height + rect.top + 'px');
64344         }
64345
64346         function select$$1(d, i) {
64347             idx = i;
64348             render();
64349         }
64350
64351         function ensureVisible() {
64352             var node = wrapper.selectAll('a.selected').node();
64353             if (node) node.scrollIntoView();
64354         }
64355
64356         function accept(d) {
64357             if (!shown) return;
64358             input.property('value', d.value);
64359             utilTriggerEvent(input, 'change');
64360             dispatch$$1.call('accept', this, d);
64361             hide();
64362         }
64363     };
64364
64365     combobox.fetcher = function(_) {
64366         if (!arguments.length) return fetcher;
64367         fetcher = _;
64368         return combobox;
64369     };
64370
64371     combobox.data = function(_) {
64372         if (!arguments.length) return data;
64373         data = _;
64374         return combobox;
64375     };
64376
64377     combobox.minItems = function(_) {
64378         if (!arguments.length) return minItems;
64379         minItems = _;
64380         return combobox;
64381     };
64382
64383     combobox.caseSensitive = function(_) {
64384         if (!arguments.length) return caseSensitive;
64385         caseSensitive = _;
64386         return combobox;
64387     };
64388
64389     combobox.container = function(_) {
64390         if (!arguments.length) return container;
64391         container = _;
64392         return combobox;
64393     };
64394
64395     return utilRebind(combobox, dispatch$$1, 'on');
64396 }
64397
64398
64399 d3combobox.off = function(input) {
64400     input
64401         .on('focus.typeahead', null)
64402         .on('blur.typeahead', null)
64403         .on('keydown.typeahead', null)
64404         .on('keyup.typeahead', null)
64405         .on('input.typeahead', null)
64406         .each(function() {
64407             select(this.parentNode).selectAll('.combobox-caret')
64408                 .filter(function(d) { return d === input.node(); })
64409                 .on('mousedown', null);
64410         });
64411
64412     select('body')
64413         .on('scroll.combobox', null);
64414 };
64415
64416 function uiDisclosure() {
64417     var dispatch$$1 = dispatch('toggled'),
64418         title,
64419         expanded = false,
64420         content = function () {};
64421
64422
64423     var disclosure = function(selection$$1) {
64424         var hideToggle = selection$$1.selectAll('.hide-toggle')
64425             .data([0]);
64426
64427         hideToggle = hideToggle.enter()
64428             .append('a')
64429             .attr('href', '#')
64430             .attr('class', 'hide-toggle')
64431             .merge(hideToggle);
64432
64433         hideToggle
64434             .text(title)
64435             .on('click', toggle)
64436             .classed('expanded', expanded);
64437
64438
64439         var wrap = selection$$1.selectAll('div')
64440             .data([0]);
64441
64442         wrap = wrap.enter()
64443             .append('div')
64444             .merge(wrap);
64445
64446         wrap
64447             .classed('hide', !expanded)
64448             .call(content);
64449
64450
64451         function toggle() {
64452             expanded = !expanded;
64453             hideToggle.classed('expanded', expanded);
64454             wrap.call(uiToggle(expanded));
64455             dispatch$$1.call('toggled', this, expanded);
64456         }
64457     };
64458
64459
64460     disclosure.title = function(_) {
64461         if (!arguments.length) return title;
64462         title = _;
64463         return disclosure;
64464     };
64465
64466
64467     disclosure.expanded = function(_) {
64468         if (!arguments.length) return expanded;
64469         expanded = _;
64470         return disclosure;
64471     };
64472
64473
64474     disclosure.content = function(_) {
64475         if (!arguments.length) return content;
64476         content = _;
64477         return disclosure;
64478     };
64479
64480
64481     return utilRebind(disclosure, dispatch$$1, 'on');
64482 }
64483
64484 function uiRawMemberEditor(context) {
64485     var id,
64486         taginfo = services.taginfo;
64487
64488
64489     function selectMember(d) {
64490         event.preventDefault();
64491         context.enter(modeSelect(context, [d.id]));
64492     }
64493
64494
64495     function changeRole(d) {
64496         var role = select(this).property('value');
64497         var member = { id: d.id, type: d.type, role: role };
64498         context.perform(
64499             actionChangeMember(d.relation.id, member, d.index),
64500             t('operations.change_role.annotation')
64501         );
64502     }
64503
64504
64505     function deleteMember(d) {
64506         context.perform(
64507             actionDeleteMember(d.relation.id, d.index),
64508             t('operations.delete_member.annotation')
64509         );
64510
64511         if (!context.hasEntity(d.relation.id)) {
64512             context.enter(modeBrowse(context));
64513         }
64514     }
64515
64516
64517     function rawMemberEditor(selection$$1) {
64518         var entity = context.entity(id),
64519             memberships = [];
64520
64521         entity.members.slice(0, 1000).forEach(function(member, index) {
64522             memberships.push({
64523                 index: index,
64524                 id: member.id,
64525                 type: member.type,
64526                 role: member.role,
64527                 relation: entity,
64528                 member: context.hasEntity(member.id)
64529             });
64530         });
64531
64532         var gt = entity.members.length > 1000 ? '>' : '';
64533         selection$$1.call(uiDisclosure()
64534             .title(t('inspector.all_members') + ' (' + gt + memberships.length + ')')
64535             .expanded(true)
64536             .on('toggled', toggled)
64537             .content(content)
64538         );
64539
64540
64541         function toggled(expanded) {
64542             if (expanded) {
64543                 selection$$1.node().parentNode.scrollTop += 200;
64544             }
64545         }
64546
64547
64548         function content(wrap) {
64549             var list = wrap.selectAll('.member-list')
64550                 .data([0]);
64551
64552             list = list.enter()
64553                 .append('ul')
64554                 .attr('class', 'member-list')
64555                 .merge(list);
64556
64557
64558             var items = list.selectAll('li')
64559                 .data(memberships, function(d) {
64560                     return osmEntity$$1.key(d.relation) + ',' + d.index + ',' +
64561                         (d.member ? osmEntity$$1.key(d.member) : 'incomplete');
64562                 });
64563
64564             items.exit()
64565                 .each(unbind)
64566                 .remove();
64567
64568             var enter = items.enter()
64569                 .append('li')
64570                 .attr('class', 'member-row form-field')
64571                 .classed('member-incomplete', function(d) { return !d.member; });
64572
64573             enter
64574                 .each(function(d) {
64575                     if (d.member) {
64576                         var label = select(this).append('label')
64577                             .attr('class', 'form-label')
64578                             .append('a')
64579                             .attr('href', '#')
64580                             .on('click', selectMember);
64581
64582                         label.append('span')
64583                             .attr('class', 'member-entity-type')
64584                             .text(function(d) {
64585                                 var matched = context.presets().match(d.member, context.graph());
64586                                 return (matched && matched.name()) || utilDisplayType(d.member.id);
64587                             });
64588
64589                         label.append('span')
64590                             .attr('class', 'member-entity-name')
64591                             .text(function(d) { return utilDisplayName(d.member); });
64592
64593                     } else {
64594                         select(this).append('label')
64595                             .attr('class', 'form-label')
64596                             .text(t('inspector.incomplete', { id: d.id }));
64597                     }
64598                 });
64599
64600             enter
64601                 .append('input')
64602                 .attr('class', 'member-role')
64603                 .property('type', 'text')
64604                 .attr('maxlength', 255)
64605                 .attr('placeholder', t('inspector.role'))
64606                 .call(utilNoAuto)
64607                 .property('value', function(d) { return d.role; })
64608                 .on('change', changeRole);
64609
64610             enter
64611                 .append('button')
64612                 .attr('tabindex', -1)
64613                 .attr('class', 'remove button-input-action member-delete minor')
64614                 .on('click', deleteMember)
64615                 .call(svgIcon('#operation-delete'));
64616
64617             if (taginfo) {
64618                 enter.each(bindTypeahead);
64619             }
64620
64621
64622             function bindTypeahead(d) {
64623                 var row = select(this),
64624                     role = row.selectAll('input.member-role');
64625
64626                 function sort(value, data) {
64627                     var sameletter = [],
64628                         other = [];
64629                     for (var i = 0; i < data.length; i++) {
64630                         if (data[i].value.substring(0, value.length) === value) {
64631                             sameletter.push(data[i]);
64632                         } else {
64633                             other.push(data[i]);
64634                         }
64635                     }
64636                     return sameletter.concat(other);
64637                 }
64638
64639                 role.call(d3combobox()
64640                     .container(context.container())
64641                     .fetcher(function(role, callback) {
64642                         var rtype = entity.tags.type;
64643                         taginfo.roles({
64644                             debounce: true,
64645                             rtype: rtype || '',
64646                             geometry: context.geometry(d.member.id),
64647                             query: role
64648                         }, function(err, data) {
64649                             if (!err) callback(sort(role, data));
64650                         });
64651                     }));
64652             }
64653
64654
64655             function unbind() {
64656                 var row = select(this);
64657
64658                 row.selectAll('input.member-role')
64659                     .call(d3combobox.off);
64660             }
64661         }
64662     }
64663
64664
64665     rawMemberEditor.entityID = function(_) {
64666         if (!arguments.length) return id;
64667         id = _;
64668         return rawMemberEditor;
64669     };
64670
64671
64672     return rawMemberEditor;
64673 }
64674
64675 function uiRawMembershipEditor(context) {
64676     var taginfo = services.taginfo,
64677         id, showBlank;
64678
64679
64680     function selectRelation(d) {
64681         event.preventDefault();
64682         context.enter(modeSelect(context, [d.relation.id]));
64683     }
64684
64685
64686     function changeRole(d) {
64687         var role = select(this).property('value');
64688         context.perform(
64689             actionChangeMember(d.relation.id, lodash.extend({}, d.member, { role: role }), d.index),
64690             t('operations.change_role.annotation')
64691         );
64692     }
64693
64694
64695     function addMembership(d, role) {
64696         showBlank = false;
64697
64698         if (d.relation) {
64699             context.perform(
64700                 actionAddMember(d.relation.id, { id: id, type: context.entity(id).type, role: role }),
64701                 t('operations.add_member.annotation')
64702             );
64703
64704         } else {
64705             var relation = osmRelation();
64706             context.perform(
64707                 actionAddEntity(relation),
64708                 actionAddMember(relation.id, { id: id, type: context.entity(id).type, role: role }),
64709                 t('operations.add.annotation.relation')
64710             );
64711
64712             context.enter(modeSelect(context, [relation.id]));
64713         }
64714     }
64715
64716
64717     function deleteMembership(d) {
64718         context.perform(
64719             actionDeleteMember(d.relation.id, d.index),
64720             t('operations.delete_member.annotation')
64721         );
64722     }
64723
64724
64725     function relations(q) {
64726         var newRelation = {
64727                 relation: null,
64728                 value: t('inspector.new_relation')
64729             },
64730             result = [],
64731             graph = context.graph();
64732
64733         context.intersects(context.extent()).forEach(function(entity) {
64734             if (entity.type !== 'relation' || entity.id === id)
64735                 return;
64736
64737             var matched = context.presets().match(entity, graph),
64738                 presetName = (matched && matched.name()) || t('inspector.relation'),
64739                 entityName = utilDisplayName(entity) || '';
64740
64741             var value = presetName + ' ' + entityName;
64742             if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
64743                 return;
64744
64745             result.push({
64746                 relation: entity,
64747                 value: value
64748             });
64749         });
64750
64751         result.sort(function(a, b) {
64752             return osmRelation.creationOrder(a.relation, b.relation);
64753         });
64754
64755         // Dedupe identical names by appending relation id - see #2891
64756         var dupeGroups = lodash(result)
64757             .groupBy('value')
64758             .filter(function(v) { return v.length > 1; })
64759             .value();
64760
64761         dupeGroups.forEach(function(group) {
64762             group.forEach(function(obj) {
64763                 obj.value += ' ' + obj.relation.id;
64764             });
64765         });
64766
64767         result.unshift(newRelation);
64768         return result;
64769     }
64770
64771
64772     function rawMembershipEditor(selection$$1) {
64773         var entity = context.entity(id),
64774             parents = context.graph().parentRelations(entity),
64775             memberships = [];
64776
64777         parents.slice(0, 1000).forEach(function(relation) {
64778             relation.members.forEach(function(member, index) {
64779                 if (member.id === entity.id) {
64780                     memberships.push({ relation: relation, member: member, index: index });
64781                 }
64782             });
64783         });
64784
64785         var gt = parents.length > 1000 ? '>' : '';
64786         selection$$1.call(uiDisclosure()
64787             .title(t('inspector.all_relations') + ' (' + gt + memberships.length + ')')
64788             .expanded(true)
64789             .on('toggled', toggled)
64790             .content(content)
64791         );
64792
64793
64794         function toggled(expanded) {
64795             if (expanded) {
64796                 selection$$1.node().parentNode.scrollTop += 200;
64797             }
64798         }
64799
64800
64801         function content(wrap) {
64802             var list = wrap.selectAll('.member-list')
64803                 .data([0]);
64804
64805             list = list.enter()
64806                 .append('ul')
64807                 .attr('class', 'member-list')
64808                 .merge(list);
64809
64810
64811             var items = list.selectAll('li.member-row-normal')
64812                 .data(memberships, function(d) {
64813                     return osmEntity$$1.key(d.relation) + ',' + d.index;
64814                 });
64815
64816             items.exit()
64817                 .each(unbind)
64818                 .remove();
64819
64820             var enter = items.enter()
64821                 .append('li')
64822                 .attr('class', 'member-row member-row-normal form-field');
64823
64824             var label = enter
64825                 .append('label')
64826                 .attr('class', 'form-label')
64827                 .append('a')
64828                 .attr('href', '#')
64829                 .on('click', selectRelation);
64830
64831             label
64832                 .append('span')
64833                 .attr('class', 'member-entity-type')
64834                 .text(function(d) {
64835                     var matched = context.presets().match(d.relation, context.graph());
64836                     return (matched && matched.name()) || t('inspector.relation');
64837                 });
64838
64839             label
64840                 .append('span')
64841                 .attr('class', 'member-entity-name')
64842                 .text(function(d) { return utilDisplayName(d.relation); });
64843
64844             enter
64845                 .append('input')
64846                 .attr('class', 'member-role')
64847                 .property('type', 'text')
64848                 .attr('maxlength', 255)
64849                 .attr('placeholder', t('inspector.role'))
64850                 .call(utilNoAuto)
64851                 .property('value', function(d) { return d.member.role; })
64852                 .on('change', changeRole);
64853
64854             enter
64855                 .append('button')
64856                 .attr('tabindex', -1)
64857                 .attr('class', 'remove button-input-action member-delete minor')
64858                 .on('click', deleteMembership)
64859                 .call(svgIcon('#operation-delete'));
64860
64861             if (taginfo) {
64862                 enter.each(bindTypeahead);
64863             }
64864
64865
64866             var newrow = list.selectAll('.member-row-new')
64867                 .data(showBlank ? [0] : []);
64868
64869             newrow.exit()
64870                 .remove();
64871
64872             enter = newrow.enter()
64873                 .append('li')
64874                 .attr('class', 'member-row member-row-new form-field');
64875
64876             enter
64877                 .append('input')
64878                 .attr('type', 'text')
64879                 .attr('class', 'member-entity-input')
64880                 .call(utilNoAuto);
64881
64882             enter
64883                 .append('input')
64884                 .attr('class', 'member-role')
64885                 .property('type', 'text')
64886                 .attr('maxlength', 255)
64887                 .attr('placeholder', t('inspector.role'))
64888                 .call(utilNoAuto)
64889                 .on('change', changeRole);
64890
64891             enter
64892                 .append('button')
64893                 .attr('tabindex', -1)
64894                 .attr('class', 'remove button-input-action member-delete minor')
64895                 .on('click', deleteMembership)
64896                 .call(svgIcon('#operation-delete'));
64897
64898             newrow = newrow
64899                 .merge(enter);
64900
64901             newrow.selectAll('.member-entity-input')
64902                 .call(d3combobox()
64903                     .container(context.container())
64904                     .minItems(1)
64905                     .fetcher(function(value, callback) { callback(relations(value)); })
64906                     .on('accept', onAccept)
64907                 );
64908
64909
64910             var addrel = wrap.selectAll('.add-relation')
64911                 .data([0]);
64912
64913             addrel = addrel.enter()
64914                 .append('button')
64915                 .attr('class', 'add-relation')
64916                 .merge(addrel);
64917
64918             addrel
64919                 .call(svgIcon('#icon-plus', 'light'))
64920                 .on('click', function() {
64921                     showBlank = true;
64922                     content(wrap);
64923                     list.selectAll('.member-entity-input').node().focus();
64924                 });
64925
64926
64927             function onAccept(d) {
64928                 var role = list.selectAll('.member-row-new .member-role').property('value');
64929                 addMembership(d, role);
64930             }
64931
64932
64933             function bindTypeahead(d) {
64934                 var row = select(this),
64935                     role = row.selectAll('input.member-role');
64936
64937                 function sort(value, data) {
64938                     var sameletter = [],
64939                         other = [];
64940                     for (var i = 0; i < data.length; i++) {
64941                         if (data[i].value.substring(0, value.length) === value) {
64942                             sameletter.push(data[i]);
64943                         } else {
64944                             other.push(data[i]);
64945                         }
64946                     }
64947                     return sameletter.concat(other);
64948                 }
64949
64950                 role.call(d3combobox()
64951                     .container(context.container())
64952                     .fetcher(function(role, callback) {
64953                         var rtype = d.relation.tags.type;
64954                         taginfo.roles({
64955                             debounce: true,
64956                             rtype: rtype || '',
64957                             geometry: context.geometry(id),
64958                             query: role
64959                         }, function(err, data) {
64960                             if (!err) callback(sort(role, data));
64961                         });
64962                     }));
64963             }
64964
64965
64966             function unbind() {
64967                 var row = select(this);
64968
64969                 row.selectAll('input.member-role')
64970                     .call(d3combobox.off);
64971             }
64972         }
64973     }
64974
64975
64976     rawMembershipEditor.entityID = function(_) {
64977         if (!arguments.length) return id;
64978         id = _;
64979         return rawMembershipEditor;
64980     };
64981
64982
64983     return rawMembershipEditor;
64984 }
64985
64986 function uiTagReference(tag) {
64987     var taginfo = services.taginfo,
64988         tagReference = {},
64989         button,
64990         body,
64991         loaded,
64992         showing;
64993
64994
64995     function findLocal(data) {
64996         var locale = utilDetect().locale.toLowerCase(),
64997             localized;
64998
64999         if (locale !== 'pt-br') {  // see #3776, prefer 'pt' over 'pt-br'
65000             localized = lodash.find(data, function(d) {
65001                 return d.lang.toLowerCase() === locale;
65002             });
65003             if (localized) return localized;
65004         }
65005
65006         // try the non-regional version of a language, like
65007         // 'en' if the language is 'en-US'
65008         if (locale.indexOf('-') !== -1) {
65009             var first = locale.split('-')[0];
65010             localized = lodash.find(data, function(d) {
65011                 return d.lang.toLowerCase() === first;
65012             });
65013             if (localized) return localized;
65014         }
65015
65016         // finally fall back to english
65017         return lodash.find(data, function(d) {
65018             return d.lang.toLowerCase() === 'en';
65019         });
65020     }
65021
65022
65023     function load(param) {
65024         if (!taginfo) return;
65025
65026         button.classed('tag-reference-loading', true);
65027
65028         taginfo.docs(param, function show(err, data) {
65029             var docs;
65030             if (!err && data) {
65031                 docs = findLocal(data);
65032             }
65033
65034             body.html('');
65035
65036
65037             if (!docs || !docs.title) {
65038                 if (param.hasOwnProperty('value')) {
65039                     load(lodash.omit(param, 'value'));   // retry with key only
65040                 } else {
65041                     body.append('p').text(t('inspector.no_documentation_key'));
65042                     done();
65043                 }
65044                 return;
65045             }
65046
65047
65048             if (docs.image && docs.image.thumb_url_prefix) {
65049                 body
65050                     .append('img')
65051                     .attr('class', 'wiki-image')
65052                     .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
65053                     .on('load', function() { done(); })
65054                     .on('error', function() { select(this).remove(); done(); });
65055             } else {
65056                 done();
65057             }
65058
65059             body
65060                 .append('p')
65061                 .text(docs.description || t('inspector.documentation_redirect'));
65062
65063             body
65064                 .append('a')
65065                 .attr('target', '_blank')
65066                 .attr('tabindex', -1)
65067                 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
65068                 .call(svgIcon('#icon-out-link', 'inline'))
65069                 .append('span')
65070                 .text(t('inspector.reference'));
65071         });
65072     }
65073
65074
65075     function done() {
65076         loaded = true;
65077
65078         button.classed('tag-reference-loading', false);
65079
65080         body.transition()
65081             .duration(200)
65082             .style('max-height', '200px')
65083             .style('opacity', '1');
65084
65085         showing = true;
65086     }
65087
65088
65089     function hide(selection$$1) {
65090         selection$$1 = selection$$1 || body.transition().duration(200);
65091
65092         selection$$1
65093             .style('max-height', '0px')
65094             .style('opacity', '0');
65095
65096         showing = false;
65097     }
65098
65099
65100     tagReference.button = function(selection$$1) {
65101         button = selection$$1.selectAll('.tag-reference-button')
65102             .data([0]);
65103
65104         button = button.enter()
65105             .append('button')
65106             .attr('class', 'tag-reference-button')
65107             .attr('tabindex', -1)
65108             .call(svgIcon('#icon-inspect'))
65109             .merge(button);
65110
65111         button
65112             .on('click', function () {
65113                 event.stopPropagation();
65114                 event.preventDefault();
65115                 if (showing) {
65116                     hide();
65117                 } else if (loaded) {
65118                     done();
65119                 } else {
65120                     load(tag);
65121                 }
65122             });
65123     };
65124
65125
65126     tagReference.body = function(selection$$1) {
65127         body = selection$$1.selectAll('.tag-reference-body')
65128             .data([0]);
65129
65130         body = body.enter()
65131             .append('div')
65132             .attr('class', 'tag-reference-body cf')
65133             .style('max-height', '0')
65134             .style('opacity', '0')
65135             .merge(body);
65136
65137         if (showing === false) {
65138             hide(body);
65139         }
65140     };
65141
65142
65143     tagReference.showing = function(_) {
65144         if (!arguments.length) return showing;
65145         showing = _;
65146         return tagReference;
65147     };
65148
65149
65150     return tagReference;
65151 }
65152
65153 function uiRawTagEditor(context) {
65154     var taginfo = services.taginfo,
65155         dispatch$$1 = dispatch('change'),
65156         expanded = context.storage('raw_tag_editor.expanded') === 'true',
65157         readOnlyTags = [],
65158         updatePreference = true,
65159         showBlank = false,
65160         newRow,
65161         state,
65162         preset,
65163         tags,
65164         id;
65165
65166
65167     function rawTagEditor(selection$$1) {
65168         var count = Object.keys(tags).filter(function(d) { return d; }).length;
65169
65170         selection$$1.call(uiDisclosure()
65171             .title(t('inspector.all_tags') + ' (' + count + ')')
65172             .expanded(expanded)
65173             .on('toggled', toggled)
65174             .content(content)
65175         );
65176
65177         function toggled(expanded) {
65178             if (updatePreference) {
65179                 context.storage('raw_tag_editor.expanded', expanded);
65180             }
65181             if (expanded) {
65182                 selection$$1.node().parentNode.scrollTop += 200;
65183             }
65184         }
65185     }
65186
65187
65188     function content(wrap) {
65189         var entries$$1 = entries(tags);
65190
65191         if (!entries$$1.length || showBlank) {
65192             showBlank = false;
65193             entries$$1.push({key: '', value: ''});
65194             newRow = '';
65195         }
65196
65197         var list = wrap.selectAll('.tag-list')
65198             .data([0]);
65199
65200         list = list.enter()
65201             .append('ul')
65202             .attr('class', 'tag-list')
65203             .merge(list);
65204
65205         var newTag = wrap.selectAll('.add-tag')
65206             .data([0]);
65207
65208         newTag.enter()
65209             .append('button')
65210             .attr('class', 'add-tag')
65211             .on('click', addTag)
65212             .call(svgIcon('#icon-plus', 'light'));
65213
65214
65215         var items = list.selectAll('.tag-row')
65216             .data(entries$$1, function(d) { return d.key; });
65217
65218         items.exit()
65219             .each(unbind)
65220             .remove();
65221
65222         // Enter
65223
65224         var enter = items.enter()
65225             .append('li')
65226             .attr('class', 'tag-row cf')
65227             .classed('readonly', isReadOnly);
65228
65229         enter
65230             .append('div')
65231             .attr('class', 'key-wrap')
65232             .append('input')
65233             .property('type', 'text')
65234             .attr('class', 'key')
65235             .attr('maxlength', 255)
65236             .call(utilNoAuto)
65237             .on('blur', keyChange)
65238             .on('change', keyChange);
65239
65240         enter
65241             .append('div')
65242             .attr('class', 'input-wrap-position')
65243             .append('input')
65244             .property('type', 'text')
65245             .attr('class', 'value')
65246             .attr('maxlength', 255)
65247             .call(utilNoAuto)
65248             .on('blur', valueChange)
65249             .on('change', valueChange)
65250             .on('keydown.push-more', pushMore);
65251
65252         enter
65253             .append('button')
65254             .attr('tabindex', -1)
65255             .attr('class', 'remove minor')
65256             .call(svgIcon('#operation-delete'));
65257
65258
65259         // Update
65260
65261         items = items
65262             .merge(enter)
65263             .sort(function(a, b) {
65264                 return (a.key === newRow && b.key !== newRow) ? 1
65265                     : (a.key !== newRow && b.key === newRow) ? -1
65266                     : ascending(a.key, b.key);
65267             });
65268
65269         items
65270             .each(function(tag) {
65271                 var row = select(this),
65272                     key = row.select('input.key'),      // propagate bound data to child
65273                     value = row.select('input.value');  // propagate bound data to child
65274
65275                 if (id && taginfo) {
65276                     bindTypeahead(key, value);
65277                 }
65278
65279                 var isRelation = (id && context.entity(id).type === 'relation'),
65280                     reference;
65281
65282                 if (isRelation && tag.key === 'type') {
65283                     reference = uiTagReference({ rtype: tag.value }, context);
65284                 } else {
65285                     reference = uiTagReference({ key: tag.key, value: tag.value }, context);
65286                 }
65287
65288                 if (state === 'hover') {
65289                     reference.showing(false);
65290                 }
65291
65292                 row
65293                     .call(reference.button)
65294                     .call(reference.body);
65295             });
65296
65297         items.selectAll('input.key')
65298             .attr('title', function(d) { return d.key; })
65299             .call(utilGetSetValue, function(d) { return d.key; })
65300             .property('disabled', isReadOnly);
65301
65302         items.selectAll('input.value')
65303             .attr('title', function(d) { return d.value; })
65304             .call(utilGetSetValue, function(d) { return d.value; })
65305             .property('disabled', isReadOnly);
65306
65307         items.selectAll('button.remove')
65308             .on('click', removeTag);
65309
65310
65311
65312         function isReadOnly(d) {
65313             return readOnlyTags.indexOf(d.key) !== -1;
65314         }
65315
65316
65317         function pushMore() {
65318             if (event.keyCode === 9 && !event.shiftKey &&
65319                 list.selectAll('li:last-child input.value').node() === this) {
65320                 addTag();
65321             }
65322         }
65323
65324
65325         function bindTypeahead(key, value) {
65326             if (isReadOnly({ key: key })) return;
65327             var geometry = context.geometry(id);
65328
65329             key.call(d3combobox()
65330                 .container(context.container())
65331                 .fetcher(function(value, callback) {
65332                     taginfo.keys({
65333                         debounce: true,
65334                         geometry: geometry,
65335                         query: value
65336                     }, function(err, data) {
65337                         if (!err) callback(sort(value, data));
65338                     });
65339                 }));
65340
65341             value.call(d3combobox()
65342                 .container(context.container())
65343                 .fetcher(function(value, callback) {
65344                     taginfo.values({
65345                         debounce: true,
65346                         key: utilGetSetValue(key),
65347                         geometry: geometry,
65348                         query: value
65349                     }, function(err, data) {
65350                         if (!err) callback(sort(value, data));
65351                     });
65352                 }));
65353
65354
65355             function sort(value, data) {
65356                 var sameletter = [],
65357                     other = [];
65358                 for (var i = 0; i < data.length; i++) {
65359                     if (data[i].value.substring(0, value.length) === value) {
65360                         sameletter.push(data[i]);
65361                     } else {
65362                         other.push(data[i]);
65363                     }
65364                 }
65365                 return sameletter.concat(other);
65366             }
65367         }
65368
65369
65370         function unbind() {
65371             var row = select(this);
65372
65373             row.selectAll('input.key')
65374                 .call(d3combobox.off);
65375
65376             row.selectAll('input.value')
65377                 .call(d3combobox.off);
65378         }
65379
65380
65381         function keyChange(d) {
65382             var kOld = d.key,
65383                 kNew = this.value.trim(),
65384                 tag = {};
65385
65386
65387             if (isReadOnly({ key: kNew })) {
65388                 this.value = kOld;
65389                 return;
65390             }
65391
65392             if (kNew && kNew !== kOld) {
65393                 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
65394                     base = match[1],
65395                     suffix = +(match[2] || 1);
65396                 while (tags[kNew]) {  // rename key if already in use
65397                     kNew = base + '_' + suffix++;
65398                 }
65399             }
65400             tag[kOld] = undefined;
65401             tag[kNew] = d.value;
65402
65403             d.key = kNew; // Maintain DOM identity through the subsequent update.
65404
65405             if (newRow === kOld) {  // see if this row is still a new row
65406                 newRow = ((d.value === '' || kNew === '') ? kNew : undefined);
65407             }
65408
65409             this.value = kNew;
65410             dispatch$$1.call('change', this, tag);
65411         }
65412
65413
65414         function valueChange(d) {
65415             if (isReadOnly(d)) return;
65416             var tag = {};
65417             tag[d.key] = this.value;
65418
65419             if (newRow === d.key && d.key !== '' && d.value !== '') {   // not a new row anymore
65420                 newRow = undefined;
65421             }
65422
65423             dispatch$$1.call('change', this, tag);
65424         }
65425
65426
65427         function removeTag(d) {
65428             if (isReadOnly(d)) return;
65429             var tag = {};
65430             tag[d.key] = undefined;
65431             dispatch$$1.call('change', this, tag);
65432             select(this.parentNode).remove();
65433         }
65434
65435
65436         function addTag() {
65437             // Wrapped in a setTimeout in case it's being called from a blur
65438             // handler. Without the setTimeout, the call to `content` would
65439             // wipe out the pending value change.
65440             setTimeout(function() {
65441                 showBlank = true;
65442                 content(wrap);
65443                 list.selectAll('li:last-child input.key').node().focus();
65444             }, 0);
65445         }
65446     }
65447
65448
65449     rawTagEditor.state = function(_) {
65450         if (!arguments.length) return state;
65451         state = _;
65452         return rawTagEditor;
65453     };
65454
65455
65456     rawTagEditor.preset = function(_) {
65457         if (!arguments.length) return preset;
65458         preset = _;
65459         if (preset.isFallback()) {
65460             expanded = true;
65461             updatePreference = false;
65462         } else {
65463             expanded = context.storage('raw_tag_editor.expanded') === 'true';
65464             updatePreference = true;
65465         }
65466         return rawTagEditor;
65467     };
65468
65469
65470     rawTagEditor.tags = function(_) {
65471         if (!arguments.length) return tags;
65472         tags = _;
65473         return rawTagEditor;
65474     };
65475
65476
65477     rawTagEditor.entityID = function(_) {
65478         if (!arguments.length) return id;
65479         id = _;
65480         return rawTagEditor;
65481     };
65482
65483
65484     rawTagEditor.expanded = function(_) {
65485         if (!arguments.length) return expanded;
65486         expanded = _;
65487         updatePreference = false;
65488         return rawTagEditor;
65489     };
65490
65491
65492     rawTagEditor.readOnlyTags = function(_) {
65493         if (!arguments.length) return readOnlyTags;
65494         readOnlyTags = _;
65495         return rawTagEditor;
65496     };
65497
65498
65499     return utilRebind(rawTagEditor, dispatch$$1, 'on');
65500 }
65501
65502 function uiFieldCheck(field, context) {
65503     var dispatch$$1 = dispatch('change'),
65504         options = field.strings && field.strings.options,
65505         values$$1 = [],
65506         texts = [],
65507         input = select(null),
65508         text$$1 = select(null),
65509         label = select(null),
65510         reverser = select(null),
65511         impliedYes,
65512         entityId,
65513         value;
65514
65515
65516     if (options) {
65517         for (var k in options) {
65518             values$$1.push(k === 'undefined' ? undefined : k);
65519             texts.push(field.t('options.' + k, { 'default': options[k] }));
65520         }
65521     } else {
65522         values$$1 = [undefined, 'yes'];
65523         texts = [t('inspector.unknown'), t('inspector.check.yes')];
65524         if (field.type !== 'defaultCheck') {
65525             values$$1.push('no');
65526             texts.push(t('inspector.check.no'));
65527         }
65528     }
65529
65530
65531     // Checks tags to see whether an undefined value is "Assumed to be Yes"
65532     function checkImpliedYes() {
65533         impliedYes = (field.id === 'oneway_yes');
65534
65535         // hack: pretend `oneway` field is a `oneway_yes` field
65536         // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
65537         if (field.id === 'oneway') {
65538             var entity = context.entity(entityId);
65539             for (var key in entity.tags) {
65540                 if (key in osmOneWayTags && (entity.tags[key] in osmOneWayTags[key])) {
65541                     impliedYes = true;
65542                     texts[0] = t('presets.fields.oneway_yes.options.undefined');
65543                     break;
65544                 }
65545             }
65546         }
65547     }
65548
65549
65550     function reverserHidden() {
65551         if (!select('div.inspector-hover').empty()) return true;
65552         return !(value === 'yes' || (impliedYes && !value));
65553     }
65554
65555
65556     function reverserSetText(selection$$1) {
65557         var entity = context.hasEntity(entityId);
65558         if (reverserHidden() || !entity) return selection$$1;
65559
65560         var first = entity.first(),
65561             last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last(),
65562             pseudoDirection = first < last,
65563             icon = pseudoDirection ? '#icon-forward' : '#icon-backward';
65564
65565         selection$$1.selectAll('.reverser-span')
65566             .text(t('inspector.check.reverser'))
65567             .call(svgIcon(icon, 'inline'));
65568
65569         return selection$$1;
65570     }
65571
65572
65573     var check = function(selection$$1) {
65574         checkImpliedYes();
65575         selection$$1.classed('checkselect', 'true');
65576
65577         label = selection$$1.selectAll('.preset-input-wrap')
65578             .data([0]);
65579
65580         var enter = label.enter()
65581             .append('label')
65582             .attr('class', 'preset-input-wrap');
65583
65584         enter
65585             .append('input')
65586             .property('indeterminate', field.type !== 'defaultCheck')
65587             .attr('type', 'checkbox')
65588             .attr('id', 'preset-input-' + field.id);
65589
65590         enter
65591             .append('span')
65592             .text(texts[0])
65593             .attr('class', 'value');
65594
65595         if (field.type === 'onewayCheck') {
65596             enter
65597                 .append('a')
65598                 .attr('id', 'preset-input-' + field.id + '-reverser')
65599                 .attr('class', 'reverser button' + (reverserHidden() ? ' hide' : ''))
65600                 .attr('href', '#')
65601                 .append('span')
65602                 .attr('class', 'reverser-span');
65603         }
65604
65605         label = label.merge(enter);
65606         input = label.selectAll('input');
65607         text$$1 = label.selectAll('span.value');
65608
65609         input
65610             .on('click', function() {
65611                 var t$$1 = {};
65612                 t$$1[field.key] = values$$1[(values$$1.indexOf(value) + 1) % values$$1.length];
65613                 dispatch$$1.call('change', this, t$$1);
65614                 event.stopPropagation();
65615             });
65616
65617         if (field.type === 'onewayCheck') {
65618             reverser = label.selectAll('.reverser');
65619
65620             reverser
65621                 .call(reverserSetText)
65622                 .on('click', function() {
65623                     event.preventDefault();
65624                     event.stopPropagation();
65625                     context.perform(
65626                         actionReverse(entityId),
65627                         t('operations.reverse.annotation')
65628                     );
65629                     select(this)
65630                         .call(reverserSetText);
65631                 });
65632         }
65633     };
65634
65635
65636     check.entity = function(_) {
65637         if (!arguments.length) return context.hasEntity(entityId);
65638         entityId = _.id;
65639         return check;
65640     };
65641
65642
65643     check.tags = function(tags) {
65644         checkImpliedYes();
65645         value = tags[field.key] && tags[field.key].toLowerCase();
65646
65647         if (field.type === 'onewayCheck' && (value === '1' || value === '-1')) {
65648             value = 'yes';
65649         }
65650
65651         input
65652             .property('indeterminate', field.type !== 'defaultCheck' && !value)
65653             .property('checked', value === 'yes');
65654
65655         text$$1
65656             .text(texts[values$$1.indexOf(value)]);
65657
65658         label
65659             .classed('set', !!value);
65660
65661         if (field.type === 'onewayCheck') {
65662             reverser
65663                 .classed('hide', reverserHidden())
65664                 .call(reverserSetText);
65665         }
65666     };
65667
65668
65669     check.focus = function() {
65670         input.node().focus();
65671     };
65672
65673     return utilRebind(check, dispatch$$1, 'on');
65674 }
65675
65676 function uiFieldCombo(field, context) {
65677     var dispatch$$1 = dispatch('change'),
65678         nominatim = services.geocoder,
65679         taginfo = services.taginfo,
65680         isMulti = (field.type === 'multiCombo'),
65681         isNetwork = (field.type === 'networkCombo'),
65682         isSemi = (field.type === 'semiCombo'),
65683         optstrings = field.strings && field.strings.options,
65684         optarray = field.options,
65685         snake_case = (field.snake_case || (field.snake_case === undefined)),
65686         combobox = d3combobox()
65687             .container(context.container())
65688             .minItems(isMulti || isSemi ? 1 : 2),
65689         comboData = [],
65690         multiData = [],
65691         container,
65692         input,
65693         entity,
65694         country;
65695
65696     // ensure multiCombo field.key ends with a ':'
65697     if (isMulti && field.key.match(/:$/) === null) {
65698         field.key += ':';
65699     }
65700
65701
65702     function snake(s) {
65703         return s.replace(/\s+/g, '_');
65704     }
65705
65706     function unsnake(s) {
65707         return s.replace(/_+/g, ' ');
65708     }
65709
65710     function clean(s) {
65711         return s.split(';')
65712             .map(function(s) { return s.trim(); })
65713             .join(';');
65714     }
65715
65716
65717     // returns the tag value for a display value
65718     // (for multiCombo, dval should be the key suffix, not the entire key)
65719     function tagValue(dval) {
65720         dval = clean(dval || '');
65721
65722         if (optstrings) {
65723             var match = lodash.find(comboData, function(o) {
65724                 return o.key && clean(o.value) === dval;
65725             });
65726             if (match) {
65727                 return match.key;
65728             }
65729         }
65730
65731         if (field.type === 'typeCombo' && !dval) {
65732             return 'yes';
65733         }
65734
65735         return (snake_case ? snake(dval) : dval) || undefined;
65736     }
65737
65738
65739     // returns the display value for a tag value
65740     // (for multiCombo, tval should be the key suffix, not the entire key)
65741     function displayValue(tval) {
65742         tval = tval || '';
65743
65744         if (optstrings) {
65745             var match = lodash.find(comboData, function(o) { return o.key === tval && o.value; });
65746             if (match) {
65747                 return match.value;
65748             }
65749         }
65750
65751         if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
65752             return '';
65753         }
65754
65755         return snake_case ? unsnake(tval) : tval;
65756     }
65757
65758
65759     function objectDifference(a, b) {
65760         return lodash.reject(a, function(d1) {
65761             return lodash.some(b, function(d2) { return d1.value === d2.value; });
65762         });
65763     }
65764
65765
65766     function initCombo(selection$$1, attachTo) {
65767         if (optstrings) {
65768             selection$$1.attr('readonly', 'readonly');
65769             selection$$1.call(combobox, attachTo);
65770             setStaticValues(setPlaceholder);
65771
65772         } else if (optarray) {
65773             selection$$1.call(combobox, attachTo);
65774             setStaticValues(setPlaceholder);
65775
65776         } else if (taginfo) {
65777             selection$$1.call(combobox.fetcher(setTaginfoValues), attachTo);
65778             setTaginfoValues('', setPlaceholder);
65779         }
65780     }
65781
65782
65783     function setStaticValues(callback) {
65784         if (!(optstrings || optarray)) return;
65785
65786         if (optstrings) {
65787             comboData = Object.keys(optstrings).map(function(k) {
65788                 var v = field.t('options.' + k, { 'default': optstrings[k] });
65789                 return {
65790                     key: k,
65791                     value: v,
65792                     title: v
65793                 };
65794             });
65795
65796         } else if (optarray) {
65797             comboData = optarray.map(function(k) {
65798                 var v = snake_case ? unsnake(k) : k;
65799                 return {
65800                     key: k,
65801                     value: v,
65802                     title: v
65803                 };
65804             });
65805         }
65806
65807         combobox.data(objectDifference(comboData, multiData));
65808         if (callback) callback(comboData);
65809     }
65810
65811
65812     function setTaginfoValues(q, callback) {
65813         var fn = isMulti ? 'multikeys' : 'values';
65814         var query = (isMulti ? field.key : '') + q;
65815         var hasCountryPrefix = isNetwork && country && country.indexOf(q.toLowerCase()) === 0;
65816         if (hasCountryPrefix) {
65817             query = country + ':';
65818         }
65819
65820         taginfo[fn]({
65821             debounce: (q !== ''),
65822             key: field.key,
65823             geometry: context.geometry(entity.id),
65824             query: query
65825         }, function(err, data) {
65826             if (err) return;
65827             if (hasCountryPrefix) {
65828                 data = lodash.filter(data, function(d) {
65829                     return d.value.toLowerCase().indexOf(country + ':') === 0;
65830                 });
65831             }
65832
65833             comboData = lodash.map(data, function(d) {
65834                 var k = d.value;
65835                 if (isMulti) k = k.replace(field.key, '');
65836                 var v = snake_case ? unsnake(k) : k;
65837                 return {
65838                     key: k,
65839                     value: v,
65840                     title: isMulti ? v : d.title
65841                 };
65842             });
65843
65844             comboData = objectDifference(comboData, multiData);
65845             if (callback) callback(comboData);
65846         });
65847     }
65848
65849
65850     function setPlaceholder(d) {
65851         var ph;
65852
65853         if (isMulti || isSemi) {
65854             ph = field.placeholder() || t('inspector.add');
65855         } else {
65856             var vals = lodash.map(d, 'value').filter(function(s) { return s.length < 20; }),
65857                 placeholders = vals.length > 1 ? vals : lodash.map(d, 'key');
65858             ph = field.placeholder() || placeholders.slice(0, 3).join(', ');
65859         }
65860
65861         if (ph.match(/(…|\.\.\.)$/) === null) {
65862             ph += '…';
65863         }
65864
65865         container.selectAll('input')
65866             .attr('placeholder', ph);
65867     }
65868
65869
65870     function change() {
65871         var val = tagValue(utilGetSetValue(input)),
65872             t$$1 = {};
65873
65874         if (isMulti || isSemi) {
65875             if (!val) return;
65876             container.classed('active', false);
65877             utilGetSetValue(input, '');
65878             if (isMulti) {
65879                 field.keys.push(field.key + val);
65880                 t$$1[field.key + val] = 'yes';
65881             } else if (isSemi) {
65882                 var arr = multiData.map(function(d) { return d.key; });
65883                 arr.push(val);
65884                 t$$1[field.key] = lodash.compact(lodash.uniq(arr)).join(';');
65885             }
65886             window.setTimeout(function() { input.node().focus(); }, 10);
65887
65888         } else {
65889             t$$1[field.key] = val;
65890         }
65891
65892         dispatch$$1.call('change', this, t$$1);
65893     }
65894
65895
65896     function removeMultikey(d) {
65897         event.stopPropagation();
65898         var t$$1 = {};
65899         if (isMulti) {
65900             t$$1[d.key] = undefined;
65901         } else if (isSemi) {
65902             lodash.remove(multiData, function(md) { return md.key === d.key; });
65903             var arr = multiData.map(function(md) { return md.key; });
65904             arr = lodash.compact(lodash.uniq(arr));
65905             t$$1[field.key] = arr.length ? arr.join(';') : undefined;
65906         }
65907         dispatch$$1.call('change', this, t$$1);
65908     }
65909
65910
65911     function combo(selection$$1) {
65912         if (isMulti || isSemi) {
65913             container = selection$$1.selectAll('ul').data([0]);
65914
65915             container = container.enter()
65916                 .append('ul')
65917                 .attr('class', 'form-field-multicombo')
65918                 .on('click', function() {
65919                     window.setTimeout(function() { input.node().focus(); }, 10);
65920                 })
65921                 .merge(container);
65922
65923         } else {
65924             container = selection$$1;
65925         }
65926
65927         input = container.selectAll('input')
65928             .data([0]);
65929
65930         input = input.enter()
65931             .append('input')
65932             .attr('type', 'text')
65933             .attr('id', 'preset-input-' + field.id)
65934             .call(utilNoAuto)
65935             .call(initCombo, selection$$1)
65936             .merge(input);
65937
65938         if (isNetwork && nominatim && entity) {
65939             var center = entity.extent(context.graph()).center();
65940             nominatim.countryCode(center, function (err, code) {
65941                 country = code;
65942             });
65943         }
65944
65945         input
65946             .on('change', change)
65947             .on('blur', change);
65948
65949         if (isMulti || isSemi) {
65950             combobox
65951                 .on('accept', function() {
65952                     input.node().blur();
65953                     input.node().focus();
65954                 });
65955
65956             input
65957                 .on('focus', function() { container.classed('active', true); });
65958         }
65959     }
65960
65961
65962     combo.tags = function(tags) {
65963         if (isMulti || isSemi) {
65964             multiData = [];
65965
65966             if (isMulti) {
65967                 // Build multiData array containing keys already set..
65968                 Object.keys(tags).forEach(function(key) {
65969                     if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return;
65970
65971                     var suffix = key.substring(field.key.length);
65972                     multiData.push({
65973                         key: key,
65974                         value: displayValue(suffix)
65975                     });
65976                 });
65977
65978                 // Set keys for form-field modified (needed for undo and reset buttons)..
65979                 field.keys = lodash.map(multiData, 'key');
65980
65981             } else if (isSemi) {
65982                 var arr = lodash.compact(lodash.uniq((tags[field.key] || '').split(';')));
65983                 multiData = arr.map(function(key) {
65984                     return {
65985                         key: key,
65986                         value: displayValue(key)
65987                     };
65988                 });
65989             }
65990
65991             // Exclude existing multikeys from combo options..
65992             var available = objectDifference(comboData, multiData);
65993             combobox.data(available);
65994
65995             // Hide 'Add' button if this field uses fixed set of
65996             // translateable optstrings and they're all currently used..
65997             container.selectAll('.combobox-input, .combobox-caret')
65998                 .classed('hide', optstrings && !available.length);
65999
66000
66001             // Render chips
66002             var chips = container.selectAll('.chips')
66003                 .data(multiData);
66004
66005             chips.exit()
66006                 .remove();
66007
66008             var enter = chips.enter()
66009                 .insert('li', 'input')
66010                 .attr('class', 'chips');
66011
66012             enter.append('span');
66013             enter.append('a');
66014
66015             chips = chips.merge(enter);
66016
66017             chips.select('span')
66018                 .text(function(d) { return d.value; });
66019
66020             chips.select('a')
66021                 .on('click', removeMultikey)
66022                 .attr('class', 'remove')
66023                 .text('×');
66024
66025         } else {
66026             utilGetSetValue(input, displayValue(tags[field.key]));
66027         }
66028     };
66029
66030
66031     combo.focus = function() {
66032         input.node().focus();
66033     };
66034
66035
66036     combo.entity = function(_) {
66037         if (!arguments.length) return entity;
66038         entity = _;
66039         return combo;
66040     };
66041
66042
66043     return utilRebind(combo, dispatch$$1, 'on');
66044 }
66045
66046 function uiFieldText(field, context) {
66047     var dispatch$$1 = dispatch('change'),
66048         nominatim = services.geocoder,
66049         input,
66050         entity;
66051
66052
66053     function i(selection$$1) {
66054         var fieldId = 'preset-input-' + field.id;
66055
66056         input = selection$$1.selectAll('input')
66057             .data([0]);
66058
66059         input = input.enter()
66060             .append('input')
66061             .attr('type', field.type)
66062             .attr('id', fieldId)
66063             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
66064             .call(utilNoAuto)
66065             .merge(input);
66066
66067         input
66068             .on('input', change(true))
66069             .on('blur', change())
66070             .on('change', change());
66071
66072         if (field.type === 'tel' && nominatim && entity) {
66073             var center = entity.extent(context.graph()).center();
66074             nominatim.countryCode(center, function (err, countryCode) {
66075                 if (err || !dataPhoneFormats[countryCode]) return;
66076                 selection$$1.selectAll('#' + fieldId)
66077                     .attr('placeholder', dataPhoneFormats[countryCode]);
66078             });
66079
66080         } else if (field.type === 'number') {
66081             input.attr('type', 'text');
66082
66083             var spinControl = selection$$1.selectAll('.spin-control')
66084                 .data([0]);
66085
66086             var enter = spinControl.enter()
66087                 .append('div')
66088                 .attr('class', 'spin-control');
66089
66090             enter
66091                 .append('button')
66092                 .datum(-1)
66093                 .attr('class', 'decrement')
66094                 .attr('tabindex', -1);
66095
66096             enter
66097                 .append('button')
66098                 .datum(1)
66099                 .attr('class', 'increment')
66100                 .attr('tabindex', -1);
66101
66102             spinControl = spinControl
66103                 .merge(enter);
66104
66105             spinControl.selectAll('button')
66106                 .on('click', function(d) {
66107                     event.preventDefault();
66108                     var num = parseInt(input.node().value || 0, 10);
66109                     if (!isNaN(num)) input.node().value = num + d;
66110                     change()();
66111                 });
66112         }
66113     }
66114
66115
66116     function change(onInput) {
66117         return function() {
66118             var t$$1 = {};
66119             t$$1[field.key] = utilGetSetValue(input) || undefined;
66120             dispatch$$1.call('change', this, t$$1, onInput);
66121         };
66122     }
66123
66124
66125     i.entity = function(_) {
66126         if (!arguments.length) return entity;
66127         entity = _;
66128         return i;
66129     };
66130
66131
66132     i.tags = function(tags) {
66133         utilGetSetValue(input, tags[field.key] || '');
66134     };
66135
66136
66137     i.focus = function() {
66138         var node = input.node();
66139         if (node) node.focus();
66140     };
66141
66142     return utilRebind(i, dispatch$$1, 'on');
66143 }
66144
66145 function uiFieldAccess(field, context) {
66146     var dispatch$$1 = dispatch('change'),
66147         items;
66148
66149     function access(selection$$1) {
66150         var wrap = selection$$1.selectAll('.preset-input-wrap')
66151             .data([0]);
66152
66153         wrap = wrap.enter()
66154             .append('div')
66155             .attr('class', 'cf preset-input-wrap')
66156             .append('ul')
66157             .merge(wrap);
66158
66159         var list = wrap.selectAll('ul')
66160             .data([0]);
66161
66162         list = list.enter()
66163             .append('ul')
66164             .merge(list);
66165
66166
66167         items = list.selectAll('li')
66168             .data(field.keys);
66169
66170         // Enter
66171         var enter = items.enter()
66172             .append('li')
66173             .attr('class', function(d) { return 'cf preset-access-' + d; });
66174
66175         enter
66176             .append('span')
66177             .attr('class', 'col6 label preset-label-access')
66178             .attr('for', function(d) { return 'preset-input-access-' + d; })
66179             .text(function(d) { return field.t('types.' + d); });
66180
66181         enter
66182             .append('div')
66183             .attr('class', 'col6 preset-input-access-wrap')
66184             .append('input')
66185             .attr('type', 'text')
66186             .attr('class', 'preset-input-access')
66187             .attr('id', function(d) { return 'preset-input-access-' + d; })
66188             .call(utilNoAuto)
66189             .each(function(d) {
66190                 select(this)
66191                     .call(d3combobox()
66192                         .container(context.container())
66193                         .data(access.options(d))
66194                     );
66195             });
66196
66197
66198         // Update
66199         items = items.merge(enter);
66200
66201         wrap.selectAll('.preset-input-access')
66202             .on('change', change)
66203             .on('blur', change);
66204     }
66205
66206
66207     function change(d) {
66208         var tag = {};
66209         tag[d] = utilGetSetValue(select(this)) || undefined;
66210         dispatch$$1.call('change', this, tag);
66211     }
66212
66213
66214     access.options = function(type) {
66215         var options = ['no', 'permissive', 'private', 'destination'];
66216
66217         if (type !== 'access') {
66218             options.unshift('yes');
66219             options.push('designated');
66220
66221             if (type === 'bicycle') {
66222                 options.push('dismount');
66223             }
66224         }
66225
66226         return options.map(function(option) {
66227             return {
66228                 title: field.t('options.' + option + '.description'),
66229                 value: option
66230             };
66231         });
66232     };
66233
66234
66235     var placeholders = {
66236         footway: {
66237             foot: 'designated',
66238             motor_vehicle: 'no'
66239         },
66240         steps: {
66241             foot: 'yes',
66242             motor_vehicle: 'no',
66243             bicycle: 'no',
66244             horse: 'no'
66245         },
66246         pedestrian: {
66247             foot: 'yes',
66248             motor_vehicle: 'no'
66249         },
66250         cycleway: {
66251             motor_vehicle: 'no',
66252             bicycle: 'designated'
66253         },
66254         bridleway: {
66255             motor_vehicle: 'no',
66256             horse: 'designated'
66257         },
66258         path: {
66259             foot: 'yes',
66260             motor_vehicle: 'no',
66261             bicycle: 'yes',
66262             horse: 'yes'
66263         },
66264         motorway: {
66265             foot: 'no',
66266             motor_vehicle: 'yes',
66267             bicycle: 'no',
66268             horse: 'no'
66269         },
66270         trunk: {
66271             motor_vehicle: 'yes'
66272         },
66273         primary: {
66274             foot: 'yes',
66275             motor_vehicle: 'yes',
66276             bicycle: 'yes',
66277             horse: 'yes'
66278         },
66279         secondary: {
66280             foot: 'yes',
66281             motor_vehicle: 'yes',
66282             bicycle: 'yes',
66283             horse: 'yes'
66284         },
66285         tertiary: {
66286             foot: 'yes',
66287             motor_vehicle: 'yes',
66288             bicycle: 'yes',
66289             horse: 'yes'
66290         },
66291         residential: {
66292             foot: 'yes',
66293             motor_vehicle: 'yes',
66294             bicycle: 'yes',
66295             horse: 'yes'
66296         },
66297         unclassified: {
66298             foot: 'yes',
66299             motor_vehicle: 'yes',
66300             bicycle: 'yes',
66301             horse: 'yes'
66302         },
66303         service: {
66304             foot: 'yes',
66305             motor_vehicle: 'yes',
66306             bicycle: 'yes',
66307             horse: 'yes'
66308         },
66309         motorway_link: {
66310             foot: 'no',
66311             motor_vehicle: 'yes',
66312             bicycle: 'no',
66313             horse: 'no'
66314         },
66315         trunk_link: {
66316             motor_vehicle: 'yes'
66317         },
66318         primary_link: {
66319             foot: 'yes',
66320             motor_vehicle: 'yes',
66321             bicycle: 'yes',
66322             horse: 'yes'
66323         },
66324         secondary_link: {
66325             foot: 'yes',
66326             motor_vehicle: 'yes',
66327             bicycle: 'yes',
66328             horse: 'yes'
66329         },
66330         tertiary_link: {
66331             foot: 'yes',
66332             motor_vehicle: 'yes',
66333             bicycle: 'yes',
66334             horse: 'yes'
66335         }
66336     };
66337
66338
66339     access.tags = function(tags) {
66340         utilGetSetValue(items.selectAll('.preset-input-access'),
66341             function(d) { return tags[d] || ''; })
66342             .attr('placeholder', function() {
66343                 return tags.access ? tags.access : field.placeholder();
66344             });
66345
66346         items.selectAll('#preset-input-access-access')
66347             .attr('placeholder', 'yes');
66348
66349         lodash.forEach(placeholders[tags.highway], function(v, k) {
66350             items.selectAll('#preset-input-access-' + k)
66351                 .attr('placeholder', function() { return (tags.access || v); });
66352         });
66353     };
66354
66355
66356     access.focus = function() {
66357         items.selectAll('.preset-input-access')
66358             .node().focus();
66359     };
66360
66361
66362     return utilRebind(access, dispatch$$1, 'on');
66363 }
66364
66365 function uiFieldAddress(field, context) {
66366     var dispatch$$1 = dispatch('init', 'change'),
66367         nominatim = services.geocoder,
66368         wrap = select(null),
66369         isInitialized = false,
66370         entity;
66371
66372     function getNearStreets() {
66373         var extent$$1 = entity.extent(context.graph()),
66374             l = extent$$1.center(),
66375             box = geoExtent$$1(l).padByMeters(200);
66376
66377         var streets = context.intersects(box)
66378             .filter(isAddressable)
66379             .map(function(d) {
66380                 var loc = context.projection([
66381                     (extent$$1[0][0] + extent$$1[1][0]) / 2,
66382                     (extent$$1[0][1] + extent$$1[1][1]) / 2]),
66383                     choice = geoChooseEdge(context.childNodes(d), loc, context.projection);
66384                 return {
66385                     title: d.tags.name,
66386                     value: d.tags.name,
66387                     dist: choice.distance
66388                 };
66389             })
66390             .sort(function(a, b) {
66391                 return a.dist - b.dist;
66392             });
66393
66394         return lodash.uniqBy(streets, 'value');
66395
66396         function isAddressable(d) {
66397             return d.tags.highway && d.tags.name && d.type === 'way';
66398         }
66399     }
66400
66401
66402     function getNearCities() {
66403         var extent$$1 = entity.extent(context.graph()),
66404             l = extent$$1.center(),
66405             box = geoExtent$$1(l).padByMeters(200);
66406
66407         var cities = context.intersects(box)
66408             .filter(isAddressable)
66409             .map(function(d) {
66410                 return {
66411                     title: d.tags['addr:city'] || d.tags.name,
66412                     value: d.tags['addr:city'] || d.tags.name,
66413                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
66414                 };
66415             })
66416             .sort(function(a, b) {
66417                 return a.dist - b.dist;
66418             });
66419
66420         return lodash.uniqBy(cities, 'value');
66421
66422
66423         function isAddressable(d) {
66424             if (d.tags.name &&
66425                 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
66426                 return true;
66427
66428             if (d.tags.place && d.tags.name && (
66429                     d.tags.place === 'city' ||
66430                     d.tags.place === 'town' ||
66431                     d.tags.place === 'village'))
66432                 return true;
66433
66434             if (d.tags['addr:city']) return true;
66435
66436             return false;
66437         }
66438     }
66439
66440     function getNearValues(key) {
66441         var extent$$1 = entity.extent(context.graph()),
66442             l = extent$$1.center(),
66443             box = geoExtent$$1(l).padByMeters(200);
66444
66445         var results = context.intersects(box)
66446             .filter(function hasTag(d) {
66447                 return d.tags[key];
66448             })
66449             .map(function(d) {
66450                 return {
66451                     title: d.tags[key],
66452                     value: d.tags[key],
66453                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
66454                 };
66455             })
66456             .sort(function(a, b) {
66457                 return a.dist - b.dist;
66458             });
66459
66460         return lodash.uniqBy(results, 'value');
66461     }
66462
66463
66464     function initCallback(err, countryCode) {
66465         if (err) return;
66466
66467         var addressFormat = lodash.find(dataAddressFormats, function (a) {
66468             return a && a.countryCodes && lodash.includes(a.countryCodes, countryCode.toLowerCase());
66469         }) || lodash.first(dataAddressFormats);
66470
66471         var widths = addressFormat.widths || {
66472             housenumber: 1/3, street: 2/3,
66473             city: 2/3, state: 1/4, postcode: 1/3
66474         };
66475
66476         function row(r) {
66477             // Normalize widths.
66478             var total = lodash.reduce(r, function(sum$$1, field) {
66479                 return sum$$1 + (widths[field] || 0.5);
66480             }, 0);
66481
66482             return r.map(function (field) {
66483                 return {
66484                     id: field,
66485                     width: (widths[field] || 0.5) / total
66486                 };
66487             });
66488         }
66489
66490         wrap.selectAll('div.addr-row')
66491             .data(addressFormat.format)
66492             .enter()
66493             .append('div')
66494             .attr('class', 'addr-row')
66495             .selectAll('input')
66496             .data(row)
66497             .enter()
66498             .append('input')
66499             .property('type', 'text')
66500             .attr('placeholder', function (d) {
66501                 var localkey = d.id + '!' + countryCode.toLowerCase(),
66502                     tkey = field.strings.placeholders[localkey] ? localkey : d.id;
66503                 return field.t('placeholders.' + tkey);
66504             })
66505             .attr('class', function (d) { return 'addr-' + d.id; })
66506             .call(utilNoAuto)
66507             .style('width', function (d) { return d.width * 100 + '%'; });
66508
66509         // Update
66510
66511         // setup dropdowns for common address tags
66512         var dropdowns = addressFormat.dropdowns || [
66513             'city', 'county', 'country', 'district', 'hamlet',
66514             'neighbourhood', 'place', 'postcode', 'province',
66515             'quarter', 'state', 'street', 'subdistrict', 'suburb'
66516         ];
66517
66518         // If fields exist for any of these tags, create dropdowns to pick nearby values..
66519         dropdowns.forEach(function(tag) {
66520             var nearValues = (tag === 'street') ? getNearStreets
66521                     : (tag === 'city') ? getNearCities
66522                     : getNearValues;
66523
66524             wrap.selectAll('input.addr-' + tag)
66525                 .call(d3combobox()
66526                     .container(context.container())
66527                     .minItems(1)
66528                     .fetcher(function(value, callback) {
66529                         callback(nearValues('addr:' + tag));
66530                     })
66531                 );
66532         });
66533
66534         wrap.selectAll('input')
66535             .on('blur', change())
66536             .on('change', change());
66537
66538         wrap.selectAll('input:not(.combobox-input)')
66539             .on('input', change(true));
66540
66541         dispatch$$1.call('init');
66542         isInitialized = true;
66543     }
66544
66545
66546     function address(selection$$1) {
66547         isInitialized = false;
66548
66549         wrap = selection$$1.selectAll('.preset-input-wrap')
66550             .data([0]);
66551
66552         wrap = wrap.enter()
66553             .append('div')
66554             .attr('class', 'preset-input-wrap')
66555             .merge(wrap);
66556
66557         if (nominatim && entity) {
66558             var center = entity.extent(context.graph()).center();
66559             nominatim.countryCode(center, initCallback);
66560         }
66561     }
66562
66563
66564     function change(onInput) {
66565         return function() {
66566             var tags = {};
66567
66568             wrap.selectAll('input')
66569                 .each(function (field) {
66570                     tags['addr:' + field.id] = this.value || undefined;
66571                 });
66572
66573             dispatch$$1.call('change', this, tags, onInput);
66574         };
66575     }
66576
66577
66578     function updateTags(tags) {
66579         utilGetSetValue(wrap.selectAll('input'), function (field) {
66580             return tags['addr:' + field.id] || '';
66581         });
66582     }
66583
66584
66585     address.entity = function(_) {
66586         if (!arguments.length) return entity;
66587         entity = _;
66588         return address;
66589     };
66590
66591
66592     address.tags = function(tags) {
66593         if (isInitialized) {
66594             updateTags(tags);
66595         } else {
66596             dispatch$$1.on('init', function () {
66597                 dispatch$$1.on('init', null);
66598                 updateTags(tags);
66599             });
66600         }
66601     };
66602
66603
66604     address.focus = function() {
66605         var node = wrap.selectAll('input').node();
66606         if (node) node.focus();
66607     };
66608
66609
66610     return utilRebind(address, dispatch$$1, 'on');
66611 }
66612
66613 function uiFieldCycleway(field, context) {
66614     var dispatch$$1 = dispatch('change'),
66615         items = select(null);
66616
66617
66618     function cycleway(selection$$1) {
66619
66620         function stripcolon(s) {
66621             return s.replace(':', '');
66622         }
66623
66624
66625         var wrap = selection$$1.selectAll('.preset-input-wrap')
66626             .data([0]);
66627
66628         wrap = wrap.enter()
66629             .append('div')
66630             .attr('class', 'cf preset-input-wrap')
66631             .merge(wrap);
66632
66633
66634         var div = wrap.selectAll('ul')
66635             .data([0]);
66636
66637         div = div.enter()
66638             .append('ul')
66639             .merge(div);
66640
66641
66642         items = div.selectAll('li')
66643             .data(field.keys);
66644
66645         var enter = items.enter()
66646             .append('li')
66647             .attr('class', function(d) { return 'cf preset-cycleway-' + stripcolon(d); });
66648
66649         enter
66650             .append('span')
66651             .attr('class', 'col6 label preset-label-cycleway')
66652             .attr('for', function(d) { return 'preset-input-cycleway-' + stripcolon(d); })
66653             .text(function(d) { return field.t('types.' + d); });
66654
66655         enter
66656             .append('div')
66657             .attr('class', 'col6 preset-input-cycleway-wrap')
66658             .append('input')
66659             .attr('type', 'text')
66660             .attr('class', function(d) { return 'preset-input-cycleway preset-input-' + stripcolon(d); })
66661             .call(utilNoAuto)
66662             .each(function(d) {
66663                 select(this)
66664                     .call(d3combobox()
66665                         .container(context.container())
66666                         .data(cycleway.options(d))
66667                     );
66668             });
66669
66670
66671         // Update
66672         wrap.selectAll('.preset-input-cycleway')
66673             .on('change', change)
66674             .on('blur', change);
66675     }
66676
66677
66678     function change() {
66679         var left = utilGetSetValue(select('.preset-input-cyclewayleft')),
66680             right = utilGetSetValue(select('.preset-input-cyclewayright')),
66681             tag = {};
66682
66683         if (left === 'none' || left === '') { left = undefined; }
66684         if (right === 'none' || right === '') { right = undefined; }
66685
66686         // Always set both left and right as changing one can affect the other
66687         tag = {
66688             cycleway: undefined,
66689             'cycleway:left': left,
66690             'cycleway:right': right
66691         };
66692
66693         // If the left and right tags match, use the cycleway tag to tag both
66694         // sides the same way
66695         if (left === right) {
66696             tag = {
66697                 cycleway: left,
66698                 'cycleway:left': undefined,
66699                 'cycleway:right': undefined
66700             };
66701         }
66702
66703         dispatch$$1.call('change', this, tag);
66704     }
66705
66706
66707     cycleway.options = function() {
66708         return keys(field.strings.options).map(function(option) {
66709             return {
66710                 title: field.t('options.' + option + '.description'),
66711                 value: option
66712             };
66713         });
66714     };
66715
66716
66717     cycleway.tags = function(tags) {
66718         utilGetSetValue(items.selectAll('.preset-input-cycleway'), function(d) {
66719                 // If cycleway is set, always return that
66720                 if (tags.cycleway) {
66721                     return tags.cycleway;
66722                 }
66723                 return tags[d] || '';
66724             })
66725             .attr('placeholder', field.placeholder());
66726     };
66727
66728
66729     cycleway.focus = function() {
66730         items.selectAll('.preset-input-cycleway')
66731             .node().focus();
66732     };
66733
66734
66735     return utilRebind(cycleway, dispatch$$1, 'on');
66736 }
66737
66738 function uiFieldLanes(field, context) {
66739     var dispatch$$1 = dispatch('change'),
66740         LANE_WIDTH = 40,
66741         LANE_HEIGHT = 200,
66742         wayID,
66743         lanesData;
66744
66745     function lanes(selection$$1) {
66746         lanesData = context.entity(wayID).lanes();
66747
66748         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
66749             selection$$1.call(lanes.off);
66750             return;
66751         }
66752
66753         var wrap = selection$$1.selectAll('.preset-input-wrap')
66754             .data([0]);
66755
66756         wrap = wrap.enter()
66757             .append('div')
66758             .attr('class', 'preset-input-wrap')
66759             .merge(wrap);
66760
66761         var surface =  wrap.selectAll('.surface')
66762             .data([0]);
66763
66764         var d = utilGetDimensions(wrap);
66765         var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
66766
66767         surface = surface.enter()
66768             .append('svg')
66769             .attr('width', d[0])
66770             .attr('height', 300)
66771             .attr('class', 'surface')
66772             .merge(surface);
66773
66774
66775         var lanesSelection = surface.selectAll('.lanes')
66776             .data([0]);
66777
66778         lanesSelection = lanesSelection.enter()
66779             .append('g')
66780             .attr('class', 'lanes')
66781             .merge(lanesSelection);
66782
66783         lanesSelection
66784             .attr('transform', function () {
66785                 return 'translate(' + (freeSpace / 2) + ', 0)';
66786             });
66787
66788
66789         var lane = lanesSelection.selectAll('.lane')
66790            .data(lanesData.lanes);
66791
66792         lane.exit()
66793             .remove();
66794
66795         var enter = lane.enter()
66796             .append('g')
66797             .attr('class', 'lane');
66798
66799         enter
66800             .append('g')
66801             .append('rect')
66802             .attr('y', 50)
66803             .attr('width', LANE_WIDTH)
66804             .attr('height', LANE_HEIGHT);
66805
66806         enter
66807             .append('g')
66808             .attr('class', 'forward')
66809             .append('text')
66810             .attr('y', 40)
66811             .attr('x', 14)
66812             .text('▲');
66813
66814         enter
66815             .append('g')
66816             .attr('class', 'bothways')
66817             .append('text')
66818             .attr('y', 40)
66819             .attr('x', 14)
66820             .text('▲▼');
66821
66822         enter
66823             .append('g')
66824             .attr('class', 'backward')
66825             .append('text')
66826             .attr('y', 40)
66827             .attr('x', 14)
66828             .text('▼');
66829
66830
66831         lane = lane
66832             .merge(enter);
66833
66834         lane
66835             .attr('transform', function(d) {
66836                 return 'translate(' + (LANE_WIDTH * d.index * 1.5) + ', 0)';
66837             });
66838
66839         lane.select('.forward')
66840             .style('visibility', function(d) {
66841                 return d.direction === 'forward' ? 'visible' : 'hidden';
66842             });
66843
66844         lane.select('.bothways')
66845             .style('visibility', function(d) {
66846                 return d.direction === 'bothways' ? 'visible' : 'hidden';
66847             });
66848
66849         lane.select('.backward')
66850             .style('visibility', function(d) {
66851                 return d.direction === 'backward' ? 'visible' : 'hidden';
66852             });
66853     }
66854
66855
66856     lanes.entity = function(_) {
66857         if (!wayID || wayID !== _.id) {
66858             wayID = _.id;
66859         }
66860     };
66861
66862     lanes.tags = function() {};
66863     lanes.focus = function() {};
66864     lanes.off = function() {};
66865
66866     return utilRebind(lanes, dispatch$$1, 'on');
66867 }
66868
66869 function uiFieldLocalized(field, context) {
66870     var dispatch$$1 = dispatch('change', 'input'),
66871         wikipedia = services.wikipedia,
66872         input = select(null),
66873         localizedInputs = select(null),
66874         wikiTitles,
66875         entity;
66876
66877
66878     function localized(selection$$1) {
66879         input = selection$$1.selectAll('.localized-main')
66880             .data([0]);
66881
66882         input = input.enter()
66883             .append('input')
66884             .attr('type', 'text')
66885             .attr('id', 'preset-input-' + field.id)
66886             .attr('class', 'localized-main')
66887             .attr('placeholder', field.placeholder())
66888             .call(utilNoAuto)
66889             .merge(input);
66890
66891         if (field.id === 'name') {
66892             var preset = context.presets().match(entity, context.graph());
66893             input
66894                 .call(d3combobox()
66895                     .container(context.container())
66896                     .fetcher(utilSuggestNames(preset, dataSuggestions))
66897                 );
66898         }
66899
66900         input
66901             .on('input', change(true))
66902             .on('blur', change())
66903             .on('change', change());
66904
66905
66906         var translateButton = selection$$1.selectAll('.localized-add')
66907             .data([0]);
66908
66909         translateButton = translateButton.enter()
66910             .append('button')
66911             .attr('class', 'button-input-action localized-add minor')
66912             .attr('tabindex', -1)
66913             .call(svgIcon('#icon-plus'))
66914             .call(tooltip()
66915                 .title(t('translate.translate'))
66916                 .placement('left'))
66917             .merge(translateButton);
66918
66919         translateButton
66920             .on('click', addNew);
66921
66922
66923         localizedInputs = selection$$1.selectAll('.localized-wrap')
66924             .data([0]);
66925
66926         localizedInputs = localizedInputs.enter().append('div')
66927             .attr('class', 'localized-wrap')
66928             .merge(localizedInputs);
66929     }
66930
66931
66932     function addNew() {
66933         event.preventDefault();
66934         var data$$1 = localizedInputs.selectAll('div.entry').data();
66935         var defaultLang = utilDetect().locale.toLowerCase().split('-')[0];
66936         var langExists = lodash.find(data$$1, function(datum) { return datum.lang === defaultLang;});
66937         var isLangEn = defaultLang.indexOf('en') > -1;
66938         if (isLangEn || langExists) {
66939             defaultLang = '';
66940         }
66941         data$$1.push({ lang: defaultLang, value: '' });
66942         localizedInputs.call(render, data$$1);
66943     }
66944
66945
66946     function change(onInput) {
66947         return function() {
66948             var t$$1 = {};
66949             t$$1[field.key] = utilGetSetValue(select(this)) || undefined;
66950             dispatch$$1.call('change', this, t$$1, onInput);
66951         };
66952     }
66953
66954
66955     function key(lang) {
66956         return field.key + ':' + lang;
66957     }
66958
66959
66960     function changeLang(d) {
66961         var lang = utilGetSetValue(select(this)),
66962             t$$1 = {},
66963             language = lodash.find(dataWikipedia, function(d) {
66964                 return d[0].toLowerCase() === lang.toLowerCase() ||
66965                     d[1].toLowerCase() === lang.toLowerCase();
66966             });
66967
66968         if (language) lang = language[2];
66969
66970         if (d.lang && d.lang !== lang) {
66971             t$$1[key(d.lang)] = undefined;
66972         }
66973
66974         var value = utilGetSetValue(select(this.parentNode)
66975             .selectAll('.localized-value'));
66976
66977         if (lang && value) {
66978             t$$1[key(lang)] = value;
66979         } else if (lang && wikiTitles && wikiTitles[d.lang]) {
66980             t$$1[key(lang)] = wikiTitles[d.lang];
66981         }
66982
66983         d.lang = lang;
66984         dispatch$$1.call('change', this, t$$1);
66985     }
66986
66987
66988     function changeValue(d) {
66989         if (!d.lang) return;
66990         var t$$1 = {};
66991         t$$1[key(d.lang)] = utilGetSetValue(select(this)) || undefined;
66992         dispatch$$1.call('change', this, t$$1);
66993     }
66994
66995
66996     function fetcher(value, cb) {
66997         var v = value.toLowerCase();
66998
66999         cb(dataWikipedia.filter(function(d) {
67000             return d[0].toLowerCase().indexOf(v) >= 0 ||
67001             d[1].toLowerCase().indexOf(v) >= 0 ||
67002             d[2].toLowerCase().indexOf(v) >= 0;
67003         }).map(function(d) {
67004             return { value: d[1] };
67005         }));
67006     }
67007
67008
67009     function render(selection$$1, data$$1) {
67010         var wraps = selection$$1.selectAll('div.entry').
67011             data(data$$1, function(d) { return d.lang; });
67012
67013         wraps.exit()
67014             .transition()
67015             .duration(200)
67016             .style('max-height','0px')
67017             .style('opacity', '0')
67018             .style('top','-10px')
67019             .remove();
67020
67021         var innerWrap = wraps.enter()
67022             .insert('div', ':first-child');
67023
67024         innerWrap.attr('class', 'entry')
67025             .each(function() {
67026                 var wrap = select(this);
67027                 var langcombo = d3combobox()
67028                     .container(context.container())
67029                     .fetcher(fetcher)
67030                     .minItems(0);
67031
67032                 var label = wrap
67033                     .append('label')
67034                     .attr('class','form-label')
67035                     .text(t('translate.localized_translation_label'))
67036                     .attr('for','localized-lang');
67037
67038                 label
67039                     .append('button')
67040                     .attr('class', 'minor remove')
67041                     .on('click', function(d){
67042                         event.preventDefault();
67043                         var t$$1 = {};
67044                         t$$1[key(d.lang)] = undefined;
67045                         dispatch$$1.call('change', this, t$$1);
67046                         select(this.parentNode.parentNode)
67047                             .style('top','0')
67048                             .style('max-height','240px')
67049                             .transition()
67050                             .style('opacity', '0')
67051                             .style('max-height','0px')
67052                             .remove();
67053                     })
67054                     .call(svgIcon('#operation-delete'));
67055
67056                 wrap
67057                     .append('input')
67058                     .attr('class', 'localized-lang')
67059                     .attr('type', 'text')
67060                     .attr('placeholder',t('translate.localized_translation_language'))
67061                     .on('blur', changeLang)
67062                     .on('change', changeLang)
67063                     .call(langcombo);
67064
67065                 wrap
67066                     .append('input')
67067                     .on('blur', changeValue)
67068                     .on('change', changeValue)
67069                     .attr('type', 'text')
67070                     .attr('placeholder', t('translate.localized_translation_name'))
67071                     .attr('class', 'localized-value');
67072             });
67073
67074         innerWrap
67075             .style('margin-top', '0px')
67076             .style('max-height', '0px')
67077             .style('opacity', '0')
67078             .transition()
67079             .duration(200)
67080             .style('margin-top', '10px')
67081             .style('max-height', '240px')
67082             .style('opacity', '1')
67083             .on('end', function() {
67084                 select(this)
67085                     .style('max-height', '')
67086                     .style('overflow', 'visible');
67087             });
67088
67089
67090         var entry = selection$$1.selectAll('.entry');
67091
67092         utilGetSetValue(entry.select('.localized-lang'), function(d) {
67093                 var lang = lodash.find(dataWikipedia, function(lang) { return lang[2] === d.lang; });
67094                 return lang ? lang[1] : d.lang;
67095             });
67096
67097         utilGetSetValue(entry.select('.localized-value'),
67098             function(d) { return d.value; });
67099     }
67100
67101
67102     localized.tags = function(tags) {
67103         // Fetch translations from wikipedia
67104         if (tags.wikipedia && !wikiTitles) {
67105             wikiTitles = {};
67106             var wm = tags.wikipedia.match(/([^:]+):(.+)/);
67107             if (wm && wm[0] && wm[1]) {
67108                 wikipedia.translations(wm[1], wm[2], function(d) {
67109                     wikiTitles = d;
67110                 });
67111             }
67112         }
67113
67114         utilGetSetValue(input, tags[field.key] || '');
67115
67116         var postfixed = [], k, m;
67117         for (k in tags) {
67118             m = k.match(/^(.*):([a-zA-Z_-]+)$/);
67119             if (m && m[1] === field.key && m[2]) {
67120                 postfixed.push({ lang: m[2], value: tags[k] });
67121             }
67122         }
67123
67124         localizedInputs.call(render, postfixed.reverse());
67125     };
67126
67127
67128     localized.focus = function() {
67129         input.node().focus();
67130     };
67131
67132
67133     localized.entity = function(_) {
67134         if (!arguments.length) return entity;
67135         entity = _;
67136         return localized;
67137     };
67138
67139     return utilRebind(localized, dispatch$$1, 'on');
67140 }
67141
67142 function uiFieldMaxspeed(field, context) {
67143     var dispatch$$1 = dispatch('change'),
67144         entity,
67145         isImperial,
67146         unitInput = select(null),
67147         input = select(null),
67148         combobox;
67149
67150     var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
67151         imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
67152
67153
67154     function maxspeed(selection$$1) {
67155         combobox = d3combobox()
67156             .container(context.container());
67157
67158         var unitCombobox = d3combobox()
67159             .container(context.container())
67160             .data(['km/h', 'mph'].map(comboValues));
67161
67162         input = selection$$1.selectAll('#preset-input-' + field.id)
67163             .data([0]);
67164
67165         input = input.enter()
67166             .append('input')
67167             .attr('type', 'text')
67168             .attr('id', 'preset-input-' + field.id)
67169             .attr('placeholder', field.placeholder())
67170             .call(utilNoAuto)
67171             .call(combobox)
67172             .merge(input);
67173
67174         input
67175             .on('change', change)
67176             .on('blur', change);
67177
67178         var childNodes = context.graph().childNodes(context.entity(entity.id)),
67179             loc = childNodes[~~(childNodes.length/2)].loc;
67180
67181         isImperial = lodash.some(dataImperial.features, function(f) {
67182             return lodash.some(f.geometry.coordinates, function(d) {
67183                 return geoPointInPolygon(loc, d);
67184             });
67185         });
67186
67187         unitInput = selection$$1.selectAll('input.maxspeed-unit')
67188             .data([0]);
67189
67190         unitInput = unitInput.enter()
67191             .append('input')
67192             .attr('type', 'text')
67193             .attr('class', 'maxspeed-unit')
67194             .call(unitCombobox)
67195             .merge(unitInput);
67196
67197         unitInput
67198             .on('blur', changeUnits)
67199             .on('change', changeUnits);
67200
67201
67202         function changeUnits() {
67203             isImperial = utilGetSetValue(unitInput) === 'mph';
67204             utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
67205             setSuggestions();
67206             change();
67207         }
67208     }
67209
67210
67211     function setSuggestions() {
67212         combobox.data((isImperial ? imperialValues : metricValues).map(comboValues));
67213         utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
67214     }
67215
67216
67217     function comboValues(d) {
67218         return {
67219             value: d.toString(),
67220             title: d.toString()
67221         };
67222     }
67223
67224
67225     function change() {
67226         var tag = {},
67227             value = utilGetSetValue(input);
67228
67229         if (!value) {
67230             tag[field.key] = undefined;
67231         } else if (isNaN(value) || !isImperial) {
67232             tag[field.key] = value;
67233         } else {
67234             tag[field.key] = value + ' mph';
67235         }
67236
67237         dispatch$$1.call('change', this, tag);
67238     }
67239
67240
67241     maxspeed.tags = function(tags) {
67242         var value = tags[field.key];
67243
67244         if (value && value.indexOf('mph') >= 0) {
67245             value = parseInt(value, 10);
67246             isImperial = true;
67247         } else if (value) {
67248             isImperial = false;
67249         }
67250
67251         setSuggestions();
67252         utilGetSetValue(input, value || '');
67253     };
67254
67255
67256     maxspeed.focus = function() {
67257         input.node().focus();
67258     };
67259
67260
67261     maxspeed.entity = function(_) {
67262         entity = _;
67263     };
67264
67265
67266     return utilRebind(maxspeed, dispatch$$1, 'on');
67267 }
67268
67269 function uiFieldRadio(field, context) {
67270     var dispatch$$1 = dispatch('change'),
67271         taginfo = services.taginfo,
67272         placeholder = select(null),
67273         wrap = select(null),
67274         labels = select(null),
67275         radios = select(null),
67276         typeInput = select(null),
67277         layerInput = select(null),
67278         oldType = {},
67279         entity;
67280
67281
67282     function selectedKey() {
67283         var selector$$1 = '.form-field-structure .toggle-list label.active input',
67284             node = selectAll(selector$$1);
67285         return !node.empty() && node.datum();
67286     }
67287
67288     // returns the tag value for a display value
67289     function tagValue(dispVal) {
67290         dispVal = snake(clean(dispVal || ''));
67291         return dispVal.toLowerCase() || 'yes';
67292     }
67293
67294     // returns the display value for a tag value
67295     function displayValue(tagVal) {
67296         tagVal = tagVal || '';
67297         return tagVal.toLowerCase() === 'yes' ? '' : unsnake(tagVal);
67298     }
67299
67300     function snake(s) {
67301         return s.replace(/\s+/g, '_');
67302     }
67303
67304     function unsnake(s) {
67305         return s.replace(/_+/g, ' ');
67306     }
67307
67308     function clean(s) {
67309         return s.split(';')
67310             .map(function(s) { return s.trim(); })
67311             .join(';');
67312     }
67313
67314
67315     function radio(selection$$1) {
67316         selection$$1.classed('preset-radio', true);
67317
67318         wrap = selection$$1.selectAll('.preset-input-wrap')
67319             .data([0]);
67320
67321         var enter = wrap.enter()
67322             .append('div')
67323             .attr('class', 'preset-input-wrap toggle-list');
67324
67325         enter
67326             .append('span')
67327             .attr('class', 'placeholder');
67328
67329         wrap = wrap
67330             .merge(enter);
67331
67332
67333         placeholder = wrap.selectAll('.placeholder');
67334
67335         labels = wrap.selectAll('label')
67336             .data(field.options || field.keys);
67337
67338         enter = labels.enter()
67339             .append('label');
67340
67341         enter
67342             .append('input')
67343             .attr('type', 'radio')
67344             .attr('name', field.id)
67345             .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
67346             .attr('checked', false);
67347
67348         enter
67349             .append('span')
67350             .text(function(d) { return field.t('options.' + d, { 'default': d }); });
67351
67352         labels = labels
67353             .merge(enter);
67354
67355         radios = labels.selectAll('input')
67356             .on('change', changeRadio);
67357     }
67358
67359
67360     function structureExtras(selection$$1) {
67361         var selected = selectedKey();
67362
67363         var extrasWrap = selection$$1.selectAll('.structure-extras-wrap')
67364                 .data(selected ? [0] : []);
67365
67366         extrasWrap.exit()
67367             .remove();
67368
67369         extrasWrap = extrasWrap.enter()
67370             .append('div')
67371             .attr('class', 'structure-extras-wrap')
67372             .merge(extrasWrap);
67373
67374         var list = extrasWrap.selectAll('ul')
67375             .data([0]);
67376
67377         list = list.enter()
67378             .append('ul')
67379             .merge(list);
67380
67381
67382         // Type
67383         var typeItem = list.selectAll('.structure-type-item')
67384             .data([0]);
67385
67386         var typeEnter = typeItem.enter()
67387             .append('li')
67388             .attr('class', 'cf structure-type-item');
67389
67390         typeEnter
67391             .append('span')
67392             .attr('class', 'col6 label structure-label-type')
67393             .attr('for', 'structure-input-type')
67394             .text(t('inspector.radio.structure.type'));
67395
67396         typeEnter
67397             .append('div')
67398             .attr('class', 'col6 structure-input-type-wrap')
67399             .append('input')
67400             .attr('type', 'text')
67401             .attr('class', 'structure-input-type')
67402             .attr('placeholder', t('inspector.radio.structure.default'))
67403             .call(utilNoAuto);
67404
67405         typeItem = typeItem
67406             .merge(typeEnter);
67407
67408         typeInput = typeItem.selectAll('.structure-input-type');
67409
67410         if (taginfo) {
67411             typeInput
67412                 .call(d3combobox()
67413                     .container(context.container())
67414                     .fetcher(typeFetcher)
67415                 );
67416         }
67417
67418         typeInput
67419             .on('change', changeType)
67420             .on('blur', changeType);
67421
67422
67423         // Layer
67424         var showLayer = (selected === 'bridge' || selected === 'tunnel');
67425
67426         var layerItem = list.selectAll('.structure-layer-item')
67427             .data(showLayer ? [0] : []);
67428
67429         layerItem.exit()
67430             .remove();
67431
67432         var layerEnter = layerItem.enter()
67433             .append('li')
67434             .attr('class', 'cf structure-layer-item');
67435
67436         layerEnter
67437             .append('span')
67438             .attr('class', 'col6 label structure-label-layer')
67439             .attr('for', 'structure-input-layer')
67440             .text(t('inspector.radio.structure.layer'));
67441
67442         layerEnter
67443             .append('div')
67444             .attr('class', 'col6 structure-input-layer-wrap')
67445             .append('input')
67446             .attr('type', 'text')
67447             .attr('class', 'structure-input-layer')
67448             .attr('placeholder', '0')
67449             .call(utilNoAuto);
67450
67451         var spin = layerEnter
67452             .append('div')
67453             .attr('class', 'spin-control');
67454
67455         spin
67456             .append('button')
67457             .datum(-1)
67458             .attr('class', 'decrement')
67459             .attr('tabindex', -1);
67460
67461         spin
67462             .append('button')
67463             .datum(1)
67464             .attr('class', 'increment')
67465             .attr('tabindex', -1);
67466
67467         layerItem = layerItem
67468             .merge(layerEnter);
67469
67470         layerInput = layerItem.selectAll('.structure-input-layer')
67471             .on('change', changeLayer)
67472             .on('blur', changeLayer);
67473
67474         layerItem.selectAll('button')
67475             .on('click', function(d) {
67476                 event.preventDefault();
67477                 var num = parseInt(layerInput.node().value || 0, 10);
67478                 if (!isNaN(num)) layerInput.node().value = num + d;
67479                 changeLayer();
67480             });
67481
67482     }
67483
67484
67485     function typeFetcher(q, callback) {
67486         taginfo.values({
67487             debounce: true,
67488             key: selectedKey(),
67489             query: q
67490         }, function(err, data) {
67491             if (err) return;
67492             var comboData = data.map(function(d) {
67493                 return {
67494                     key: d.value,
67495                     value: unsnake(d.value),
67496                     title: d.title
67497                 };
67498             });
67499             if (callback) callback(comboData);
67500         });
67501     }
67502
67503
67504     function changeType() {
67505         var key = selectedKey(),
67506             t$$1 = {};
67507
67508         if (!key) return;
67509         var val = tagValue(utilGetSetValue(typeInput));
67510         t$$1[key] = val;
67511         if (val !== 'no') oldType[key] = val;
67512         dispatch$$1.call('change', this, t$$1);
67513     }
67514
67515
67516     function changeLayer() {
67517         // note: don't use utilGetSetValue here because we want 0 to be falsy.
67518         var t$$1 = { layer: layerInput.node().value || undefined };
67519         dispatch$$1.call('change', this, t$$1);
67520     }
67521
67522
67523     function changeRadio() {
67524         var t$$1 = {},
67525             activeKey;
67526
67527         if (field.key) {
67528             t$$1[field.key] = undefined;
67529         }
67530
67531         radios.each(function(d) {
67532             var active$$1 = select(this).property('checked');
67533             if (active$$1) activeKey = d;
67534
67535             if (field.key) {
67536                 if (active$$1) t$$1[field.key] = d;
67537             } else {
67538                 var val = oldType[activeKey] || 'yes';
67539                 t$$1[d] = active$$1 ? val : undefined;
67540             }
67541         });
67542
67543         if (field.type === 'structureRadio') {
67544             if (activeKey === 'bridge') {
67545                 t$$1.layer = '1';
67546             } else if (activeKey === 'tunnel') {
67547                 t$$1.layer = '-1';
67548             } else {
67549                 t$$1.layer = undefined;
67550             }
67551         }
67552
67553         dispatch$$1.call('change', this, t$$1);
67554     }
67555
67556
67557     radio.tags = function(tags) {
67558         function checked(d) {
67559             if (field.key) {
67560                 return tags[field.key] === d;
67561             } else {
67562                 return !!(tags[d] && tags[d].toLowerCase() !== 'no');
67563             }
67564         }
67565
67566         labels.classed('active', checked);
67567         radios.property('checked', checked);
67568
67569         var selection$$1 = radios.filter(function() { return this.checked; });
67570         var typeVal = '';
67571
67572         if (selection$$1.empty()) {
67573             placeholder.text(t('inspector.none'));
67574         } else {
67575             placeholder.text(selection$$1.attr('value'));
67576             typeVal = oldType[selection$$1.datum()] = tags[selection$$1.datum()];
67577         }
67578
67579         if (field.type === 'structureRadio') {
67580             wrap.call(structureExtras);
67581             utilGetSetValue(typeInput, displayValue(typeVal) || '');
67582             utilGetSetValue(layerInput, tags.layer || '');
67583         }
67584     };
67585
67586
67587     radio.focus = function() {
67588         radios.node().focus();
67589     };
67590
67591
67592     radio.entity = function(_) {
67593         if (!arguments.length) return entity;
67594         entity = _;
67595         oldType = {};
67596         return radio;
67597     };
67598
67599
67600     return utilRebind(radio, dispatch$$1, 'on');
67601 }
67602
67603 function uiFieldRestrictions(field, context) {
67604     var dispatch$$1 = dispatch('change'),
67605         breathe = behaviorBreathe(context),
67606         hover = behaviorHover(context),
67607         initialized = false,
67608         vertexID,
67609         fromNodeID;
67610
67611
67612     function restrictions(selection$$1) {
67613         // if form field is hidden or has detached from dom, clean up.
67614         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
67615             selection$$1.call(restrictions.off);
67616             return;
67617         }
67618
67619         var wrap = selection$$1.selectAll('.preset-input-wrap')
67620             .data([0]);
67621
67622         var enter = wrap.enter()
67623             .append('div')
67624             .attr('class', 'preset-input-wrap');
67625
67626         enter
67627             .append('div')
67628             .attr('class', 'restriction-help');
67629
67630
67631         var intersection = osmIntersection(context.graph(), vertexID),
67632             graph = intersection.graph,
67633             vertex = graph.entity(vertexID),
67634             filter = utilFunctor(true),
67635             extent$$1 = geoExtent$$1(),
67636             projection = geoRawMercator();
67637
67638         var d = utilGetDimensions(wrap.merge(enter)),
67639             c = [d[0] / 2, d[1] / 2],
67640             z = 24;
67641
67642         projection
67643             .scale(256 * Math.pow(2, z) / (2 * Math.PI));
67644
67645         var s = projection(vertex.loc);
67646
67647         projection
67648             .translate([c[0] - s[0], c[1] - s[1]])
67649             .clipExtent([[0, 0], d]);
67650
67651         var drawLayers = svgLayers(projection, context).only('osm').dimensions(d),
67652             drawVertices = svgVertices$$1(projection, context),
67653             drawLines = svgLines$$1(projection, context),
67654             drawTurns = svgTurns(projection, context);
67655
67656         enter
67657             .call(drawLayers);
67658
67659         wrap = wrap
67660             .merge(enter);
67661
67662         var surface = wrap.selectAll('.surface');
67663
67664         if (!enter.empty()) {
67665             initialized = true;
67666             surface
67667                 .call(breathe)
67668                 .call(hover);
67669         }
67670
67671         surface
67672             .call(utilSetDimensions, d)
67673             .call(drawVertices, graph, [vertex], filter, extent$$1, z)
67674             .call(drawLines, graph, intersection.ways, filter)
67675             .call(drawTurns, graph, intersection.turns(fromNodeID));
67676
67677         surface
67678             .on('click.restrictions', click)
67679             .on('mouseover.restrictions', mouseover)
67680             .on('mouseout.restrictions', mouseout);
67681
67682         surface
67683             .selectAll('.selected')
67684             .classed('selected', false);
67685
67686         if (fromNodeID) {
67687             surface
67688                 .selectAll('.' + intersection.highways[fromNodeID].id)
67689                 .classed('selected', true);
67690         }
67691
67692         mouseout();
67693
67694         context.history()
67695             .on('change.restrictions', render);
67696
67697         select(window)
67698             .on('resize.restrictions', function() {
67699                 utilSetDimensions(wrap, null);
67700                 render();
67701             });
67702
67703
67704         function click() {
67705             surface
67706                 .call(breathe.off)
67707                 .call(breathe);
67708
67709             var datum = event.target.__data__;
67710             if (datum instanceof osmEntity$$1) {
67711                 fromNodeID = intersection.adjacentNodeId(datum.id);
67712                 render();
67713             } else if (datum instanceof osmTurn) {
67714                 if (datum.restriction) {
67715                     context.perform(
67716                         actionUnrestrictTurn(datum, projection),
67717                         t('operations.restriction.annotation.delete')
67718                     );
67719                 } else {
67720                     context.perform(
67721                         actionRestrictTurn(datum, projection),
67722                         t('operations.restriction.annotation.create')
67723                     );
67724                 }
67725             }
67726         }
67727
67728
67729         function mouseover() {
67730             var datum = event.target.__data__;
67731             if (datum instanceof osmTurn) {
67732                 var graph = context.graph(),
67733                     presets = context.presets(),
67734                     preset;
67735
67736                 if (datum.restriction) {
67737                     preset = presets.match(graph.entity(datum.restriction), graph);
67738                 } else {
67739                     preset = presets.item('type/restriction/' +
67740                         osmInferRestriction(
67741                             graph,
67742                             datum.from,
67743                             datum.via,
67744                             datum.to,
67745                             projection
67746                         )
67747                     );
67748                 }
67749
67750                 wrap.selectAll('.restriction-help')
67751                     .text(t('operations.restriction.help.' +
67752                         (datum.restriction ? 'toggle_off' : 'toggle_on'),
67753                         { restriction: preset.name() })
67754                     );
67755             }
67756         }
67757
67758
67759         function mouseout() {
67760             wrap.selectAll('.restriction-help')
67761                 .text(t('operations.restriction.help.' +
67762                     (fromNodeID ? 'toggle' : 'select'))
67763                 );
67764         }
67765
67766
67767         function render() {
67768             if (context.hasEntity(vertexID)) {
67769                 restrictions(selection$$1);
67770             }
67771         }
67772     }
67773
67774
67775     restrictions.entity = function(_) {
67776         if (!vertexID || vertexID !== _.id) {
67777             fromNodeID = null;
67778             vertexID = _.id;
67779         }
67780     };
67781
67782
67783     restrictions.tags = function() {};
67784     restrictions.focus = function() {};
67785
67786
67787     restrictions.off = function(selection$$1) {
67788         if (!initialized) return;
67789
67790         selection$$1.selectAll('.surface')
67791             .call(hover.off)
67792             .call(breathe.off)
67793             .on('click.restrictions', null)
67794             .on('mouseover.restrictions', null)
67795             .on('mouseout.restrictions', null);
67796
67797         context.history()
67798             .on('change.restrictions', null);
67799
67800         select(window)
67801             .on('resize.restrictions', null);
67802     };
67803
67804
67805     return utilRebind(restrictions, dispatch$$1, 'on');
67806 }
67807
67808 function uiFieldTextarea(field) {
67809     var dispatch$$1 = dispatch('change'),
67810         input = select(null);
67811
67812
67813     function textarea(selection$$1) {
67814         input = selection$$1.selectAll('textarea')
67815             .data([0]);
67816
67817         input = input.enter()
67818             .append('textarea')
67819             .attr('id', 'preset-input-' + field.id)
67820             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
67821             .attr('maxlength', 255)
67822             .call(utilNoAuto)
67823             .on('input', change(true))
67824             .on('blur', change())
67825             .on('change', change())
67826             .merge(input);
67827     }
67828
67829
67830     function change(onInput) {
67831         return function() {
67832             var t$$1 = {};
67833             t$$1[field.key] = utilGetSetValue(input) || undefined;
67834             dispatch$$1.call('change', this, t$$1, onInput);
67835         };
67836     }
67837
67838
67839     textarea.tags = function(tags) {
67840         utilGetSetValue(input, tags[field.key] || '');
67841     };
67842
67843
67844     textarea.focus = function() {
67845         input.node().focus();
67846     };
67847
67848
67849     return utilRebind(textarea, dispatch$$1, 'on');
67850 }
67851
67852 function uiFieldWikipedia(field, context) {
67853     var dispatch$$1 = dispatch('change'),
67854         wikipedia = services.wikipedia,
67855         wikidata = services.wikidata,
67856         link = select(null),
67857         lang = select(null),
67858         title = select(null),
67859         wikiURL = '',
67860         entity;
67861
67862
67863     function wiki(selection$$1) {
67864         var langcombo = d3combobox()
67865             .container(context.container())
67866             .fetcher(function(value, cb) {
67867                 var v = value.toLowerCase();
67868
67869                 cb(dataWikipedia.filter(function(d) {
67870                     return d[0].toLowerCase().indexOf(v) >= 0 ||
67871                         d[1].toLowerCase().indexOf(v) >= 0 ||
67872                         d[2].toLowerCase().indexOf(v) >= 0;
67873                 }).map(function(d) {
67874                     return { value: d[1] };
67875                 }));
67876             });
67877
67878         var titlecombo = d3combobox()
67879             .container(context.container())
67880             .fetcher(function(value, cb) {
67881                 if (!value) {
67882                     value = context.entity(entity.id).tags.name || '';
67883                 }
67884
67885                 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
67886                 searchfn(language()[2], value, function(query, data$$1) {
67887                     cb(data$$1.map(function(d) {
67888                         return { value: d };
67889                     }));
67890                 });
67891             });
67892
67893
67894         lang = selection$$1.selectAll('input.wiki-lang')
67895             .data([0]);
67896
67897         lang = lang.enter()
67898             .append('input')
67899             .attr('type', 'text')
67900             .attr('class', 'wiki-lang')
67901             .attr('placeholder', t('translate.localized_translation_language'))
67902             .call(utilNoAuto)
67903             .merge(lang);
67904
67905         utilGetSetValue(lang, language()[1]);
67906
67907         lang
67908             .call(langcombo)
67909             .on('blur', changeLang)
67910             .on('change', changeLang);
67911
67912
67913         title = selection$$1.selectAll('input.wiki-title')
67914             .data([0]);
67915
67916         title = title.enter()
67917             .append('input')
67918             .attr('type', 'text')
67919             .attr('class', 'wiki-title')
67920             .attr('id', 'preset-input-' + field.id)
67921             .call(utilNoAuto)
67922             .merge(title);
67923
67924         title
67925             .call(titlecombo)
67926             .on('blur', blur)
67927             .on('change', change);
67928
67929
67930         link = selection$$1.selectAll('.wiki-link')
67931             .data([0]);
67932
67933         link = link.enter()
67934             .append('button')
67935             .attr('class', 'button-input-action wiki-link minor')
67936             .attr('tabindex', -1)
67937             .call(svgIcon('#icon-out-link'))
67938             .merge(link);
67939
67940         link
67941             .on('click', function() {
67942                 event.preventDefault();
67943                 if (wikiURL) window.open(wikiURL, '_blank');
67944             });
67945     }
67946
67947
67948     function language() {
67949         var value = utilGetSetValue(lang).toLowerCase();
67950         var locale = utilDetect().locale.toLowerCase();
67951         var localeLanguage;
67952         return lodash.find(dataWikipedia, function(d) {
67953             if (d[2] === locale) localeLanguage = d;
67954             return d[0].toLowerCase() === value ||
67955                 d[1].toLowerCase() === value ||
67956                 d[2] === value;
67957         }) || localeLanguage || ['English', 'English', 'en'];
67958     }
67959
67960
67961     function changeLang() {
67962         utilGetSetValue(lang, language()[1]);
67963         change(true);
67964     }
67965
67966
67967     function blur() {
67968         change(true);
67969     }
67970
67971
67972     function change(skipWikidata) {
67973         var value = utilGetSetValue(title),
67974             m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
67975             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
67976             anchor,
67977             syncTags = {};
67978
67979         if (l) {
67980             // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
67981             value = decodeURIComponent(m[2]).replace(/_/g, ' ');
67982             if (m[3]) {
67983                 try {
67984                     // Best-effort `anchordecode:` implementation
67985                     anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
67986                 } catch (e) {
67987                     anchor = decodeURIComponent(m[3]);
67988                 }
67989                 value += '#' + anchor.replace(/_/g, ' ');
67990             }
67991             value = value.slice(0, 1).toUpperCase() + value.slice(1);
67992             utilGetSetValue(lang, l[1]);
67993             utilGetSetValue(title, value);
67994         }
67995
67996         syncTags.wikipedia = value ? language()[2] + ':' + value : undefined;
67997         if (!skipWikidata) {
67998             syncTags.wikidata = undefined;
67999         }
68000
68001         dispatch$$1.call('change', this, syncTags);
68002
68003
68004         if (skipWikidata || !value || !language()[2]) return;
68005
68006         // attempt asynchronous update of wikidata tag..
68007         var initEntityId = entity.id,
68008             initWikipedia = context.entity(initEntityId).tags.wikipedia;
68009
68010         wikidata.itemsByTitle(language()[2], value, function(title, data$$1) {
68011             if (!data$$1 || !Object.keys(data$$1).length) return;
68012             var qids = Object.keys(data$$1);
68013
68014             // 1. most recent change was a tag change
68015             var annotation = t('operations.change_tags.annotation'),
68016                 currAnnotation = context.history().undoAnnotation();
68017             if (currAnnotation !== annotation) return;
68018
68019             // 2. same entity exists and still selected
68020             var selectedIds = context.selectedIDs(),
68021                 currEntityId = selectedIds.length > 0 && selectedIds[0];
68022             if (currEntityId !== initEntityId) return;
68023
68024             // 3. wikipedia value has not changed
68025             var currTags = lodash.clone(context.entity(currEntityId).tags);
68026             if (initWikipedia !== currTags.wikipedia) return;
68027
68028             // ok to coalesce the update of wikidata tag into the previous tag change
68029             currTags.wikidata = qids && lodash.find(qids, function(id) {
68030                 return id.match(/^Q\d+$/);
68031             });
68032
68033             context.overwrite(actionChangeTags(currEntityId, currTags), annotation);
68034             dispatch$$1.call('change', this, currTags);
68035         });
68036     }
68037
68038
68039     wiki.tags = function(tags) {
68040         var value = tags[field.key] || '',
68041             m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
68042             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
68043             anchor = m && m[3];
68044
68045         // value in correct format
68046         if (l) {
68047             utilGetSetValue(lang, l[1]);
68048             utilGetSetValue(title, m[2] + (anchor ? ('#' + anchor) : ''));
68049             if (anchor) {
68050                 try {
68051                     // Best-effort `anchorencode:` implementation
68052                     anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
68053                 } catch (e) {
68054                     anchor = anchor.replace(/ /g, '_');
68055                 }
68056             }
68057             wikiURL = 'https://' + m[1] + '.wikipedia.org/wiki/' +
68058                 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : '');
68059
68060         // unrecognized value format
68061         } else {
68062             utilGetSetValue(title, value);
68063             if (value && value !== '') {
68064                 utilGetSetValue(lang, '');
68065                 wikiURL = 'https://en.wikipedia.org/wiki/Special:Search?search=' + value;
68066             } else {
68067                 wikiURL = '';
68068             }
68069         }
68070     };
68071
68072
68073     wiki.entity = function(_) {
68074         if (!arguments.length) return entity;
68075         entity = _;
68076         return wiki;
68077     };
68078
68079
68080     wiki.focus = function() {
68081         title.node().focus();
68082     };
68083
68084
68085     return utilRebind(wiki, dispatch$$1, 'on');
68086 }
68087
68088 var uiFields = {
68089     access: uiFieldAccess,
68090     address: uiFieldAddress,
68091     check: uiFieldCheck,
68092     combo: uiFieldCombo,
68093     cycleway: uiFieldCycleway,
68094     defaultCheck: uiFieldCheck,
68095     email: uiFieldText,
68096     lanes: uiFieldLanes,
68097     localized: uiFieldLocalized,
68098     maxspeed: uiFieldMaxspeed,
68099     multiCombo: uiFieldCombo,
68100     networkCombo: uiFieldCombo,
68101     number: uiFieldText,
68102     onewayCheck: uiFieldCheck,
68103     radio: uiFieldRadio,
68104     restrictions: uiFieldRestrictions,
68105     semiCombo: uiFieldCombo,
68106     structureRadio: uiFieldRadio,
68107     tel: uiFieldText,
68108     text: uiFieldText,
68109     textarea: uiFieldTextarea,
68110     typeCombo: uiFieldCombo,
68111     url: uiFieldText,
68112     wikipedia: uiFieldWikipedia
68113 };
68114
68115 function uiPreset(context) {
68116     var dispatch$$1 = dispatch('change'),
68117         state,
68118         fieldsArr,
68119         preset,
68120         tags,
68121         id;
68122
68123
68124     // Field Constructor
68125     function UIField(field, entity, show) {
68126         field = lodash.clone(field);
68127
68128         field.input = uiFields[field.type](field, context)
68129             .on('change', function(t$$1, onInput) {
68130                 dispatch$$1.call('change', field, t$$1, onInput);
68131             });
68132
68133         if (field.input.entity) field.input.entity(entity);
68134
68135         field.keys = field.keys || [field.key];
68136
68137         field.show = show;
68138
68139         field.shown = function() {
68140             return field.id === 'name' || field.show || lodash.some(field.keys, function(key) { return !!tags[key]; });
68141         };
68142
68143         field.modified = function() {
68144             var original = context.graph().base().entities[entity.id];
68145             return lodash.some(field.keys, function(key) {
68146                 return original ? tags[key] !== original.tags[key] : tags[key];
68147             });
68148         };
68149
68150         field.revert = function() {
68151             var original = context.graph().base().entities[entity.id],
68152                 t$$1 = {};
68153             field.keys.forEach(function(key) {
68154                 t$$1[key] = original ? original.tags[key] : undefined;
68155             });
68156             return t$$1;
68157         };
68158
68159         field.present = function() {
68160             return lodash.some(field.keys, function(key) {
68161                 return tags[key];
68162             });
68163         };
68164
68165         field.remove = function() {
68166             var t$$1 = {};
68167             field.keys.forEach(function(key) {
68168                 t$$1[key] = undefined;
68169             });
68170             return t$$1;
68171         };
68172
68173         return field;
68174     }
68175
68176
68177     function fieldKey(field) {
68178         return field.id;
68179     }
68180
68181
68182     function presets(selection$$1) {
68183         selection$$1.call(uiDisclosure()
68184             .title(t('inspector.all_fields'))
68185             .expanded(context.storage('preset_fields.expanded') !== 'false')
68186             .on('toggled', toggled)
68187             .content(content)
68188         );
68189
68190         function toggled(expanded) {
68191             context.storage('preset_fields.expanded', expanded);
68192         }
68193     }
68194
68195
68196     function content(selection$$1) {
68197         if (!fieldsArr) {
68198             var entity = context.entity(id),
68199                 geometry = context.geometry(id),
68200                 presets = context.presets();
68201
68202             fieldsArr = [];
68203
68204             if (presets.field('name')) {
68205                 fieldsArr.push(UIField(presets.field('name'), entity));
68206             }
68207
68208             preset.fields.forEach(function(field) {
68209                 if (field.matchGeometry(geometry)) {
68210                     fieldsArr.push(UIField(field, entity, true));
68211                 }
68212             });
68213
68214             if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) {
68215                 fieldsArr.push(UIField(presets.field('restrictions'), entity, true));
68216             }
68217
68218             presets.universal().forEach(function(field) {
68219                 if (preset.fields.indexOf(field) < 0) {
68220                     fieldsArr.push(UIField(field, entity));
68221                 }
68222             });
68223         }
68224
68225         var shown = fieldsArr.filter(function(field) { return field.shown(); }),
68226             notShown = fieldsArr.filter(function(field) { return !field.shown(); });
68227
68228
68229         var form = selection$$1.selectAll('.preset-form')
68230             .data([0]);
68231
68232         form = form.enter()
68233             .append('div')
68234             .attr('class', 'preset-form inspector-inner fillL3')
68235             .merge(form);
68236
68237
68238         var fields = form.selectAll('.form-field')
68239             .data(shown, fieldKey);
68240
68241         fields.exit()
68242             .remove();
68243
68244         // Enter
68245         var enter = fields.enter()
68246             .append('div')
68247             .attr('class', function(field) {
68248                 return 'form-field form-field-' + field.id;
68249             });
68250
68251         var label = enter
68252             .append('label')
68253             .attr('class', 'form-label')
68254             .attr('for', function(field) { return 'preset-input-' + field.id; })
68255             .text(function(field) { return field.label(); });
68256
68257         var wrap = label
68258             .append('div')
68259             .attr('class', 'form-label-button-wrap');
68260
68261         wrap.append('button')
68262             .attr('class', 'remove-icon')
68263             .attr('tabindex', -1)
68264             .call(svgIcon('#operation-delete'));
68265
68266         wrap.append('button')
68267             .attr('class', 'modified-icon')
68268             .attr('tabindex', -1)
68269             .call(
68270                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
68271             );
68272
68273
68274         // Update
68275         fields = fields
68276             .merge(enter);
68277
68278         fields.selectAll('.form-label-button-wrap .remove-icon')
68279             .on('click', remove);
68280
68281         fields.selectAll('.modified-icon')
68282             .on('click', revert);
68283
68284         fields
68285             .order()
68286             .classed('modified', function(field) { return field.modified(); })
68287             .classed('present', function(field) { return field.present(); })
68288             .each(function(field) {
68289                 var reference = uiTagReference(field.reference || { key: field.key }, context);
68290
68291                 if (state === 'hover') {
68292                     reference.showing(false);
68293                 }
68294
68295                 select(this)
68296                     .call(field.input)
68297                     .selectAll('input')
68298                     .on('keydown', function() {
68299                         // if user presses enter, and combobox is not active, accept edits..
68300                         if (event.keyCode === 13 && select('.combobox').empty()) {
68301                             context.enter(modeBrowse(context));
68302                         }
68303                     });
68304
68305                 select(this)
68306                     .call(reference.body)
68307                     .select('.form-label-button-wrap')
68308                     .call(reference.button);
68309
68310                 field.input.tags(tags);
68311             });
68312
68313         notShown = notShown.map(function(field) {
68314             return {
68315                 title: field.label(),
68316                 value: field.label(),
68317                 field: field
68318             };
68319         });
68320
68321
68322         var more = selection$$1.selectAll('.more-fields')
68323             .data((notShown.length > 0) ? [0] : []);
68324
68325         more.exit()
68326             .remove();
68327
68328         more = more.enter()
68329             .append('div')
68330             .attr('class', 'more-fields')
68331             .append('label')
68332             .text(t('inspector.add_fields'))
68333             .merge(more);
68334
68335
68336         var input = more.selectAll('.value')
68337             .data([0]);
68338
68339         input.exit()
68340             .remove();
68341
68342         input = input.enter()
68343             .append('input')
68344             .attr('class', 'value')
68345             .attr('type', 'text')
68346             .call(utilNoAuto)
68347             .merge(input);
68348
68349         input
68350             .call(utilGetSetValue, '')
68351             .attr('placeholder', function() {
68352                 var placeholder = [];
68353                 for (var field in notShown) {
68354                     placeholder.push(notShown[field].title);
68355                 }
68356                 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
68357             })
68358             .call(d3combobox()
68359                 .container(context.container())
68360                 .data(notShown)
68361                 .minItems(1)
68362                 .on('accept', show)
68363             );
68364
68365
68366         function show(field) {
68367             field = field.field;
68368             field.show = true;
68369             content(selection$$1);
68370             field.input.focus();
68371         }
68372
68373
68374         function revert(field) {
68375             event.stopPropagation();
68376             event.preventDefault();
68377             dispatch$$1.call('change', field, field.revert());
68378         }
68379
68380
68381         function remove(field) {
68382             event.stopPropagation();
68383             event.preventDefault();
68384             dispatch$$1.call('change', field, field.remove());
68385         }
68386     }
68387
68388
68389     presets.preset = function(_) {
68390         if (!arguments.length) return preset;
68391         if (preset && preset.id === _.id) return presets;
68392         preset = _;
68393         fieldsArr = null;
68394         return presets;
68395     };
68396
68397
68398     presets.state = function(_) {
68399         if (!arguments.length) return state;
68400         state = _;
68401         return presets;
68402     };
68403
68404
68405     presets.tags = function(_) {
68406         if (!arguments.length) return tags;
68407         tags = _;
68408         // Don't reset fieldsArr here.
68409         return presets;
68410     };
68411
68412
68413     presets.entityID = function(_) {
68414         if (!arguments.length) return id;
68415         if (id === _) return presets;
68416         id = _;
68417         fieldsArr = null;
68418         return presets;
68419     };
68420
68421
68422     return utilRebind(presets, dispatch$$1, 'on');
68423 }
68424
68425 function uiEntityEditor(context) {
68426     var dispatch$$1 = dispatch('choose'),
68427         state = 'select',
68428         coalesceChanges = false,
68429         modified = false,
68430         base,
68431         id,
68432         activePreset,
68433         reference;
68434
68435     var presetEditor = uiPreset(context)
68436         .on('change', changeTags);
68437     var rawTagEditor = uiRawTagEditor(context)
68438         .on('change', changeTags);
68439
68440
68441     function entityEditor(selection$$1) {
68442         var entity = context.entity(id),
68443             tags = lodash.clone(entity.tags);
68444
68445         // Header
68446         var header = selection$$1.selectAll('.header')
68447             .data([0]);
68448
68449         // Enter
68450         var enter = header.enter()
68451             .append('div')
68452             .attr('class', 'header fillL cf');
68453
68454         enter
68455             .append('button')
68456             .attr('class', 'fl preset-reset preset-choose')
68457             .call(svgIcon((textDirection === 'rtl') ? '#icon-forward' : '#icon-backward'));
68458
68459         enter
68460             .append('button')
68461             .attr('class', 'fr preset-close')
68462             .on('click', function() { context.enter(modeBrowse(context)); })
68463             .call(svgIcon(modified ? '#icon-apply' : '#icon-close'));
68464
68465         enter
68466             .append('h3')
68467             .text(t('inspector.edit'));
68468
68469         // Update
68470         header = header
68471             .merge(enter);
68472
68473         header.selectAll('.preset-reset')
68474             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
68475
68476
68477         // Body
68478         var body = selection$$1.selectAll('.inspector-body')
68479             .data([0]);
68480
68481         // Enter
68482         enter = body.enter()
68483             .append('div')
68484             .attr('class', 'inspector-body');
68485
68486         enter
68487             .append('div')
68488             .attr('class', 'preset-list-item inspector-inner')
68489             .append('div')
68490             .attr('class', 'preset-list-button-wrap')
68491             .append('button')
68492             .attr('class', 'preset-list-button preset-reset')
68493             .call(tooltip().title(t('inspector.back_tooltip')).placement('bottom'))
68494             .append('div')
68495             .attr('class', 'label');
68496
68497         enter
68498             .append('div')
68499             .attr('class', 'inspector-border inspector-preset');
68500
68501         enter
68502             .append('div')
68503             .attr('class', 'inspector-border raw-tag-editor inspector-inner');
68504
68505         enter
68506             .append('div')
68507             .attr('class', 'inspector-border raw-member-editor inspector-inner');
68508
68509         enter
68510             .append('div')
68511             .attr('class', 'raw-membership-editor inspector-inner');
68512
68513         // Update
68514         body = body
68515             .merge(enter);
68516
68517         body.selectAll('.preset-list-button-wrap')
68518             .call(reference.button);
68519
68520         body.selectAll('.preset-list-item')
68521             .call(reference.body);
68522
68523         body.selectAll('.preset-reset')
68524             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
68525
68526         body.select('.preset-list-item button')
68527             .call(uiPresetIcon()
68528                 .geometry(context.geometry(id))
68529                 .preset(activePreset));
68530
68531         body.select('.preset-list-item .label')
68532             .text(activePreset.name());
68533
68534         body.select('.inspector-preset')
68535             .call(presetEditor
68536                 .preset(activePreset)
68537                 .entityID(id)
68538                 .tags(tags)
68539                 .state(state));
68540
68541         body.select('.raw-tag-editor')
68542             .call(rawTagEditor
68543                 .preset(activePreset)
68544                 .entityID(id)
68545                 .tags(tags)
68546                 .state(state));
68547
68548         if (entity.type === 'relation') {
68549             body.select('.raw-member-editor')
68550                 .style('display', 'block')
68551                 .call(uiRawMemberEditor(context)
68552                     .entityID(id));
68553         } else {
68554             body.select('.raw-member-editor')
68555                 .style('display', 'none');
68556         }
68557
68558         body.select('.raw-membership-editor')
68559             .call(uiRawMembershipEditor(context)
68560                 .entityID(id));
68561
68562
68563         context.history()
68564             .on('change.entity-editor', historyChanged);
68565
68566
68567         function historyChanged() {
68568             if (state === 'hide') return;
68569
68570             var entity = context.hasEntity(id),
68571                 graph = context.graph();
68572             if (!entity) return;
68573
68574             entityEditor.preset(context.presets().match(entity, graph));
68575             entityEditor.modified(base !== graph);
68576             entityEditor(selection$$1);
68577         }
68578     }
68579
68580
68581     function clean(o) {
68582
68583         function cleanVal(k, v) {
68584             function keepSpaces(k) {
68585                 return k.match(/_hours|_times/) !== null;
68586             }
68587
68588             var blacklist = ['description', 'note', 'fixme'];
68589             if (lodash.some(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
68590
68591             var cleaned = v.split(';')
68592                 .map(function(s) { return s.trim(); })
68593                 .join(keepSpaces(k) ? '; ' : ';');
68594
68595             // The code below is not intended to validate websites and emails.
68596             // It is only intended to prevent obvious copy-paste errors. (#2323)
68597             // clean website- and email-like tags
68598             if (k.indexOf('website') !== -1 ||
68599                 k.indexOf('email') !== -1 ||
68600                 cleaned.indexOf('http') === 0) {
68601                 cleaned = cleaned
68602                     .replace(/[\u200B-\u200F\uFEFF]/g, '');  // strip LRM and other zero width chars
68603
68604             }
68605
68606             return cleaned;
68607         }
68608
68609         var out = {}, k, v;
68610         for (k in o) {
68611             if (k && (v = o[k]) !== undefined) {
68612                 out[k] = cleanVal(k, v);
68613             }
68614         }
68615         return out;
68616     }
68617
68618
68619     // Tag changes that fire on input can all get coalesced into a single
68620     // history operation when the user leaves the field.  #2342
68621     function changeTags(changed, onInput) {
68622         var entity = context.entity(id),
68623             annotation = t('operations.change_tags.annotation'),
68624             tags = lodash.clone(entity.tags);
68625
68626         lodash.forEach(changed, function(v, k) {
68627             if (v !== undefined || tags.hasOwnProperty(k)) {
68628                 tags[k] = v;
68629             }
68630         });
68631
68632         if (!onInput) {
68633             tags = clean(tags);
68634         }
68635
68636         if (!lodash.isEqual(entity.tags, tags)) {
68637             if (coalesceChanges) {
68638                 context.overwrite(actionChangeTags(id, tags), annotation);
68639             } else {
68640                 context.perform(actionChangeTags(id, tags), annotation);
68641                 coalesceChanges = !!onInput;
68642             }
68643         }
68644     }
68645
68646
68647     entityEditor.modified = function(_) {
68648         if (!arguments.length) return modified;
68649         modified = _;
68650         selectAll('button.preset-close use')
68651             .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
68652     };
68653
68654
68655     entityEditor.state = function(_) {
68656         if (!arguments.length) return state;
68657         state = _;
68658         return entityEditor;
68659     };
68660
68661
68662     entityEditor.entityID = function(_) {
68663         if (!arguments.length) return id;
68664         id = _;
68665         base = context.graph();
68666         entityEditor.preset(context.presets().match(context.entity(id), base));
68667         entityEditor.modified(false);
68668         coalesceChanges = false;
68669         return entityEditor;
68670     };
68671
68672
68673     entityEditor.preset = function(_) {
68674         if (!arguments.length) return activePreset;
68675         if (_ !== activePreset) {
68676             activePreset = _;
68677             reference = uiTagReference(activePreset.reference(context.geometry(id)), context)
68678                 .showing(false);
68679         }
68680         return entityEditor;
68681     };
68682
68683
68684     return utilRebind(entityEditor, dispatch$$1, 'on');
68685 }
68686
68687 function uiPresetList(context) {
68688     var dispatch$$1 = dispatch('choose'),
68689         id,
68690         currentPreset,
68691         autofocus = false;
68692
68693
68694     function presetList(selection$$1) {
68695         var entity = context.entity(id),
68696             geometry = context.geometry(id);
68697
68698         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
68699         if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
68700             geometry = 'point';
68701         }
68702
68703         var presets = context.presets().matchGeometry(geometry);
68704
68705         selection$$1.html('');
68706
68707         var messagewrap = selection$$1
68708             .append('div')
68709             .attr('class', 'header fillL cf');
68710
68711         var message = messagewrap
68712             .append('h3')
68713             .text(t('inspector.choose'));
68714
68715         if (context.entity(id).isUsed(context.graph())) {
68716             messagewrap
68717                 .append('button')
68718                 .attr('class', 'preset-choose')
68719                 .on('click', function() { dispatch$$1.call('choose', this, currentPreset); })
68720                 .call(svgIcon((textDirection === 'rtl') ? '#icon-backward' : '#icon-forward'));
68721         } else {
68722             messagewrap
68723                 .append('button')
68724                 .attr('class', 'close')
68725                 .on('click', function() {
68726                     context.enter(modeBrowse(context));
68727                 })
68728                 .call(svgIcon('#icon-close'));
68729         }
68730
68731         function keydown() {
68732             // hack to let delete shortcut work when search is autofocused
68733             if (search.property('value').length === 0 &&
68734                 (event.keyCode === d3keybinding.keyCodes['⌫'] ||
68735                  event.keyCode === d3keybinding.keyCodes['⌦'])) {
68736                 event.preventDefault();
68737                 event.stopPropagation();
68738                 operationDelete([id], context)();
68739             } else if (search.property('value').length === 0 &&
68740                 (event.ctrlKey || event.metaKey) &&
68741                 event.keyCode === d3keybinding.keyCodes.z) {
68742                 event.preventDefault();
68743                 event.stopPropagation();
68744                 context.undo();
68745             } else if (!event.ctrlKey && !event.metaKey) {
68746                 select(this).on('keydown', null);
68747             }
68748         }
68749
68750         function keypress() {
68751             // enter
68752             var value = search.property('value');
68753             if (event.keyCode === 13 && value.length) {
68754                 list.selectAll('.preset-list-item:first-child').datum().choose();
68755             }
68756         }
68757
68758         function inputevent() {
68759             var value = search.property('value');
68760             list.classed('filtered', value.length);
68761             if (value.length) {
68762                 var results = presets.search(value, geometry);
68763                 message.text(t('inspector.results', {
68764                     n: results.collection.length,
68765                     search: value
68766                 }));
68767                 list.call(drawList, results);
68768             } else {
68769                 list.call(drawList, context.presets().defaults(geometry, 36));
68770                 message.text(t('inspector.choose'));
68771             }
68772         }
68773
68774         var searchWrap = selection$$1
68775             .append('div')
68776             .attr('class', 'search-header');
68777
68778         var search = searchWrap
68779             .append('input')
68780             .attr('class', 'preset-search-input')
68781             .attr('placeholder', t('inspector.search'))
68782             .attr('type', 'search')
68783             .call(utilNoAuto)
68784             .on('keydown', keydown)
68785             .on('keypress', keypress)
68786             .on('input', inputevent);
68787
68788         searchWrap
68789             .call(svgIcon('#icon-search', 'pre-text'));
68790
68791         if (autofocus) {
68792             search.node().focus();
68793         }
68794
68795         var listWrap = selection$$1
68796             .append('div')
68797             .attr('class', 'inspector-body');
68798
68799         var list = listWrap
68800             .append('div')
68801             .attr('class', 'preset-list fillL cf')
68802             .call(drawList, context.presets().defaults(geometry, 36));
68803     }
68804
68805
68806     function drawList(list, presets) {
68807         var collection = presets.collection.map(function(preset) {
68808             return preset.members ? CategoryItem(preset) : PresetItem(preset);
68809         });
68810
68811         var items = list.selectAll('.preset-list-item')
68812             .data(collection, function(d) { return d.preset.id; });
68813
68814         items.order();
68815
68816         items.exit()
68817             .remove();
68818
68819         items.enter()
68820             .append('div')
68821             .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
68822             .classed('current', function(item) { return item.preset === currentPreset; })
68823             .each(function(item) { select(this).call(item); })
68824             .style('opacity', 0)
68825             .transition()
68826             .style('opacity', 1);
68827     }
68828
68829
68830     function CategoryItem(preset) {
68831         var box, sublist, shown = false;
68832
68833         function item(selection$$1) {
68834             var wrap = selection$$1.append('div')
68835                 .attr('class', 'preset-list-button-wrap category col12');
68836
68837             var button = wrap
68838                 .append('button')
68839                 .attr('class', 'preset-list-button')
68840                 .classed('expanded', false)
68841                 .call(uiPresetIcon()
68842                     .geometry(context.geometry(id))
68843                     .preset(preset))
68844                 .on('click', function() {
68845                     var isExpanded = select(this).classed('expanded');
68846                     var iconName = isExpanded ?
68847                         (textDirection === 'rtl' ? '#icon-backward' : '#icon-forward') : '#icon-down';
68848                     select(this)
68849                         .classed('expanded', !isExpanded);
68850                     select(this).selectAll('div.label svg.icon use')
68851                         .attr('href', iconName);
68852                     item.choose();
68853                 });
68854
68855             var label = button
68856                 .append('div')
68857                 .attr('class', 'label');
68858
68859             label
68860                 .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'))
68861                 .append('span')
68862                 .html(function() { return preset.name() + '&hellip;'; });
68863
68864             box = selection$$1.append('div')
68865                 .attr('class', 'subgrid col12')
68866                 .style('max-height', '0px')
68867                 .style('opacity', 0);
68868
68869             box.append('div')
68870                 .attr('class', 'arrow');
68871
68872             sublist = box.append('div')
68873                 .attr('class', 'preset-list fillL3 cf fl');
68874         }
68875
68876
68877         item.choose = function() {
68878             if (!box || !sublist) return;
68879
68880             if (shown) {
68881                 shown = false;
68882                 box.transition()
68883                     .duration(200)
68884                     .style('opacity', '0')
68885                     .style('max-height', '0px')
68886                     .style('padding-bottom', '0px');
68887             } else {
68888                 shown = true;
68889                 sublist.call(drawList, preset.members);
68890                 box.transition()
68891                     .duration(200)
68892                     .style('opacity', '1')
68893                     .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
68894                     .style('padding-bottom', '20px');
68895             }
68896         };
68897
68898         item.preset = preset;
68899
68900         return item;
68901     }
68902
68903
68904     function PresetItem(preset) {
68905         function item(selection$$1) {
68906             var wrap = selection$$1.append('div')
68907                 .attr('class', 'preset-list-button-wrap col12');
68908
68909             wrap.append('button')
68910                 .attr('class', 'preset-list-button')
68911                 .call(uiPresetIcon()
68912                     .geometry(context.geometry(id))
68913                     .preset(preset))
68914                 .on('click', item.choose)
68915                 .append('div')
68916                 .attr('class', 'label')
68917                 .text(preset.name());
68918
68919             wrap.call(item.reference.button);
68920             selection$$1.call(item.reference.body);
68921         }
68922
68923         item.choose = function() {
68924             context.presets().choose(preset);
68925
68926             context.perform(
68927                 actionChangePreset(id, currentPreset, preset),
68928                 t('operations.change_tags.annotation')
68929             );
68930
68931             dispatch$$1.call('choose', this, preset);
68932         };
68933
68934         item.help = function() {
68935             event.stopPropagation();
68936             item.reference.toggle();
68937         };
68938
68939         item.preset = preset;
68940         item.reference = uiTagReference(preset.reference(context.geometry(id)), context);
68941
68942         return item;
68943     }
68944
68945
68946     presetList.autofocus = function(_) {
68947         if (!arguments.length) return autofocus;
68948         autofocus = _;
68949         return presetList;
68950     };
68951
68952
68953     presetList.entityID = function(_) {
68954         if (!arguments.length) return id;
68955         id = _;
68956         presetList.preset(context.presets().match(context.entity(id), context.graph()));
68957         return presetList;
68958     };
68959
68960
68961     presetList.preset = function(_) {
68962         if (!arguments.length) return currentPreset;
68963         currentPreset = _;
68964         return presetList;
68965     };
68966
68967
68968     return utilRebind(presetList, dispatch$$1, 'on');
68969 }
68970
68971 function uiViewOnOSM(context) {
68972     var id;
68973
68974     function viewOnOSM(selection) {
68975         var entity = context.entity(id);
68976
68977         selection.style('display', entity.isNew() ? 'none' : null);
68978
68979         var link = selection.selectAll('.view-on-osm')
68980             .data([0]);
68981
68982         var enter = link.enter()
68983             .append('a')
68984             .attr('class', 'view-on-osm')
68985             .attr('target', '_blank')
68986             .call(svgIcon('#icon-out-link', 'inline'));
68987
68988         enter
68989             .append('span')
68990             .text(t('inspector.view_on_osm'));
68991
68992         link
68993             .merge(enter)
68994             .attr('href', context.connection().entityURL(entity));
68995     }
68996
68997
68998     viewOnOSM.entityID = function(_) {
68999         if (!arguments.length) return id;
69000         id = _;
69001         return viewOnOSM;
69002     };
69003
69004     return viewOnOSM;
69005 }
69006
69007 function uiInspector(context) {
69008     var presetList = uiPresetList(context),
69009         entityEditor = uiEntityEditor(context),
69010         state = 'select',
69011         entityID,
69012         newFeature = false;
69013
69014
69015     function inspector(selection$$1) {
69016         presetList
69017             .entityID(entityID)
69018             .autofocus(newFeature)
69019             .on('choose', setPreset);
69020
69021         entityEditor
69022             .state(state)
69023             .entityID(entityID)
69024             .on('choose', showList);
69025
69026         var wrap = selection$$1.selectAll('.panewrap')
69027             .data([0]);
69028
69029         var enter = wrap.enter()
69030             .append('div')
69031             .attr('class', 'panewrap');
69032
69033         enter
69034             .append('div')
69035             .attr('class', 'preset-list-pane pane');
69036
69037         enter
69038             .append('div')
69039             .attr('class', 'entity-editor-pane pane');
69040
69041         wrap = wrap.merge(enter);
69042         var presetPane = wrap.selectAll('.preset-list-pane');
69043         var editorPane = wrap.selectAll('.entity-editor-pane');
69044
69045         var graph = context.graph(),
69046             entity = context.entity(entityID),
69047             showEditor = state === 'hover' ||
69048                 entity.isUsed(graph) ||
69049                 entity.isHighwayIntersection(graph);
69050
69051         if (showEditor) {
69052             wrap.style('right', '0%');
69053             editorPane.call(entityEditor);
69054         } else {
69055             wrap.style('right', '-100%');
69056             presetPane.call(presetList);
69057         }
69058
69059         var footer = selection$$1.selectAll('.footer')
69060             .data([0]);
69061
69062         footer = footer.enter()
69063             .append('div')
69064             .attr('class', 'footer')
69065             .merge(footer);
69066
69067         footer
69068             .call(uiViewOnOSM(context).entityID(entityID));
69069
69070
69071         function showList(preset) {
69072             wrap.transition()
69073                 .styleTween('right', function() { return interpolateValue('0%', '-100%'); });
69074
69075             presetPane
69076                 .call(presetList.preset(preset).autofocus(true));
69077         }
69078
69079
69080         function setPreset(preset) {
69081             wrap.transition()
69082                 .styleTween('right', function() { return interpolateValue('-100%', '0%'); });
69083
69084             editorPane
69085                 .call(entityEditor.preset(preset));
69086         }
69087     }
69088
69089
69090     inspector.state = function(_) {
69091         if (!arguments.length) return state;
69092         state = _;
69093         entityEditor.state(state);
69094         return inspector;
69095     };
69096
69097
69098     inspector.entityID = function(_) {
69099         if (!arguments.length) return entityID;
69100         entityID = _;
69101         return inspector;
69102     };
69103
69104
69105     inspector.newFeature = function(_) {
69106         if (!arguments.length) return newFeature;
69107         newFeature = _;
69108         return inspector;
69109     };
69110
69111
69112     return inspector;
69113 }
69114
69115 function uiNotice(context) {
69116
69117     return function(selection) {
69118         var div = selection
69119             .append('div')
69120             .attr('class', 'notice');
69121
69122         var button = div
69123             .append('button')
69124             .attr('class', 'zoom-to notice')
69125             .on('click', function() { context.map().zoom(context.minEditableZoom()); });
69126
69127         button
69128             .call(svgIcon('#icon-plus', 'pre-text'))
69129             .append('span')
69130             .attr('class', 'label')
69131             .text(t('zoom_in_edit'));
69132
69133
69134         function disableTooHigh() {
69135             div.style('display', context.editable() ? 'none' : 'block');
69136         }
69137
69138         context.map()
69139             .on('move.notice', lodash.debounce(disableTooHigh, 500));
69140
69141         disableTooHigh();
69142     };
69143 }
69144
69145 function uiSidebar(context) {
69146     var inspector = uiInspector(context),
69147         current;
69148
69149
69150     function sidebar(selection) {
69151         var featureListWrap = selection
69152             .append('div')
69153             .attr('class', 'feature-list-pane')
69154             .call(uiFeatureList(context));
69155
69156         selection
69157             .call(uiNotice(context));
69158
69159         var inspectorWrap = selection
69160             .append('div')
69161             .attr('class', 'inspector-hidden inspector-wrap fr');
69162
69163
69164         function hover(id) {
69165             if (!current && context.hasEntity(id)) {
69166                 featureListWrap
69167                     .classed('inspector-hidden', true);
69168
69169                 inspectorWrap
69170                     .classed('inspector-hidden', false)
69171                     .classed('inspector-hover', true);
69172
69173                 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
69174                     inspector
69175                         .state('hover')
69176                         .entityID(id);
69177
69178                     inspectorWrap
69179                         .call(inspector);
69180                 }
69181
69182             } else if (!current) {
69183                 featureListWrap
69184                     .classed('inspector-hidden', false);
69185                 inspectorWrap
69186                     .classed('inspector-hidden', true);
69187                 inspector
69188                     .state('hide');
69189             }
69190         }
69191
69192
69193         sidebar.hover = lodash.throttle(hover, 200);
69194
69195
69196         sidebar.select = function(id, newFeature) {
69197             if (!current && id) {
69198                 featureListWrap
69199                     .classed('inspector-hidden', true);
69200
69201                 inspectorWrap
69202                     .classed('inspector-hidden', false)
69203                     .classed('inspector-hover', false);
69204
69205                 if (inspector.entityID() !== id || inspector.state() !== 'select') {
69206                     inspector
69207                         .state('select')
69208                         .entityID(id)
69209                         .newFeature(newFeature);
69210
69211                     inspectorWrap
69212                         .call(inspector);
69213                 }
69214
69215             } else if (!current) {
69216                 featureListWrap
69217                     .classed('inspector-hidden', false);
69218                 inspectorWrap
69219                     .classed('inspector-hidden', true);
69220                 inspector
69221                     .state('hide');
69222             }
69223         };
69224
69225
69226         sidebar.show = function(component) {
69227             featureListWrap
69228                 .classed('inspector-hidden', true);
69229             inspectorWrap
69230                 .classed('inspector-hidden', true);
69231
69232             if (current) current.remove();
69233             current = selection
69234                 .append('div')
69235                 .attr('class', 'sidebar-component')
69236                 .call(component);
69237         };
69238
69239
69240         sidebar.hide = function() {
69241             featureListWrap
69242                 .classed('inspector-hidden', false);
69243             inspectorWrap
69244                 .classed('inspector-hidden', true);
69245
69246             if (current) current.remove();
69247             current = null;
69248         };
69249     }
69250
69251
69252     sidebar.hover = function() {};
69253     sidebar.hover.cancel = function() {};
69254     sidebar.select = function() {};
69255     sidebar.show = function() {};
69256     sidebar.hide = function() {};
69257
69258     return sidebar;
69259 }
69260
69261 function uiSpinner(context) {
69262     var connection = context.connection();
69263
69264
69265     return function(selection) {
69266         var img = selection
69267             .append('img')
69268             .attr('src', context.imagePath('loader-black.gif'))
69269             .style('opacity', 0);
69270
69271         connection
69272             .on('loading.spinner', function() {
69273                 img.transition()
69274                     .style('opacity', 1);
69275             });
69276
69277         connection
69278             .on('loaded.spinner', function() {
69279                 img.transition()
69280                     .style('opacity', 0);
69281             });
69282     };
69283 }
69284
69285 function uiSplash(context) {
69286
69287     return function(selection) {
69288         if (context.storage('sawSplash'))
69289              return;
69290
69291         context.storage('sawSplash', true);
69292
69293         var modalSelection = uiModal(selection);
69294
69295         modalSelection.select('.modal')
69296             .attr('class', 'modal-splash modal col6');
69297
69298         var introModal = modalSelection.select('.content')
69299             .append('div')
69300             .attr('class', 'fillL');
69301
69302         introModal
69303             .append('div')
69304             .attr('class','modal-section cf')
69305             .append('h3').text(t('splash.welcome'));
69306
69307         introModal
69308             .append('div')
69309             .attr('class','modal-section')
69310             .append('p')
69311             .html(t('splash.text', {
69312                 version: context.version,
69313                 website: '<a href="http://ideditor.com/">ideditor.com</a>',
69314                 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
69315             }));
69316
69317         var buttonWrap = introModal
69318             .append('div')
69319             .attr('class', 'modal-actions cf');
69320
69321         var walkthrough = buttonWrap
69322             .append('button')
69323             .attr('class', 'walkthrough col6')
69324             .on('click', function() {
69325                 context.container().call(uiIntro(context));
69326                 modalSelection.close();
69327             });
69328
69329         walkthrough
69330             .append('svg')
69331             .attr('class', 'logo logo-walkthrough')
69332             .append('use')
69333             .attr('xlink:href', '#logo-walkthrough');
69334
69335         walkthrough
69336             .append('div')
69337             .text(t('splash.walkthrough'));
69338
69339         var startEditing = buttonWrap
69340             .append('button')
69341             .attr('class', 'start-editing col6')
69342             .on('click', modalSelection.close);
69343
69344         startEditing
69345             .append('svg')
69346             .attr('class', 'logo logo-features')
69347             .append('use')
69348             .attr('xlink:href', '#logo-features');
69349
69350         startEditing
69351             .append('div')
69352             .text(t('splash.start'));
69353
69354
69355         modalSelection.select('button.close')
69356             .attr('class','hide');
69357
69358     };
69359 }
69360
69361 function uiStatus(context) {
69362     var connection = context.connection();
69363
69364     return function(selection$$1) {
69365
69366         function update() {
69367             connection.status(function(err, apiStatus) {
69368                 selection$$1.html('');
69369
69370                 if (err) {
69371                     if (apiStatus === 'rateLimited') {
69372                         selection$$1
69373                             .text(t('status.rateLimit'))
69374                             .append('a')
69375                             .attr('class', 'api-status-login')
69376                             .attr('target', '_blank')
69377                             .call(svgIcon('#icon-out-link', 'inline'))
69378                             .append('span')
69379                             .text(t('login'))
69380                             .on('click.login', function() {
69381                                 event.preventDefault();
69382                                 connection.authenticate();
69383                             });
69384                     } else {
69385                         // TODO: nice messages for different error types
69386                         selection$$1.text(t('status.error'));
69387                     }
69388
69389                 } else if (apiStatus === 'readonly') {
69390                     selection$$1.text(t('status.readonly'));
69391                 } else if (apiStatus === 'offline') {
69392                     selection$$1.text(t('status.offline'));
69393                 }
69394
69395                 selection$$1.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
69396             });
69397         }
69398
69399         connection
69400             .on('change', function() { update(selection$$1); });
69401
69402         window.setInterval(update, 90000);
69403         update(selection$$1);
69404     };
69405 }
69406
69407 function uiUndoRedo(context) {
69408     var commands = [{
69409         id: 'undo',
69410         cmd: uiCmd('⌘Z'),
69411         action: function() { if (!saving()) context.undo(); },
69412         annotation: function() { return context.history().undoAnnotation(); }
69413     }, {
69414         id: 'redo',
69415         cmd: uiCmd('⌘⇧Z'),
69416         action: function() { if (!saving()) context.redo(); },
69417         annotation: function() { return context.history().redoAnnotation(); }
69418     }];
69419
69420
69421     function saving() {
69422         return context.mode().id === 'save';
69423     }
69424
69425
69426     return function(selection$$1) {
69427         var tooltipBehavior = tooltip()
69428             .placement('bottom')
69429             .html(true)
69430             .title(function (d) {
69431                 return uiTooltipHtml(d.annotation() ?
69432                     t(d.id + '.tooltip', {action: d.annotation()}) :
69433                     t(d.id + '.nothing'), d.cmd);
69434             });
69435
69436         var buttons = selection$$1.selectAll('button')
69437             .data(commands)
69438             .enter()
69439             .append('button')
69440             .attr('class', function(d) { return 'col6 disabled ' + d.id + '-button'; })
69441             .on('click', function(d) { return d.action(); })
69442             .call(tooltipBehavior);
69443
69444         buttons.each(function(d) {
69445             var iconName = d.id;
69446             if (textDirection === 'rtl') {
69447                 if (iconName === 'undo') {
69448                     iconName = 'redo';
69449                 } else if (iconName === 'redo') {
69450                     iconName = 'undo';
69451                 }
69452             }
69453             select(this)
69454                 .call(svgIcon('#icon-' + iconName));
69455         });
69456
69457         var keybinding = d3keybinding('undo')
69458             .on(commands[0].cmd, function() { event.preventDefault(); commands[0].action(); })
69459             .on(commands[1].cmd, function() { event.preventDefault(); commands[1].action(); });
69460
69461         select(document)
69462             .call(keybinding);
69463
69464         context.history()
69465             .on('change.undo_redo', update);
69466
69467         context
69468             .on('enter.undo_redo', update);
69469
69470         function update() {
69471             buttons
69472                 .property('disabled', saving())
69473                 .classed('disabled', function(d) { return !d.annotation(); })
69474                 .each(function() {
69475                     var selection$$1 = select(this);
69476                     if (selection$$1.property('tooltipVisible')) {
69477                         selection$$1.call(tooltipBehavior.show);
69478                     }
69479                 });
69480         }
69481     };
69482 }
69483
69484 // these are module variables so they are preserved through a ui.restart()
69485 var sawVersion = null;
69486 var isNewVersion = false;
69487 var isNewUser = false;
69488
69489
69490 function uiVersion(context) {
69491
69492     var currVersion = context.version,
69493         matchedVersion = currVersion.match(/\d\.\d\.\d.*/);
69494
69495     if (sawVersion === null && matchedVersion !== null) {
69496         isNewVersion = (context.storage('sawVersion') !== currVersion);
69497         isNewUser = !context.storage('sawSplash');
69498         context.storage('sawVersion', currVersion);
69499         sawVersion = currVersion;
69500     }
69501
69502     return function(selection) {
69503         selection
69504             .append('a')
69505             .attr('target', '_blank')
69506             .attr('tabindex', -1)
69507             .attr('href', 'https://github.com/openstreetmap/iD')
69508             .text(currVersion);
69509
69510         // only show new version indicator to users that have used iD before
69511         if (isNewVersion && !isNewUser) {
69512             selection
69513                 .append('div')
69514                 .attr('class', 'badge')
69515                 .append('a')
69516                 .attr('target', '_blank')
69517                 .attr('tabindex', -1)
69518                 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CHANGELOG.md#whats-new')
69519                 .call(svgIcon('#gift-11'))
69520                 .call(tooltip()
69521                     .title(t('version.whats_new', { version: currVersion }))
69522                     .placement('top')
69523                 );
69524         }
69525     };
69526 }
69527
69528 function uiZoom(context) {
69529     var zooms = [{
69530         id: 'zoom-in',
69531         icon: 'plus',
69532         title: t('zoom.in'),
69533         action: context.zoomIn,
69534         key: '+'
69535     }, {
69536         id: 'zoom-out',
69537         icon: 'minus',
69538         title: t('zoom.out'),
69539         action: context.zoomOut,
69540         key: '-'
69541     }];
69542
69543
69544     function zoomIn() {
69545         event.preventDefault();
69546         context.zoomIn();
69547     }
69548
69549
69550     function zoomOut() {
69551         event.preventDefault();
69552         context.zoomOut();
69553     }
69554
69555
69556     function zoomInFurther() {
69557         event.preventDefault();
69558         context.zoomInFurther();
69559     }
69560
69561
69562     function zoomOutFurther() {
69563         event.preventDefault();
69564         context.zoomOutFurther();
69565     }
69566
69567
69568     return function(selection$$1) {
69569         var button = selection$$1.selectAll('button')
69570             .data(zooms)
69571             .enter()
69572             .append('button')
69573             .attr('tabindex', -1)
69574             .attr('class', function(d) { return d.id; })
69575             .on('click.editor', function(d) { d.action(); })
69576             .call(tooltip()
69577                 .placement((textDirection === 'rtl') ? 'right' : 'left')
69578                 .html(true)
69579                 .title(function(d) {
69580                     return uiTooltipHtml(d.title, d.key);
69581                 })
69582             );
69583
69584         button.each(function(d) {
69585             select(this)
69586                 .call(svgIcon('#icon-' + d.icon, 'light'));
69587         });
69588
69589         var keybinding = d3keybinding('zoom');
69590
69591         lodash.each(['=','ffequals','plus','ffplus'], function(key) {
69592             keybinding.on([key, '⇧' + key], zoomIn);
69593             keybinding.on([uiCmd('⌘' + key), uiCmd('⌘⇧' + key)], zoomInFurther);
69594         });
69595         lodash.each(['-','ffminus','dash'], function(key) {
69596             keybinding.on([key, '⇧' + key], zoomOut);
69597             keybinding.on([uiCmd('⌘' + key), uiCmd('⌘⇧' + key)], zoomOutFurther);
69598         });
69599
69600         select(document)
69601             .call(keybinding);
69602     };
69603 }
69604
69605 function uiInit(context) {
69606     var uiInitCounter = 0;
69607
69608
69609     function render(container) {
69610         container
69611             .attr('dir', textDirection);
69612
69613         var map$$1 = context.map();
69614
69615         var hash = behaviorHash(context);
69616         hash();
69617
69618         if (!hash.hadHash) {
69619             map$$1.centerZoom([0, 0], 2);
69620         }
69621
69622         container
69623             .append('svg')
69624             .attr('id', 'defs')
69625             .call(svgDefs(context));
69626
69627         container
69628             .append('div')
69629             .attr('id', 'sidebar')
69630             .attr('class', 'col4')
69631             .call(ui.sidebar);
69632
69633         var content = container
69634             .append('div')
69635             .attr('id', 'content')
69636             .attr('class', 'active');
69637
69638         var bar = content
69639             .append('div')
69640             .attr('id', 'bar')
69641             .attr('class', 'fillD');
69642
69643         content
69644             .append('div')
69645             .attr('id', 'map')
69646             .attr('dir', 'ltr')
69647             .call(map$$1);
69648
69649         content
69650             .call(uiMapInMap(context));
69651
69652         content
69653             .append('div')
69654             .call(uiInfo(context));
69655
69656         bar
69657             .append('div')
69658             .attr('class', 'spacer col4');
69659
69660         var limiter = bar.append('div')
69661             .attr('class', 'limiter');
69662
69663         limiter
69664             .append('div')
69665             .attr('class', 'button-wrap joined col3')
69666             .call(uiModes(context), limiter);
69667
69668         limiter
69669             .append('div')
69670             .attr('class', 'button-wrap joined col1')
69671             .call(uiUndoRedo(context));
69672
69673         limiter
69674             .append('div')
69675             .attr('class', 'button-wrap col1')
69676             .call(uiSave(context));
69677
69678         bar
69679             .append('div')
69680             .attr('class', 'full-screen')
69681             .call(uiFullScreen(context));
69682
69683         bar
69684             .append('div')
69685             .attr('class', 'spinner')
69686             .call(uiSpinner(context));
69687
69688
69689         var controls = bar
69690             .append('div')
69691             .attr('class', 'map-controls');
69692
69693         controls
69694             .append('div')
69695             .attr('class', 'map-control zoombuttons')
69696             .call(uiZoom(context));
69697
69698         controls
69699             .append('div')
69700             .attr('class', 'map-control geolocate-control')
69701             .call(uiGeolocate(context));
69702
69703         controls
69704             .append('div')
69705             .attr('class', 'map-control background-control')
69706             .call(uiBackground(context));
69707
69708         controls
69709             .append('div')
69710             .attr('class', 'map-control map-data-control')
69711             .call(uiMapData(context));
69712
69713         controls
69714             .append('div')
69715             .attr('class', 'map-control help-control')
69716             .call(uiHelp(context));
69717
69718
69719         var about = content
69720             .append('div')
69721             .attr('id', 'about');
69722
69723         about
69724             .append('div')
69725             .attr('id', 'attrib')
69726             .attr('dir', 'ltr')
69727             .call(uiAttribution(context));
69728
69729         about
69730             .append('div')
69731             .attr('class', 'api-status')
69732             .call(uiStatus(context));
69733
69734
69735         var footer = about
69736             .append('div')
69737             .attr('id', 'footer')
69738             .attr('class', 'fillD');
69739
69740         footer
69741             .append('div')
69742             .attr('id', 'flash-wrap')
69743             .attr('class', 'footer-hide');
69744
69745         var footerWrap = footer
69746             .append('div')
69747             .attr('id', 'footer-wrap')
69748             .attr('class', 'footer-show');
69749
69750         footerWrap
69751             .append('div')
69752             .attr('id', 'scale-block')
69753             .call(uiScale(context));
69754
69755         var aboutList = footerWrap
69756             .append('div')
69757             .attr('id', 'info-block')
69758             .append('ul')
69759             .attr('id', 'about-list');
69760
69761         if (!context.embed()) {
69762             aboutList
69763                 .call(uiAccount(context));
69764         }
69765
69766         aboutList
69767             .append('li')
69768             .attr('class', 'version')
69769             .call(uiVersion(context));
69770
69771         var issueLinks = aboutList
69772             .append('li');
69773
69774         issueLinks
69775             .append('a')
69776             .attr('target', '_blank')
69777             .attr('tabindex', -1)
69778             .attr('href', 'https://github.com/openstreetmap/iD/issues')
69779             .call(svgIcon('#icon-bug', 'light'))
69780             .call(tooltip().title(t('report_a_bug')).placement('top'));
69781
69782         issueLinks
69783             .append('a')
69784             .attr('target', '_blank')
69785             .attr('tabindex', -1)
69786             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
69787             .call(svgIcon('#icon-translate', 'light'))
69788             .call(tooltip().title(t('help_translate')).placement('top'));
69789
69790         aboutList
69791             .append('li')
69792             .attr('class', 'feature-warning')
69793             .attr('tabindex', -1)
69794             .call(uiFeatureInfo(context));
69795
69796         aboutList
69797             .append('li')
69798             .attr('class', 'user-list')
69799             .attr('tabindex', -1)
69800             .call(uiContributors(context));
69801
69802
69803         window.onbeforeunload = function() {
69804             return context.save();
69805         };
69806
69807         window.onunload = function() {
69808             context.history().unlock();
69809         };
69810
69811         var mapDimensions = map$$1.dimensions();
69812
69813
69814         function onResize() {
69815             mapDimensions = utilGetDimensions(content, true);
69816             map$$1.dimensions(mapDimensions);
69817         }
69818
69819         select(window)
69820             .on('resize.editor', onResize);
69821
69822         onResize();
69823
69824         function pan(d) {
69825             return function() {
69826                 event.preventDefault();
69827                 context.pan(d, 100);
69828             };
69829         }
69830
69831
69832         // pan amount
69833         var pa = 10;
69834
69835         var keybinding = d3keybinding('main')
69836             .on('⌫', function() { event.preventDefault(); })
69837             .on('←', pan([pa, 0]))
69838             .on('↑', pan([0, pa]))
69839             .on('→', pan([-pa, 0]))
69840             .on('↓', pan([0, -pa]))
69841             .on(['⇧←', uiCmd('⌘←')], pan([mapDimensions[0], 0]))
69842             .on(['⇧↑', uiCmd('⌘↑')], pan([0, mapDimensions[1]]))
69843             .on(['⇧→', uiCmd('⌘→')], pan([-mapDimensions[0], 0]))
69844             .on(['⇧↓', uiCmd('⌘↓')], pan([0, -mapDimensions[1]]));
69845
69846         select(document)
69847             .call(keybinding);
69848
69849         context.enter(modeBrowse(context));
69850
69851         if (!uiInitCounter++) {
69852             context.container()
69853                 .call(uiSplash(context))
69854                 .call(uiRestore(context));
69855         }
69856
69857         var authenticating = uiLoading(context)
69858             .message(t('loading_auth'))
69859             .blocking(true);
69860
69861         context.connection()
69862             .on('authLoading.ui', function() {
69863                 context.container()
69864                     .call(authenticating);
69865             })
69866             .on('authDone.ui', function() {
69867                 authenticating.close();
69868             });
69869
69870         uiInitCounter++;
69871     }
69872
69873
69874     var renderCallback;
69875
69876     function ui(node, callback) {
69877         renderCallback = callback;
69878         var container = select(node);
69879         context.container(container);
69880         context.loadLocale(function(err) {
69881             if (!err) {
69882                 render(container);
69883             }
69884             if (callback) {
69885                 callback(err);
69886             }
69887         });
69888     }
69889
69890
69891     ui.restart = function(arg) {
69892         context.locale(arg);
69893         context.loadLocale(function(err) {
69894             if (!err) {
69895                 context.container().selectAll('*').remove();
69896                 render(context.container());
69897                 if (renderCallback) renderCallback();
69898             }
69899         });
69900     };
69901
69902
69903     ui.sidebar = uiSidebar(context);
69904
69905     return ui;
69906 }
69907
69908 var changeset;
69909 var readOnlyTags = ['created_by', 'imagery_used', 'host', 'locale'];
69910
69911
69912 function uiCommit(context) {
69913     var dispatch$$1 = dispatch('cancel', 'save');
69914
69915
69916     function commit(selection$$1) {
69917         if (!changeset) {
69918             var detected = utilDetect(),
69919                 tags = {
69920                     created_by: ('iD ' + context.version).substr(0, 255),
69921                     imagery_used: context.history().imageryUsed().join(';').substr(0, 255),
69922                     host: detected.host.substr(0, 255),
69923                     locale: detected.locale.substr(0, 255)
69924                 };
69925
69926             changeset = new osmChangeset({ tags: tags });
69927         }
69928
69929
69930         var changes = context.history().changes(),
69931             summary = context.history().difference().summary(),
69932             rawTagEditor = uiRawTagEditor(context).on('change', changeTags),
69933             comment = context.storage('comment') || '',
69934             commentDate = +context.storage('commentDate') || 0,
69935             currDate = Date.now(),
69936             cutoff = 2 * 86400 * 1000;   // 2 days
69937
69938         // expire the stored comment if it is too old - #3947
69939         if (commentDate > currDate || currDate - commentDate > cutoff) {
69940             comment = '';
69941         }
69942
69943         selection$$1
69944             .append('div')
69945             .attr('class', 'header fillL')
69946             .append('h3')
69947             .text(t('commit.title'));
69948
69949         var body = selection$$1
69950             .append('div')
69951             .attr('class', 'body');
69952
69953         var commentSection = body
69954             .append('div')
69955             .attr('class', 'modal-section form-field commit-form');
69956
69957         commentSection
69958             .append('label')
69959             .attr('class', 'form-label')
69960             .text(t('commit.message_label'));
69961
69962         var commentField = commentSection
69963             .append('textarea')
69964             .attr('class', 'commit-form-comment')
69965             .attr('placeholder', t('commit.description_placeholder'))
69966             .attr('maxlength', 255)
69967             .property('value', comment)
69968             .on('input.save', change(true))
69969             .on('change.save', change())
69970             .on('blur.save', function() {
69971                 context.storage('comment', this.value);
69972                 context.storage('commentDate', Date.now());
69973             });
69974
69975
69976         commentField.node().select();
69977
69978         context.connection().userChangesets(function (err, changesets) {
69979             if (err) return;
69980
69981             var comments = changesets.map(function(changeset) {
69982                 return {
69983                     title: changeset.tags.comment,
69984                     value: changeset.tags.comment
69985                 };
69986             });
69987
69988             commentField
69989                 .call(d3combobox()
69990                     .container(context.container())
69991                     .caseSensitive(true)
69992                     .data(lodash.uniqBy(comments, 'title'))
69993                 );
69994         });
69995
69996         var clippyArea = commentSection.append('div')
69997             .attr('class', 'clippy-area');
69998
69999         var changeSetInfo = commentSection.append('div')
70000             .attr('class', 'changeset-info');
70001
70002         changeSetInfo.append('a')
70003             .attr('target', '_blank')
70004             .attr('tabindex', -1)
70005             .call(svgIcon('#icon-out-link', 'inline'))
70006             .attr('href', t('commit.about_changeset_comments_link'))
70007             .append('span')
70008             .text(t('commit.about_changeset_comments'));
70009
70010
70011         // Warnings
70012         var warnings = body.selectAll('div.warning-section')
70013             .data([context.history().validate(changes)]);
70014
70015         warnings = warnings.enter()
70016             .append('div')
70017             .attr('class', 'modal-section warning-section fillL2')
70018             .style('display', function(d) { return lodash.isEmpty(d) ? 'none' : null; })
70019             .style('background', '#ffb')
70020             .merge(warnings);
70021
70022         warnings
70023             .append('h3')
70024             .text(t('commit.warnings'));
70025
70026         warnings
70027             .append('ul')
70028             .attr('class', 'changeset-list');
70029
70030         var warningLi = warnings.select('ul').selectAll('li')
70031             .data(function(d) { return d; });
70032
70033         warningLi = warningLi.enter()
70034             .append('li')
70035             .on('mouseover', mouseover)
70036             .on('mouseout', mouseout)
70037             .on('click', warningClick)
70038             .merge(warningLi);
70039
70040         warningLi
70041             .call(svgIcon('#icon-alert', 'pre-text'));
70042
70043         warningLi
70044             .append('strong')
70045             .text(function(d) { return d.message; });
70046
70047         warningLi.filter(function(d) { return d.tooltip; })
70048             .call(tooltip()
70049                 .title(function(d) { return d.tooltip; })
70050                 .placement('top')
70051             );
70052
70053
70054         // Upload Explanation
70055         var saveSection = body
70056             .append('div')
70057             .attr('class','modal-section save-section fillL cf');
70058
70059         var prose = saveSection
70060             .append('p')
70061             .attr('class', 'commit-info')
70062             .html(t('commit.upload_explanation'));
70063
70064
70065         context.connection().userDetails(function(err, user) {
70066             if (err) return;
70067
70068             var userLink = select(document.createElement('div'));
70069
70070             if (user.image_url) {
70071                 userLink
70072                     .append('img')
70073                     .attr('src', user.image_url)
70074                     .attr('class', 'icon pre-text user-icon');
70075             }
70076
70077             userLink
70078                 .append('a')
70079                 .attr('class','user-info')
70080                 .text(user.display_name)
70081                 .attr('href', context.connection().userURL(user.display_name))
70082                 .attr('tabindex', -1)
70083                 .attr('target', '_blank');
70084
70085             prose
70086                 .html(t('commit.upload_explanation_with_user', { user: userLink.html() }));
70087         });
70088
70089
70090         // Buttons
70091         var buttonSection = saveSection
70092             .append('div')
70093             .attr('class', 'buttons fillL cf');
70094
70095         var cancelButton = buttonSection
70096             .append('button')
70097             .attr('class', 'secondary-action col5 button cancel-button')
70098             .on('click.cancel', function() {
70099                 dispatch$$1.call('cancel');
70100             });
70101
70102         cancelButton
70103             .append('span')
70104             .attr('class', 'label')
70105             .text(t('commit.cancel'));
70106
70107         var saveButton = buttonSection
70108             .append('button')
70109             .attr('class', 'action col5 button save-button')
70110             .attr('disabled', function() {
70111                 var n = select('.commit-form textarea').node();
70112                 return (n && n.value.length) ? null : true;
70113             })
70114             .on('click.save', function() {
70115                 dispatch$$1.call('save', this, changeset);
70116             });
70117
70118         saveButton
70119             .append('span')
70120             .attr('class', 'label')
70121             .text(t('commit.save'));
70122
70123
70124         // Raw Tag Editor
70125         var tagSection = body
70126             .append('div')
70127             .attr('class', 'modal-section tag-section raw-tag-editor');
70128
70129
70130         // Changes
70131         var changeSection = body
70132             .append('div')
70133             .attr('class', 'commit-section modal-section fillL2');
70134
70135         changeSection.append('h3')
70136             .text(t('commit.changes', { count: summary.length }));
70137
70138         var li = changeSection
70139             .append('ul')
70140             .attr('class', 'changeset-list')
70141             .selectAll('li')
70142             .data(summary);
70143
70144         li = li.enter()
70145             .append('li')
70146             .on('mouseover', mouseover)
70147             .on('mouseout', mouseout)
70148             .on('click', zoomToEntity)
70149             .merge(li);
70150
70151         li.each(function(d) {
70152             select(this)
70153                 .call(svgIcon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
70154         });
70155
70156         li.append('span')
70157             .attr('class', 'change-type')
70158             .text(function(d) { return t('commit.' + d.changeType) + ' '; });
70159
70160         li.append('strong')
70161             .attr('class', 'entity-type')
70162             .text(function(d) {
70163                 var matched = context.presets().match(d.entity, d.graph);
70164                 return (matched && matched.name()) || utilDisplayType(d.entity.id);
70165             });
70166
70167         li.append('span')
70168             .attr('class', 'entity-name')
70169             .text(function(d) {
70170                 var name = utilDisplayName(d.entity) || '',
70171                     string = '';
70172                 if (name !== '') string += ':';
70173                 return string += ' ' + name;
70174             });
70175
70176         li.style('opacity', 0)
70177             .transition()
70178             .style('opacity', 1);
70179
70180
70181         // Call change() off the bat, in case a changeset
70182         // comment is recovered from localStorage
70183         utilTriggerEvent(commentField, 'input');
70184
70185
70186         function mouseover(d) {
70187             if (d.entity) {
70188                 context.surface().selectAll(
70189                     utilEntityOrMemberSelector([d.entity.id], context.graph())
70190                 ).classed('hover', true);
70191             }
70192         }
70193
70194
70195         function mouseout() {
70196             context.surface().selectAll('.hover')
70197                 .classed('hover', false);
70198         }
70199
70200
70201         function warningClick(d) {
70202             if (d.entity) {
70203                 context.map().zoomTo(d.entity);
70204                 context.enter(modeSelect(context, [d.entity.id]));
70205             }
70206         }
70207
70208
70209         function zoomToEntity(change) {
70210             var entity = change.entity;
70211             if (change.changeType !== 'deleted' &&
70212                 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
70213                 context.map().zoomTo(entity);
70214                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
70215                     .classed('hover', true);
70216             }
70217         }
70218
70219
70220         function checkComment(comment) {
70221             // Save button disabled if there is no comment..
70222             selectAll('.save-section .save-button')
70223                 .attr('disabled', (comment.length ? null : true));
70224
70225             // Warn if comment mentions Google..
70226             var googleWarning = clippyArea
70227                .html('')
70228                .selectAll('a')
70229                .data(comment.match(/google/i) ? [true] : []);
70230
70231             googleWarning.exit()
70232                 .remove();
70233
70234             googleWarning.enter()
70235                .append('a')
70236                .attr('target', '_blank')
70237                .attr('tabindex', -1)
70238                .call(svgIcon('#icon-alert', 'inline'))
70239                .attr('href', t('commit.google_warning_link'))
70240                .append('span')
70241                .text(t('commit.google_warning'));
70242         }
70243
70244
70245         function change(onInput) {
70246             return function() {
70247                 var comment = commentField.property('value').trim();
70248                 if (!onInput) {
70249                     commentField.property('value', comment);
70250                 }
70251
70252                 checkComment(comment);
70253
70254                 var changeset = updateChangeset({ comment: comment });
70255                 var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
70256
70257                 tagSection
70258                     .call(rawTagEditor
70259                         .expanded(expanded)
70260                         .readOnlyTags(readOnlyTags)
70261                         .tags(lodash.clone(changeset.tags))
70262                     );
70263             };
70264         }
70265
70266
70267         function changeTags(changed) {
70268             if (changed.hasOwnProperty('comment')) {
70269                 if (changed.comment === undefined) {
70270                     changed.comment = '';
70271                 }
70272                 changed.comment = changed.comment.trim();
70273                 commentField.property('value', changed.comment);
70274             }
70275             updateChangeset(changed);
70276             utilTriggerEvent(commentField, 'input');
70277         }
70278
70279
70280         function updateChangeset(changed) {
70281             var tags = lodash.clone(changeset.tags);
70282
70283             lodash.forEach(changed, function(v, k) {
70284                 k = k.trim().substr(0, 255);
70285                 if (readOnlyTags.indexOf(k) !== -1) return;
70286
70287                 if (k !== '' && v !== undefined) {
70288                     tags[k] = v.trim().substr(0, 255);
70289                 } else {
70290                     delete tags[k];
70291                 }
70292             });
70293
70294             if (!lodash.isEqual(changeset.tags, tags)) {
70295                 changeset = changeset.update({ tags: tags });
70296             }
70297
70298             return changeset;
70299         }
70300
70301     }
70302
70303
70304     commit.reset = function() {
70305         changeset = null;
70306     };
70307
70308
70309     return utilRebind(commit, dispatch$$1, 'on');
70310 }
70311
70312 function uiConfirm(selection) {
70313     var modalSelection = uiModal(selection);
70314
70315     modalSelection.select('.modal')
70316         .classed('modal-alert', true);
70317
70318     var section = modalSelection.select('.content');
70319
70320     section.append('div')
70321         .attr('class', 'modal-section header');
70322
70323     section.append('div')
70324         .attr('class', 'modal-section message-text');
70325
70326     var buttons = section.append('div')
70327         .attr('class', 'modal-section buttons cf');
70328
70329
70330     modalSelection.okButton = function() {
70331         buttons
70332             .append('button')
70333             .attr('class', 'action col4')
70334             .on('click.confirm', function() {
70335                 modalSelection.remove();
70336             })
70337             .text(t('confirm.okay'));
70338
70339         return modalSelection;
70340     };
70341
70342
70343     return modalSelection;
70344 }
70345
70346 function uiConflicts(context) {
70347     var dispatch$$1 = dispatch('download', 'cancel', 'save'),
70348         list;
70349
70350
70351     function conflicts(selection$$1) {
70352         var header = selection$$1
70353             .append('div')
70354             .attr('class', 'header fillL');
70355
70356         header
70357             .append('button')
70358             .attr('class', 'fr')
70359             .on('click', function() { dispatch$$1.call('cancel'); })
70360             .call(svgIcon('#icon-close'));
70361
70362         header
70363             .append('h3')
70364             .text(t('save.conflict.header'));
70365
70366         var body = selection$$1
70367             .append('div')
70368             .attr('class', 'body fillL');
70369
70370         body
70371             .append('div')
70372             .attr('class', 'conflicts-help')
70373             .text(t('save.conflict.help'))
70374             .append('a')
70375             .attr('class', 'conflicts-download')
70376             .text(t('save.conflict.download_changes'))
70377             .on('click.download', function() { dispatch$$1.call('download'); });
70378
70379         body
70380             .append('div')
70381             .attr('class', 'conflict-container fillL3')
70382             .call(showConflict, 0);
70383
70384         body
70385             .append('div')
70386             .attr('class', 'conflicts-done')
70387             .attr('opacity', 0)
70388             .style('display', 'none')
70389             .text(t('save.conflict.done'));
70390
70391         var buttons = body
70392             .append('div')
70393             .attr('class','buttons col12 joined conflicts-buttons');
70394
70395         buttons
70396             .append('button')
70397             .attr('disabled', list.length > 1)
70398             .attr('class', 'action conflicts-button col6')
70399             .text(t('save.title'))
70400             .on('click.try_again', function() { dispatch$$1.call('save'); });
70401
70402         buttons
70403             .append('button')
70404             .attr('class', 'secondary-action conflicts-button col6')
70405             .text(t('confirm.cancel'))
70406             .on('click.cancel', function() { dispatch$$1.call('cancel'); });
70407     }
70408
70409
70410     function showConflict(selection$$1, index) {
70411         if (index < 0 || index >= list.length) return;
70412
70413         var parent = select(selection$$1.node().parentNode);
70414
70415         // enable save button if this is the last conflict being reviewed..
70416         if (index === list.length - 1) {
70417             window.setTimeout(function() {
70418                 parent.select('.conflicts-button')
70419                     .attr('disabled', null);
70420
70421                 parent.select('.conflicts-done')
70422                     .transition()
70423                     .attr('opacity', 1)
70424                     .style('display', 'block');
70425             }, 250);
70426         }
70427
70428         var item = selection$$1
70429             .selectAll('.conflict')
70430             .data([list[index]]);
70431
70432         var enter = item.enter()
70433             .append('div')
70434             .attr('class', 'conflict');
70435
70436         enter
70437             .append('h4')
70438             .attr('class', 'conflict-count')
70439             .text(t('save.conflict.count', { num: index + 1, total: list.length }));
70440
70441         enter
70442             .append('a')
70443             .attr('class', 'conflict-description')
70444             .attr('href', '#')
70445             .text(function(d) { return d.name; })
70446             .on('click', function(d) {
70447                 zoomToEntity(d.id);
70448                 event.preventDefault();
70449             });
70450
70451         var details = enter
70452             .append('div')
70453             .attr('class', 'conflict-detail-container');
70454
70455         details
70456             .append('ul')
70457             .attr('class', 'conflict-detail-list')
70458             .selectAll('li')
70459             .data(function(d) { return d.details || []; })
70460             .enter()
70461             .append('li')
70462             .attr('class', 'conflict-detail-item')
70463             .html(function(d) { return d; });
70464
70465         details
70466             .append('div')
70467             .attr('class', 'conflict-choices')
70468             .call(addChoices);
70469
70470         details
70471             .append('div')
70472             .attr('class', 'conflict-nav-buttons joined cf')
70473             .selectAll('button')
70474             .data(['previous', 'next'])
70475             .enter()
70476             .append('button')
70477             .text(function(d) { return t('save.conflict.' + d); })
70478             .attr('class', 'conflict-nav-button action col6')
70479             .attr('disabled', function(d, i) {
70480                 return (i === 0 && index === 0) ||
70481                     (i === 1 && index === list.length - 1) || null;
70482             })
70483             .on('click', function(d, i) {
70484                 var container = parent.select('.conflict-container'),
70485                 sign = (i === 0 ? -1 : 1);
70486
70487                 container
70488                     .selectAll('.conflict')
70489                     .remove();
70490
70491                 container
70492                     .call(showConflict, index + sign);
70493
70494                 event.preventDefault();
70495             });
70496
70497         item.exit()
70498             .remove();
70499     }
70500
70501
70502     function addChoices(selection$$1) {
70503         var choices = selection$$1
70504             .append('ul')
70505             .attr('class', 'layer-list')
70506             .selectAll('li')
70507             .data(function(d) { return d.choices || []; });
70508
70509         var enter = choices.enter()
70510             .append('li')
70511             .attr('class', 'layer');
70512
70513         var label = enter
70514             .append('label');
70515
70516         label
70517             .append('input')
70518             .attr('type', 'radio')
70519             .attr('name', function(d) { return d.id; })
70520             .on('change', function(d, i) {
70521                 var ul = this.parentNode.parentNode.parentNode;
70522                 ul.__data__.chosen = i;
70523                 choose(ul, d);
70524             });
70525
70526         label
70527             .append('span')
70528             .text(function(d) { return d.text; });
70529
70530         choices
70531             .each(function(d, i) {
70532                 var ul = this.parentNode;
70533                 if (ul.__data__.chosen === i) choose(ul, d);
70534             });
70535     }
70536
70537
70538     function choose(ul, datum) {
70539         if (event) event.preventDefault();
70540
70541         select(ul)
70542             .selectAll('li')
70543             .classed('active', function(d) { return d === datum; })
70544             .selectAll('input')
70545             .property('checked', function(d) { return d === datum; });
70546
70547         var extent$$1 = geoExtent$$1(),
70548             entity;
70549
70550         entity = context.graph().hasEntity(datum.id);
70551         if (entity) extent$$1._extend(entity.extent(context.graph()));
70552
70553         datum.action();
70554
70555         entity = context.graph().hasEntity(datum.id);
70556         if (entity) extent$$1._extend(entity.extent(context.graph()));
70557
70558         zoomToEntity(datum.id, extent$$1);
70559     }
70560
70561
70562     function zoomToEntity(id, extent$$1) {
70563         context.surface().selectAll('.hover')
70564             .classed('hover', false);
70565
70566         var entity = context.graph().hasEntity(id);
70567         if (entity) {
70568             if (extent$$1) {
70569                 context.map().trimmedExtent(extent$$1);
70570             } else {
70571                 context.map().zoomTo(entity);
70572             }
70573             context.surface().selectAll(
70574                 utilEntityOrMemberSelector([entity.id], context.graph()))
70575                 .classed('hover', true);
70576         }
70577     }
70578
70579
70580     // The conflict list should be an array of objects like:
70581     // {
70582     //     id: id,
70583     //     name: entityName(local),
70584     //     details: merge.conflicts(),
70585     //     chosen: 1,
70586     //     choices: [
70587     //         choice(id, keepMine, forceLocal),
70588     //         choice(id, keepTheirs, forceRemote)
70589     //     ]
70590     // }
70591     conflicts.list = function(_) {
70592         if (!arguments.length) return list;
70593         list = _;
70594         return conflicts;
70595     };
70596
70597
70598     return utilRebind(conflicts, dispatch$$1, 'on');
70599 }
70600
70601 function uiEditMenu(context, operations) {
70602     var menu,
70603         center = [0, 0],
70604         offset = [0, 0],
70605         tooltip;
70606
70607     var p = 8,               // top padding
70608         m = 4,               // top margin
70609         h = 15,              // height of icon
70610         vpBottomMargin = 45, // viewport bottom margin
70611         vpSideMargin = 35,   // viewport side margin
70612         buttonWidth = 44,
70613         buttonHeight = (2 * p + h),
70614         menuWidth = buttonWidth,
70615         menuHeight = (2 * m) + operations.length * buttonHeight,
70616         menuSideMargin = 10,
70617         tooltipWidth = 200,
70618         tooltipHeight = 200;  // a reasonable guess, real height depends on tooltip contents
70619
70620
70621     var editMenu = function (selection$$1) {
70622         if (!operations.length) return;
70623
70624         selection$$1.node().parentNode.focus();
70625
70626         var isRTL = textDirection === 'rtl',
70627             viewport = context.surfaceRect();
70628
70629         if (!isRTL && (center[0] + menuSideMargin + menuWidth) > (viewport.width - vpSideMargin)) {
70630             // menu is going left-to-right and near right viewport edge, go left instead
70631             isRTL = true;
70632         } else if (isRTL && (center[0] - menuSideMargin - menuWidth) < vpSideMargin) {
70633             // menu is going right-to-left and near left viewport edge, go right instead
70634             isRTL = false;
70635         }
70636
70637         offset[0] = (isRTL ? -1 * (menuSideMargin + menuWidth) : menuSideMargin);
70638
70639         if (center[1] + menuHeight > (viewport.height - vpBottomMargin)) {
70640             // menu is near bottom viewport edge, shift upwards
70641             offset[1] = -1 * (center[1] + menuHeight - viewport.height + vpBottomMargin);
70642         }
70643
70644         var origin = [ center[0] + offset[0], center[1] + offset[1] ];
70645
70646         menu = selection$$1
70647             .append('g')
70648             .attr('class', 'edit-menu')
70649             .attr('transform', 'translate(' + origin + ')')
70650             .attr('opacity', 0);
70651
70652         menu
70653             .transition()
70654             .attr('opacity', 1);
70655
70656         menu
70657             .append('rect')
70658             .attr('class', 'edit-menu-background')
70659             .attr('x', 4)
70660             .attr('rx', 4)
70661             .attr('ry', 4)
70662             .attr('width', menuWidth)
70663             .attr('height', menuHeight)
70664             .attr('stroke-linecap', 'round');
70665
70666
70667         var button = menu.selectAll('.edit-menu-item')
70668             .data(operations)
70669             .enter()
70670             .append('g')
70671             .attr('class', function (d) { return 'edit-menu-item edit-menu-item-' + d.id; })
70672             .classed('disabled', function (d) { return d.disabled(); })
70673             .attr('transform', function (d, i) {
70674                 return 'translate(' + geoRoundCoords([
70675                     0,
70676                     m + i * buttonHeight
70677                 ]).join(',') + ')';
70678             });
70679
70680         button
70681             .append('rect')
70682             .attr('x', 4)
70683             .attr('width', buttonWidth)
70684             .attr('height', buttonHeight)
70685             .on('click', click)
70686             .on('mousedown', mousedown)
70687             .on('mouseover', mouseover)
70688             .on('mouseout', mouseout);
70689
70690         button
70691             .append('use')
70692             .attr('width', '20')
70693             .attr('height', '20')
70694             .attr('transform', function () {
70695                 return 'translate(' + [2 * p, 5] + ')';
70696             })
70697             .attr('xlink:href', function (d) { return '#operation-' + d.id; });
70698
70699         tooltip = select(document.body)
70700             .append('div')
70701             .attr('class', 'tooltip-inner edit-menu-tooltip');
70702
70703
70704         function click(operation) {
70705             event.stopPropagation();
70706             if (operation.disabled()) return;
70707             operation();
70708             editMenu.close();
70709         }
70710
70711         function mousedown() {
70712             event.stopPropagation();  // https://github.com/openstreetmap/iD/issues/1869
70713         }
70714
70715         function mouseover(d, i) {
70716             var tipX, tipY;
70717
70718             if (!isRTL) {
70719                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
70720             } else {
70721                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
70722             }
70723
70724             if (tipX + tooltipWidth > viewport.right) {
70725                 // tip is going left-to-right and near right viewport edge, go left instead
70726                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
70727             } else if (tipX < viewport.left) {
70728                 // tip is going right-to-left and near left viewport edge, go right instead
70729                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
70730             }
70731
70732             tipY = viewport.top + origin[1] + (i * buttonHeight);
70733             if (tipY + tooltipHeight > viewport.bottom) {
70734                 // tip is near bottom viewport edge, shift upwards
70735                 tipY -= tipY + tooltipHeight - viewport.bottom;
70736             }
70737
70738             tooltip
70739                 .style('left', tipX + 'px')
70740                 .style('top', tipY + 'px')
70741                 .style('display', 'block')
70742                 .html(uiTooltipHtml(d.tooltip(), d.keys[0], d.title));
70743         }
70744
70745         function mouseout() {
70746             tooltip.style('display', 'none');
70747         }
70748     };
70749
70750
70751     editMenu.close = function () {
70752         if (menu) {
70753             menu
70754                 .style('pointer-events', 'none')
70755                 .transition()
70756                 .attr('opacity', 0)
70757                 .remove();
70758         }
70759
70760         if (tooltip) {
70761             tooltip.remove();
70762         }
70763     };
70764
70765
70766     editMenu.center = function (_) {
70767         if (!arguments.length) return center;
70768         center = _;
70769         return editMenu;
70770     };
70771
70772
70773     return editMenu;
70774 }
70775
70776 var timer$1;
70777
70778 function uiFlash(showDuration) {
70779     showDuration = showDuration || 1500;
70780
70781     if (timer$1) {
70782         timer$1.stop();
70783     }
70784
70785     select('#footer-wrap')
70786         .attr('class', 'footer-hide');
70787     select('#flash-wrap')
70788         .attr('class', 'footer-show');
70789
70790     var content = select('#flash-wrap').selectAll('.content')
70791         .data([0]);
70792
70793     content = content.enter()
70794         .append('div')
70795         .attr('class', 'content')
70796         .merge(content);
70797
70798     timer$1 = timeout$1(function() {
70799         timer$1 = null;
70800         select('#footer-wrap')
70801             .attr('class', 'footer-show');
70802         select('#flash-wrap')
70803             .attr('class', 'footer-hide');
70804     }, showDuration);
70805
70806
70807     return content;
70808 }
70809
70810 function uiLasso(context) {
70811     var group, polygon;
70812
70813     lasso.coordinates = [];
70814
70815     function lasso(selection$$1) {
70816         context.container()
70817             .classed('lasso', true);
70818
70819         group = selection$$1
70820             .append('g')
70821             .attr('class', 'lasso hide');
70822
70823         polygon = group
70824             .append('path')
70825             .attr('class', 'lasso-path');
70826
70827         group
70828             .call(uiToggle(true));
70829     }
70830
70831
70832     function draw() {
70833         if (polygon) {
70834             polygon.data([lasso.coordinates])
70835                 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
70836         }
70837     }
70838
70839
70840     lasso.extent = function () {
70841         return lasso.coordinates.reduce(function(extent$$1, point) {
70842             return extent$$1.extend(geoExtent$$1(point));
70843         }, geoExtent$$1());
70844     };
70845
70846
70847     lasso.p = function(_) {
70848         if (!arguments.length) return lasso;
70849         lasso.coordinates.push(_);
70850         draw();
70851         return lasso;
70852     };
70853
70854
70855     lasso.close = function() {
70856         if (group) {
70857             group.call(uiToggle(false, function() {
70858                 select(this).remove();
70859             }));
70860         }
70861         context.container().classed('lasso', false);
70862     };
70863
70864
70865     return lasso;
70866 }
70867
70868 function uiRadialMenu(context, operations) {
70869     var menu,
70870         center = [0, 0],
70871         tooltip;
70872
70873
70874     var radialMenu = function(selection$$1) {
70875         if (!operations.length) return;
70876
70877         selection$$1.node().parentNode.focus();
70878
70879         function click(operation) {
70880             event.stopPropagation();
70881             if (operation.disabled()) return;
70882             operation();
70883             radialMenu.close();
70884         }
70885
70886         menu = selection$$1
70887             .append('g')
70888             .attr('class', 'radial-menu')
70889             .attr('transform', 'translate(' + center + ')')
70890             .attr('opacity', 0);
70891
70892         menu
70893             .transition()
70894             .attr('opacity', 1);
70895
70896         var r = 50,
70897             a = Math.PI / 4,
70898             a0 = -Math.PI / 4,
70899             a1 = a0 + (operations.length - 1) * a;
70900
70901         menu
70902             .append('path')
70903             .attr('class', 'radial-menu-background')
70904             .attr('d', 'M' + r * Math.sin(a0) + ',' +
70905                              r * Math.cos(a0) +
70906                       ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
70907                              (r * Math.sin(a1) + 1e-3) + ',' +
70908                              (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
70909             .attr('stroke-width', 50)
70910             .attr('stroke-linecap', 'round');
70911
70912         var button = menu.selectAll()
70913             .data(operations)
70914             .enter()
70915             .append('g')
70916             .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
70917             .classed('disabled', function(d) { return d.disabled(); })
70918             .attr('transform', function(d, i) {
70919                 return 'translate(' + geoRoundCoords([
70920                         r * Math.sin(a0 + i * a),
70921                         r * Math.cos(a0 + i * a)]).join(',') + ')';
70922             });
70923
70924         button
70925             .append('circle')
70926             .attr('r', 15)
70927             .on('click', click)
70928             .on('mousedown', mousedown)
70929             .on('mouseover', mouseover)
70930             .on('mouseout', mouseout);
70931
70932         button
70933             .append('use')
70934             .attr('transform', 'translate(-10,-10)')
70935             .attr('width', '20')
70936             .attr('height', '20')
70937             .attr('xlink:href', function(d) { return '#operation-' + d.id; });
70938
70939         tooltip = select(document.body)
70940             .append('div')
70941             .attr('class', 'tooltip-inner radial-menu-tooltip');
70942
70943         function mousedown() {
70944             event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
70945         }
70946
70947         function mouseover(d, i) {
70948             var rect = context.surfaceRect(),
70949                 angle = a0 + i * a,
70950                 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
70951                 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
70952                 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
70953                 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
70954
70955             tooltip
70956                 .style('top', null)
70957                 .style('left', null)
70958                 .style('bottom', null)
70959                 .style('right', null)
70960                 .style('display', 'block')
70961                 .html(uiTooltipHtml(d.tooltip(), d.keys[0]));
70962
70963             if (i === 0) {
70964                 tooltip
70965                     .style('right', right)
70966                     .style('top', top);
70967             } else if (i >= 4) {
70968                 tooltip
70969                     .style('left', left)
70970                     .style('bottom', bottom);
70971             } else {
70972                 tooltip
70973                     .style('left', left)
70974                     .style('top', top);
70975             }
70976         }
70977
70978         function mouseout() {
70979             tooltip.style('display', 'none');
70980         }
70981     };
70982
70983
70984     radialMenu.close = function() {
70985         if (menu) {
70986             menu
70987                 .style('pointer-events', 'none')
70988                 .transition()
70989                 .attr('opacity', 0)
70990                 .remove();
70991         }
70992
70993         if (tooltip) {
70994             tooltip.remove();
70995         }
70996     };
70997
70998
70999     radialMenu.center = function(_) {
71000         if (!arguments.length) return center;
71001         center = _;
71002         return radialMenu;
71003     };
71004
71005
71006     return radialMenu;
71007 }
71008
71009 function uiSelectionList(context, selectedIDs) {
71010
71011     function selectEntity(entity) {
71012         context.enter(modeSelect(context, [entity.id]));
71013     }
71014
71015
71016     function deselectEntity(entity) {
71017         event.stopPropagation();
71018         var index = selectedIDs.indexOf(entity.id);
71019         if (index > -1) {
71020             selectedIDs.splice(index, 1);
71021         }
71022         context.enter(modeSelect(context, selectedIDs));
71023     }
71024
71025
71026     function selectionList(selection$$1) {
71027         selection$$1.classed('selection-list-pane', true);
71028
71029         var header = selection$$1
71030             .append('div')
71031             .attr('class', 'header fillL cf');
71032
71033         header
71034             .append('h3')
71035             .text(t('inspector.multiselect'));
71036
71037         var listWrap = selection$$1
71038             .append('div')
71039             .attr('class', 'inspector-body');
71040
71041         var list = listWrap
71042             .append('div')
71043             .attr('class', 'feature-list cf');
71044
71045         context.history().on('change.selection-list', drawList);
71046         drawList();
71047
71048
71049         function drawList() {
71050             var entities = selectedIDs
71051                 .map(function(id) { return context.hasEntity(id); })
71052                 .filter(function(entity) { return entity; });
71053
71054             var items = list.selectAll('.feature-list-item')
71055                 .data(entities, osmEntity$$1.key);
71056
71057             items.exit()
71058                 .remove();
71059
71060             // Enter
71061             var enter = items.enter()
71062                 .append('div')
71063                 .attr('class', 'feature-list-item')
71064                 .on('click', selectEntity);
71065
71066             var label = enter
71067                 .append('button')
71068                 .attr('class', 'label');
71069
71070             enter
71071                 .append('button')
71072                 .attr('class', 'close')
71073                 .on('click', deselectEntity)
71074                 .call(svgIcon('#icon-close'));
71075
71076             label
71077                 .append('span')
71078                 .attr('class', 'entity-geom-icon')
71079                 .call(svgIcon('', 'pre-text'));
71080
71081             label
71082                 .append('span')
71083                 .attr('class', 'entity-type');
71084
71085             label
71086                 .append('span')
71087                 .attr('class', 'entity-name');
71088
71089             // Update
71090             items = items.merge(enter);
71091
71092             items.selectAll('.entity-geom-icon use')
71093                 .attr('href', function() {
71094                     var entity = this.parentNode.parentNode.__data__;
71095                     return '#icon-' + context.geometry(entity.id);
71096                 });
71097
71098             items.selectAll('.entity-type')
71099                 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
71100
71101             items.selectAll('.entity-name')
71102                 .text(function(entity) { return utilDisplayName(entity); });
71103         }
71104     }
71105
71106     return selectionList;
71107 }
71108
71109 function uiSourceSwitch(context) {
71110     var keys$$1;
71111
71112
71113     function click() {
71114         event.preventDefault();
71115
71116         if (context.history().hasChanges() &&
71117             !window.confirm(t('source_switch.lose_changes'))) return;
71118
71119         var live = select(this)
71120             .classed('live');
71121
71122         context.connection()
71123             .switch(live ? keys$$1[1] : keys$$1[0]);
71124
71125         context.enter(modeBrowse(context));
71126         context.flush();
71127
71128         select(this)
71129             .text(live ? t('source_switch.dev') : t('source_switch.live'))
71130             .classed('live', !live);
71131     }
71132
71133     var sourceSwitch = function(selection$$1) {
71134         selection$$1
71135             .append('a')
71136             .attr('href', '#')
71137             .text(t('source_switch.live'))
71138             .classed('live', true)
71139             .attr('tabindex', -1)
71140             .on('click', click);
71141     };
71142
71143
71144     sourceSwitch.keys = function(_) {
71145         if (!arguments.length) return keys$$1;
71146         keys$$1 = _;
71147         return sourceSwitch;
71148     };
71149
71150
71151     return sourceSwitch;
71152 }
71153
71154 function uiSuccess(context) {
71155     var dispatch$$1 = dispatch('cancel'),
71156         changeset;
71157
71158
71159     function success(selection$$1) {
71160         var header = selection$$1
71161             .append('div')
71162             .attr('class', 'header fillL');
71163
71164         header
71165             .append('button')
71166             .attr('class', 'fr')
71167             .on('click', function() { dispatch$$1.call('cancel'); })
71168             .call(svgIcon('#icon-close'));
71169
71170         header
71171             .append('h3')
71172             .text(t('success.just_edited'));
71173
71174         var body = selection$$1
71175             .append('div')
71176             .attr('class', 'body save-success fillL');
71177
71178         body
71179             .append('p')
71180             .html(t('success.help_html'));
71181
71182         body
71183             .append('a')
71184             .attr('class', 'details')
71185             .attr('target', '_blank')
71186             .attr('tabindex', -1)
71187             .call(svgIcon('#icon-out-link', 'inline'))
71188             .attr('href', t('success.help_link_url'))
71189             .append('span')
71190             .text(t('success.help_link_text'));
71191
71192         var changesetURL = context.connection().changesetURL(changeset.id);
71193
71194
71195         var viewOnOsm = body
71196             .append('a')
71197             .attr('class', 'button col12 osm')
71198             .attr('target', '_blank')
71199             .attr('href', changesetURL);
71200
71201         viewOnOsm
71202             .append('svg')
71203             .attr('class', 'logo logo-osm')
71204             .append('use')
71205             .attr('xlink:href', '#logo-osm');
71206
71207         viewOnOsm
71208             .append('div')
71209             .text(t('success.view_on_osm'));
71210
71211
71212         var message = (changeset.tags.comment || t('success.edited_osm')).substring(0, 130) +
71213             ' ' + context.connection().changesetURL(changeset.id);
71214
71215         var sharing = {
71216             facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
71217             twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
71218             google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
71219         };
71220
71221         body.selectAll('.button.social')
71222             .data(entries(sharing))
71223             .enter()
71224             .append('a')
71225             .attr('class', 'button social col4')
71226             .attr('target', '_blank')
71227             .attr('href', function(d) { return d.value; })
71228             .call(tooltip()
71229                 .title(function(d) { return t('success.' + d.key); })
71230                 .placement('bottom'))
71231             .each(function(d) { select(this).call(svgIcon('#logo-' + d.key, 'social')); });
71232     }
71233
71234
71235     success.changeset = function(_) {
71236         if (!arguments.length) return changeset;
71237         changeset = _;
71238         return success;
71239     };
71240
71241
71242     return utilRebind(success, dispatch$$1, 'on');
71243 }
71244
71245 function coreHistory(context) {
71246     var imageryUsed = ['Bing'],
71247         dispatch$$1 = dispatch('change', 'undone', 'redone'),
71248         lock = utilSessionMutex('lock'),
71249         duration = 150,
71250         checkpoints = {},
71251         stack$$1, index, tree$$1;
71252
71253
71254     // internal _act, accepts list of actions and eased time
71255     function _act(actions, t) {
71256         actions = Array.prototype.slice.call(actions);
71257
71258         var annotation;
71259
71260         if (!lodash.isFunction(lodash.last(actions))) {
71261             annotation = actions.pop();
71262         }
71263
71264         stack$$1[index].transform = context.projection.transform();
71265         stack$$1[index].selectedIDs = context.selectedIDs();
71266
71267         var graph = stack$$1[index].graph;
71268         for (var i = 0; i < actions.length; i++) {
71269             graph = actions[i](graph, t);
71270         }
71271
71272         return {
71273             graph: graph,
71274             annotation: annotation,
71275             imageryUsed: imageryUsed
71276         };
71277     }
71278
71279
71280     // internal _perform with eased time
71281     function _perform(args, t) {
71282         var previous = stack$$1[index].graph;
71283         stack$$1 = stack$$1.slice(0, index + 1);
71284         stack$$1.push(_act(args, t));
71285         index++;
71286         return change(previous);
71287     }
71288
71289
71290     // internal _replace with eased time
71291     function _replace(args, t) {
71292         var previous = stack$$1[index].graph;
71293         // assert(index == stack.length - 1)
71294         stack$$1[index] = _act(args, t);
71295         return change(previous);
71296     }
71297
71298
71299     // internal _overwrite with eased time
71300     function _overwrite(args, t) {
71301         var previous = stack$$1[index].graph;
71302         if (index > 0) {
71303             index--;
71304             stack$$1.pop();
71305         }
71306         stack$$1 = stack$$1.slice(0, index + 1);
71307         stack$$1.push(_act(args, t));
71308         index++;
71309         return change(previous);
71310     }
71311
71312
71313     // determine diffrence and dispatch a change event
71314     function change(previous) {
71315         var difference = coreDifference(previous, history.graph());
71316         dispatch$$1.call('change', this, difference);
71317         return difference;
71318     }
71319
71320
71321     // iD uses namespaced keys so multiple installations do not conflict
71322     function getKey(n) {
71323         return 'iD_' + window.location.origin + '_' + n;
71324     }
71325
71326
71327     var history = {
71328
71329         graph: function() {
71330             return stack$$1[index].graph;
71331         },
71332
71333
71334         base: function() {
71335             return stack$$1[0].graph;
71336         },
71337
71338
71339         merge: function(entities, extent$$1) {
71340             stack$$1[0].graph.rebase(entities, lodash.map(stack$$1, 'graph'), false);
71341             tree$$1.rebase(entities, false);
71342
71343             dispatch$$1.call('change', this, undefined, extent$$1);
71344         },
71345
71346
71347         perform: function() {
71348             // complete any transition already in progress
71349             select(document).interrupt('history.perform');
71350
71351             var transitionable = false,
71352                 action0 = arguments[0];
71353
71354             if (arguments.length === 1 ||
71355                 arguments.length === 2 && !lodash.isFunction(arguments[1])) {
71356                 transitionable = !!action0.transitionable;
71357             }
71358
71359             if (transitionable) {
71360                 var origArguments = arguments;
71361                 select(document)
71362                     .transition('history.perform')
71363                     .duration(duration)
71364                     .ease(linear$1)
71365                     .tween('history.tween', function() {
71366                         return function(t) {
71367                             if (t < 1) _overwrite([action0], t);
71368                         };
71369                     })
71370                     .on('start', function() {
71371                         _perform([action0], 0);
71372                     })
71373                     .on('end interrupt', function() {
71374                         _overwrite(origArguments, 1);
71375                     });
71376
71377             } else {
71378                 return _perform(arguments);
71379             }
71380         },
71381
71382
71383         replace: function() {
71384             select(document).interrupt('history.perform');
71385             return _replace(arguments, 1);
71386         },
71387
71388
71389         // Same as calling pop and then perform
71390         overwrite: function() {
71391             select(document).interrupt('history.perform');
71392             return _overwrite(arguments, 1);
71393         },
71394
71395
71396         pop: function(n) {
71397             select(document).interrupt('history.perform');
71398
71399             var previous = stack$$1[index].graph;
71400             if (isNaN(+n) || +n < 0) {
71401                 n = 1;
71402             }
71403             while (n-- > 0 && index > 0) {
71404                 index--;
71405                 stack$$1.pop();
71406             }
71407             return change(previous);
71408         },
71409
71410
71411         // Back to the previous annotated state or index = 0.
71412         undo: function() {
71413             select(document).interrupt('history.perform');
71414
71415             var previous = stack$$1[index].graph;
71416             while (index > 0) {
71417                 index--;
71418                 if (stack$$1[index].annotation) break;
71419             }
71420
71421             dispatch$$1.call('undone', this, stack$$1[index]);
71422             return change(previous);
71423         },
71424
71425
71426         // Forward to the next annotated state.
71427         redo: function() {
71428             select(document).interrupt('history.perform');
71429
71430             var previous = stack$$1[index].graph;
71431             var tryIndex = index;
71432             while (tryIndex < stack$$1.length - 1) {
71433                 tryIndex++;
71434                 if (stack$$1[tryIndex].annotation) {
71435                     index = tryIndex;
71436                     dispatch$$1.call('redone', this, stack$$1[index]);
71437                     break;
71438                 }
71439             }
71440
71441             return change(previous);
71442         },
71443
71444
71445         undoAnnotation: function() {
71446             var i = index;
71447             while (i >= 0) {
71448                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
71449                 i--;
71450             }
71451         },
71452
71453
71454         redoAnnotation: function() {
71455             var i = index + 1;
71456             while (i <= stack$$1.length - 1) {
71457                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
71458                 i++;
71459             }
71460         },
71461
71462
71463         intersects: function(extent$$1) {
71464             return tree$$1.intersects(extent$$1, stack$$1[index].graph);
71465         },
71466
71467
71468         difference: function() {
71469             var base = stack$$1[0].graph,
71470                 head = stack$$1[index].graph;
71471             return coreDifference(base, head);
71472         },
71473
71474
71475         changes: function(action) {
71476             var base = stack$$1[0].graph,
71477                 head = stack$$1[index].graph;
71478
71479             if (action) {
71480                 head = action(head);
71481             }
71482
71483             var difference = coreDifference(base, head);
71484
71485             return {
71486                 modified: difference.modified(),
71487                 created: difference.created(),
71488                 deleted: difference.deleted()
71489             };
71490         },
71491
71492
71493         validate: function(changes) {
71494             return lodash(Validations)
71495                 .map(function(fn) { return fn()(changes, stack$$1[index].graph); })
71496                 .flatten()
71497                 .value();
71498         },
71499
71500
71501         hasChanges: function() {
71502             return this.difference().length() > 0;
71503         },
71504
71505
71506         imageryUsed: function(sources) {
71507             if (sources) {
71508                 imageryUsed = sources;
71509                 return history;
71510             } else {
71511                 return lodash(stack$$1.slice(1, index + 1))
71512                     .map('imageryUsed')
71513                     .flatten()
71514                     .uniq()
71515                     .without(undefined, 'Custom')
71516                     .value();
71517             }
71518         },
71519
71520
71521         // save the current history state
71522         checkpoint: function(key) {
71523             checkpoints[key] = {
71524                 stack: lodash.cloneDeep(stack$$1),
71525                 index: index
71526             };
71527             return history;
71528         },
71529
71530
71531         // restore history state to a given checkpoint or reset completely
71532         reset: function(key) {
71533             if (key !== undefined && checkpoints.hasOwnProperty(key)) {
71534                 stack$$1 = lodash.cloneDeep(checkpoints[key].stack);
71535                 index = checkpoints[key].index;
71536             } else {
71537                 stack$$1 = [{graph: coreGraph$$1()}];
71538                 index = 0;
71539                 tree$$1 = coreTree(stack$$1[0].graph);
71540                 checkpoints = {};
71541             }
71542             dispatch$$1.call('change');
71543             return history;
71544         },
71545
71546
71547         toIntroGraph: function() {
71548             var nextId = { n: 0, r: 0, w: 0 },
71549                 permIds = {},
71550                 graph = this.graph(),
71551                 baseEntities = {};
71552
71553             // clone base entities..
71554             lodash.forEach(graph.base().entities, function(entity) {
71555                 var copy = lodash.cloneDeepWith(entity, customizer);
71556                 baseEntities[copy.id] = copy;
71557             });
71558
71559             // replace base entities with head entities..
71560             lodash.forEach(graph.entities, function(entity, id) {
71561                 if (entity) {
71562                     var copy = lodash.cloneDeepWith(entity, customizer);
71563                     baseEntities[copy.id] = copy;
71564                 } else {
71565                     delete baseEntities[id];
71566                 }
71567             });
71568
71569             // swap temporary for permanent ids..
71570             lodash.forEach(baseEntities, function(entity) {
71571                 if (Array.isArray(entity.nodes)) {
71572                     entity.nodes = entity.nodes.map(function(node) {
71573                         return permIds[node] || node;
71574                     });
71575                 }
71576                 if (Array.isArray(entity.members)) {
71577                     entity.members = entity.members.map(function(member) {
71578                         member.id = permIds[member.id] || member.id;
71579                         return member;
71580                     });
71581                 }
71582             });
71583
71584             return JSON.stringify({ dataIntroGraph: baseEntities });
71585
71586
71587             function customizer(src) {
71588                 var copy = lodash.omit(lodash.cloneDeep(src), ['type', 'user', 'v', 'version', 'visible']);
71589                 if (lodash.isEmpty(copy.tags)) {
71590                     delete copy.tags;
71591                 }
71592
71593                 if (Array.isArray(copy.loc)) {
71594                     copy.loc[0] = +copy.loc[0].toFixed(6);
71595                     copy.loc[1] = +copy.loc[1].toFixed(6);
71596                 }
71597
71598                 var match = src.id.match(/([nrw])-\d*/);  // temporary id
71599                 if (match !== null) {
71600                     var nrw = match[1], permId;
71601                     do { permId = nrw + (++nextId[nrw]); }
71602                     while (baseEntities.hasOwnProperty(permId));
71603
71604                     copy.id = permIds[src.id] = permId;
71605                 }
71606                 return copy;
71607             }
71608         },
71609
71610
71611         toJSON: function() {
71612             if (!this.hasChanges()) return;
71613
71614             var allEntities = {},
71615                 baseEntities = {},
71616                 base = stack$$1[0];
71617
71618             var s = stack$$1.map(function(i) {
71619                 var modified = [], deleted = [];
71620
71621                 lodash.forEach(i.graph.entities, function(entity, id) {
71622                     if (entity) {
71623                         var key = osmEntity$$1.key(entity);
71624                         allEntities[key] = entity;
71625                         modified.push(key);
71626                     } else {
71627                         deleted.push(id);
71628                     }
71629
71630                     // make sure that the originals of changed or deleted entities get merged
71631                     // into the base of the stack after restoring the data from JSON.
71632                     if (id in base.graph.entities) {
71633                         baseEntities[id] = base.graph.entities[id];
71634                     }
71635                     // get originals of parent entities too
71636                     lodash.forEach(base.graph._parentWays[id], function(parentId) {
71637                         if (parentId in base.graph.entities) {
71638                             baseEntities[parentId] = base.graph.entities[parentId];
71639                         }
71640                     });
71641                 });
71642
71643                 var x = {};
71644
71645                 if (modified.length) x.modified = modified;
71646                 if (deleted.length) x.deleted = deleted;
71647                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
71648                 if (i.annotation) x.annotation = i.annotation;
71649
71650                 return x;
71651             });
71652
71653             return JSON.stringify({
71654                 version: 3,
71655                 entities: lodash.values(allEntities),
71656                 baseEntities: lodash.values(baseEntities),
71657                 stack: s,
71658                 nextIDs: osmEntity$$1.id.next,
71659                 index: index
71660             });
71661         },
71662
71663
71664         fromJSON: function(json$$1, loadChildNodes) {
71665             var h = JSON.parse(json$$1),
71666                 loadComplete = true;
71667
71668             osmEntity$$1.id.next = h.nextIDs;
71669             index = h.index;
71670
71671             if (h.version === 2 || h.version === 3) {
71672                 var allEntities = {};
71673
71674                 h.entities.forEach(function(entity) {
71675                     allEntities[osmEntity$$1.key(entity)] = osmEntity$$1(entity);
71676                 });
71677
71678                 if (h.version === 3) {
71679                     // This merges originals for changed entities into the base of
71680                     // the stack even if the current stack doesn't have them (for
71681                     // example when iD has been restarted in a different region)
71682                     var baseEntities = h.baseEntities.map(function(d) { return osmEntity$$1(d); });
71683                     stack$$1[0].graph.rebase(baseEntities, lodash.map(stack$$1, 'graph'), true);
71684                     tree$$1.rebase(baseEntities, true);
71685
71686                     // When we restore a modified way, we also need to fetch any missing
71687                     // childnodes that would normally have been downloaded with it.. #2142
71688                     if (loadChildNodes) {
71689                         var missing =  lodash(baseEntities)
71690                                 .filter({ type: 'way' })
71691                                 .map('nodes')
71692                                 .flatten()
71693                                 .uniq()
71694                                 .reject(function(n) { return stack$$1[0].graph.hasEntity(n); })
71695                                 .value();
71696
71697                         if (!lodash.isEmpty(missing)) {
71698                             loadComplete = false;
71699                             context.redrawEnable(false);
71700
71701                             var loading = uiLoading(context).blocking(true);
71702                             context.container().call(loading);
71703
71704                             var childNodesLoaded = function(err, result) {
71705                                 if (!err) {
71706                                     var visible = lodash.groupBy(result.data, 'visible');
71707                                     if (!lodash.isEmpty(visible.true)) {
71708                                         missing = lodash.difference(missing, lodash.map(visible.true, 'id'));
71709                                         stack$$1[0].graph.rebase(visible.true, lodash.map(stack$$1, 'graph'), true);
71710                                         tree$$1.rebase(visible.true, true);
71711                                     }
71712
71713                                     // fetch older versions of nodes that were deleted..
71714                                     lodash.each(visible.false, function(entity) {
71715                                         context.connection()
71716                                             .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
71717                                     });
71718                                 }
71719
71720                                 if (err || lodash.isEmpty(missing)) {
71721                                     loading.close();
71722                                     context.redrawEnable(true);
71723                                     dispatch$$1.call('change');
71724                                 }
71725                             };
71726
71727                             context.connection().loadMultiple(missing, childNodesLoaded);
71728                         }
71729                     }
71730                 }
71731
71732                 stack$$1 = h.stack.map(function(d) {
71733                     var entities = {}, entity;
71734
71735                     if (d.modified) {
71736                         d.modified.forEach(function(key) {
71737                             entity = allEntities[key];
71738                             entities[entity.id] = entity;
71739                         });
71740                     }
71741
71742                     if (d.deleted) {
71743                         d.deleted.forEach(function(id) {
71744                             entities[id] = undefined;
71745                         });
71746                     }
71747
71748                     return {
71749                         graph: coreGraph$$1(stack$$1[0].graph).load(entities),
71750                         annotation: d.annotation,
71751                         imageryUsed: d.imageryUsed
71752                     };
71753                 });
71754
71755             } else { // original version
71756                 stack$$1 = h.stack.map(function(d) {
71757                     var entities = {};
71758
71759                     for (var i in d.entities) {
71760                         var entity = d.entities[i];
71761                         entities[i] = entity === 'undefined' ? undefined : osmEntity$$1(entity);
71762                     }
71763
71764                     d.graph = coreGraph$$1(stack$$1[0].graph).load(entities);
71765                     return d;
71766                 });
71767             }
71768
71769             if (loadComplete) {
71770                 dispatch$$1.call('change');
71771             }
71772
71773             return history;
71774         },
71775
71776
71777         save: function() {
71778             if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
71779             return history;
71780         },
71781
71782
71783         clearSaved: function() {
71784             context.debouncedSave.cancel();
71785             if (lock.locked()) context.storage(getKey('saved_history'), null);
71786             return history;
71787         },
71788
71789
71790         lock: function() {
71791             return lock.lock();
71792         },
71793
71794
71795         unlock: function() {
71796             lock.unlock();
71797         },
71798
71799
71800         // is iD not open in another window and it detects that
71801         // there's a history stored in localStorage that's recoverable?
71802         restorableChanges: function() {
71803             return lock.locked() && !!context.storage(getKey('saved_history'));
71804         },
71805
71806
71807         // load history from a version stored in localStorage
71808         restore: function() {
71809             if (!lock.locked()) return;
71810
71811             var json$$1 = context.storage(getKey('saved_history'));
71812             if (json$$1) history.fromJSON(json$$1, true);
71813         },
71814
71815
71816         _getKey: getKey
71817
71818     };
71819
71820
71821     history.reset();
71822
71823     return utilRebind(history, dispatch$$1, 'on');
71824 }
71825
71826 function presetCollection(collection) {
71827     var maxSearchResults = 50,
71828         maxSuggestionResults = 10;
71829
71830     var presets = {
71831
71832         collection: collection,
71833
71834
71835         item: function(id) {
71836             return lodash.find(this.collection, function(d) {
71837                 return d.id === id;
71838             });
71839         },
71840
71841
71842         matchGeometry: function(geometry) {
71843             return presetCollection(this.collection.filter(function(d) {
71844                 return d.matchGeometry(geometry);
71845             }));
71846         },
71847
71848
71849         search: function(value, geometry) {
71850             if (!value) return this;
71851
71852             function leading(a) {
71853                 var index = a.indexOf(value);
71854                 return index === 0 || a[index - 1] === ' ';
71855             }
71856
71857             function suggestionName(name) {
71858                 var nameArray = name.split(' - ');
71859                 if (nameArray.length > 1) {
71860                     name = nameArray.slice(0, nameArray.length - 1).join(' - ');
71861                 }
71862                 return name.toLowerCase();
71863             }
71864
71865
71866             value = value.toLowerCase();
71867
71868             var searchable = lodash.filter(this.collection, function(a) {
71869                     return a.searchable !== false && a.suggestion !== true;
71870                 }),
71871                 suggestions = lodash.filter(this.collection, function(a) {
71872                     return a.suggestion === true;
71873                 });
71874
71875
71876             // matches value to preset.name
71877             var leading_name = lodash.filter(searchable, function(a) {
71878                     return leading(a.name().toLowerCase());
71879                 }).sort(function(a, b) {
71880                     var i;
71881                     i = b.originalScore - a.originalScore;
71882                     if (i !== 0) return i;
71883
71884                     i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
71885                     if (i !== 0) return i;
71886
71887                     return a.name().length - b.name().length;
71888                 });
71889
71890             // matches value to preset.terms values
71891             var leading_terms = lodash.filter(searchable, function(a) {
71892                     return lodash.some(a.terms() || [], leading);
71893                 });
71894
71895             // matches value to preset.tags values
71896             var leading_tag_values = lodash.filter(searchable, function(a) {
71897                     return lodash.some(lodash.without(lodash.values(a.tags || {}), '*'), leading);
71898                 });
71899
71900
71901             // finds close matches to value in preset.name
71902             var similar_name = searchable.map(function(a) {
71903                     return {
71904                         preset: a,
71905                         dist: utilEditDistance(value, a.name())
71906                     };
71907                 }).filter(function(a) {
71908                     return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
71909                 }).sort(function(a, b) {
71910                     return a.dist - b.dist;
71911                 }).map(function(a) {
71912                     return a.preset;
71913                 });
71914
71915             // finds close matches to value in preset.terms
71916             var similar_terms = lodash.filter(searchable, function(a) {
71917                     return lodash.some(a.terms() || [], function(b) {
71918                         return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
71919                     });
71920                 });
71921
71922             var leading_suggestions = lodash.filter(suggestions, function(a) {
71923                     return leading(suggestionName(a.name()));
71924                 }).sort(function(a, b) {
71925                     a = suggestionName(a.name());
71926                     b = suggestionName(b.name());
71927                     var i = a.indexOf(value) - b.indexOf(value);
71928                     if (i === 0) return a.length - b.length;
71929                     else return i;
71930                 });
71931
71932             var similar_suggestions = suggestions.map(function(a) {
71933                     return {
71934                         preset: a,
71935                         dist: utilEditDistance(value, suggestionName(a.name()))
71936                     };
71937                 }).filter(function(a) {
71938                     return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
71939                 }).sort(function(a, b) {
71940                     return a.dist - b.dist;
71941                 }).map(function(a) {
71942                     return a.preset;
71943                 });
71944
71945             var other = presets.item(geometry);
71946
71947             var results = leading_name.concat(
71948                     leading_terms,
71949                     leading_tag_values,
71950                     leading_suggestions.slice(0, maxSuggestionResults + 5),
71951                     similar_name,
71952                     similar_terms,
71953                     similar_suggestions.slice(0, maxSuggestionResults)
71954                 ).slice(0, maxSearchResults - 1);
71955
71956             return presetCollection(lodash.uniq(results.concat(other)));
71957         }
71958     };
71959
71960
71961     return presets;
71962 }
71963
71964 function presetCategory(id, category, all) {
71965     category = lodash.clone(category);
71966
71967     category.id = id;
71968
71969
71970     category.members = presetCollection(category.members.map(function(id) {
71971         return all.item(id);
71972     }));
71973
71974
71975     category.matchGeometry = function(geometry) {
71976         return category.geometry.indexOf(geometry) >= 0;
71977     };
71978
71979
71980     category.matchScore = function() {
71981         return -1;
71982     };
71983
71984
71985     category.name = function() {
71986         return t('presets.categories.' + id + '.name', {'default': id});
71987     };
71988
71989
71990     category.terms = function() {
71991         return [];
71992     };
71993
71994
71995     return category;
71996 }
71997
71998 function presetField(id, field) {
71999     field = lodash.clone(field);
72000
72001     field.id = id;
72002
72003
72004     field.matchGeometry = function(geometry) {
72005         return !field.geometry || field.geometry === geometry;
72006     };
72007
72008
72009     field.t = function(scope, options) {
72010         return t('presets.fields.' + id + '.' + scope, options);
72011     };
72012
72013
72014     field.label = function() {
72015         return field.t('label', {'default': id});
72016     };
72017
72018
72019     var placeholder = field.placeholder;
72020     field.placeholder = function() {
72021         return field.t('placeholder', {'default': placeholder});
72022     };
72023
72024
72025     return field;
72026 }
72027
72028 function presetPreset(id, preset, fields) {
72029     preset = lodash.clone(preset);
72030
72031     preset.id = id;
72032     preset.fields = (preset.fields || []).map(getFields);
72033     preset.geometry = (preset.geometry || []);
72034
72035
72036     function getFields(f) {
72037         return fields[f];
72038     }
72039
72040
72041     preset.matchGeometry = function(geometry) {
72042         return preset.geometry.indexOf(geometry) >= 0;
72043     };
72044
72045
72046     preset.originalScore = preset.matchScore || 1;
72047
72048
72049     preset.matchScore = function(entity) {
72050         var tags = preset.tags,
72051             score = 0;
72052
72053         for (var t$$1 in tags) {
72054             if (entity.tags[t$$1] === tags[t$$1]) {
72055                 score += preset.originalScore;
72056             } else if (tags[t$$1] === '*' && t$$1 in entity.tags) {
72057                 score += preset.originalScore / 2;
72058             } else {
72059                 return -1;
72060             }
72061         }
72062
72063         return score;
72064     };
72065
72066
72067     preset.t = function(scope, options) {
72068         return t('presets.presets.' + id + '.' + scope, options);
72069     };
72070
72071
72072     var name = preset.name || '';
72073     preset.name = function() {
72074         if (preset.suggestion) {
72075             id = id.split('/');
72076             id = id[0] + '/' + id[1];
72077             return name + ' - ' + t('presets.presets.' + id + '.name');
72078         }
72079         return preset.t('name', {'default': name});
72080     };
72081
72082
72083     preset.terms = function() {
72084         return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
72085     };
72086
72087
72088     preset.isFallback = function() {
72089         var tagCount = Object.keys(preset.tags).length;
72090         return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
72091     };
72092
72093
72094     var reference = preset.reference || {};
72095     preset.reference = function(geometry) {
72096         var key = reference.key || Object.keys(preset.tags)[0],
72097             value = reference.value || preset.tags[key];
72098
72099         if (geometry === 'relation' && key === 'type') {
72100             if (value in preset.tags) {
72101                 key = value;
72102                 value = preset.tags[key];
72103             } else {
72104                 return { rtype: value };
72105             }
72106         }
72107
72108         if (value === '*') {
72109             return { key: key };
72110         } else {
72111             return { key: key, value: value };
72112         }
72113     };
72114
72115
72116     var removeTags = preset.removeTags || preset.tags;
72117     preset.removeTags = function(tags, geometry) {
72118         tags = lodash.omit(tags, lodash.keys(removeTags));
72119
72120         for (var f in preset.fields) {
72121             var field = preset.fields[f];
72122             if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
72123                 delete tags[field.key];
72124             }
72125         }
72126
72127         delete tags.area;
72128         return tags;
72129     };
72130
72131
72132     var applyTags = preset.addTags || preset.tags;
72133     preset.applyTags = function(tags, geometry) {
72134         var k;
72135
72136         tags = lodash.clone(tags);
72137
72138         for (k in applyTags) {
72139             if (applyTags[k] === '*') {
72140                 tags[k] = 'yes';
72141             } else {
72142                 tags[k] = applyTags[k];
72143             }
72144         }
72145
72146         // Add area=yes if necessary.
72147         // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
72148         // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
72149         // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
72150         if (geometry === 'area') {
72151             var needsAreaTag = true;
72152             if (preset.geometry.indexOf('line') === -1) {
72153                 for (k in applyTags) {
72154                     if (k in areaKeys) {
72155                         needsAreaTag = false;
72156                         break;
72157                     }
72158                 }
72159             }
72160             if (needsAreaTag) {
72161                 tags.area = 'yes';
72162             }
72163         }
72164
72165         for (var f in preset.fields) {
72166             var field = preset.fields[f];
72167             if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
72168                 tags[field.key] = field.default;
72169             }
72170         }
72171
72172         return tags;
72173     };
72174
72175
72176     return preset;
72177 }
72178
72179 function presetIndex() {
72180     // a presetCollection with methods for
72181     // loading new data and returning defaults
72182
72183     var all = presetCollection([]),
72184         defaults = { area: all, line: all, point: all, vertex: all, relation: all },
72185         fields = {},
72186         universal = [],
72187         recent = presetCollection([]);
72188
72189     // Index of presets by (geometry, tag key).
72190     var index = {
72191         point: {},
72192         vertex: {},
72193         line: {},
72194         area: {},
72195         relation: {}
72196     };
72197
72198     all.match = function(entity, resolver) {
72199         var geometry = entity.geometry(resolver);
72200
72201         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
72202         if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
72203             geometry = 'point';
72204         }
72205
72206         var geometryMatches = index[geometry],
72207             best = -1,
72208             match;
72209
72210         for (var k in entity.tags) {
72211             var keyMatches = geometryMatches[k];
72212             if (!keyMatches) continue;
72213
72214             for (var i = 0; i < keyMatches.length; i++) {
72215                 var score = keyMatches[i].matchScore(entity);
72216                 if (score > best) {
72217                     best = score;
72218                     match = keyMatches[i];
72219                 }
72220             }
72221         }
72222
72223         return match || all.item(geometry);
72224     };
72225
72226
72227     // Because of the open nature of tagging, iD will never have a complete
72228     // list of tags used in OSM, so we want it to have logic like "assume
72229     // that a closed way with an amenity tag is an area, unless the amenity
72230     // is one of these specific types". This function computes a structure
72231     // that allows testing of such conditions, based on the presets designated
72232     // as as supporting (or not supporting) the area geometry.
72233     //
72234     // The returned object L is a whitelist/blacklist of tags. A closed way
72235     // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
72236     // (see `Way#isArea()`). In other words, the keys of L form the whitelist,
72237     // and the subkeys form the blacklist.
72238     all.areaKeys = function() {
72239         var areaKeys = {},
72240             ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],  // probably a line..
72241             presets = lodash.reject(all.collection, 'suggestion');
72242
72243         // whitelist
72244         presets.forEach(function(d) {
72245             for (var key in d.tags) break;
72246             if (!key) return;
72247             if (ignore.indexOf(key) !== -1) return;
72248
72249             if (d.geometry.indexOf('area') !== -1) {    // probably an area..
72250                 areaKeys[key] = areaKeys[key] || {};
72251             }
72252         });
72253
72254         // blacklist
72255         presets.forEach(function(d) {
72256             for (var key in d.tags) break;
72257             if (!key) return;
72258             if (ignore.indexOf(key) !== -1) return;
72259
72260             var value = d.tags[key];
72261             if (key in areaKeys &&                      // probably an area...
72262                 d.geometry.indexOf('line') !== -1 &&    // but sometimes a line
72263                 value !== '*') {
72264                 areaKeys[key][value] = true;
72265             }
72266         });
72267
72268         return areaKeys;
72269     };
72270
72271
72272     all.init = function() {
72273         var d = data.presets;
72274
72275         all.collection = [];
72276         recent.collection = [];
72277         fields = {};
72278         universal = [];
72279         index = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
72280
72281         if (d.fields) {
72282             lodash.forEach(d.fields, function(d, id) {
72283                 fields[id] = presetField(id, d);
72284                 if (d.universal) universal.push(fields[id]);
72285             });
72286         }
72287
72288         if (d.presets) {
72289             lodash.forEach(d.presets, function(d, id) {
72290                 all.collection.push(presetPreset(id, d, fields));
72291             });
72292         }
72293
72294         if (d.categories) {
72295             lodash.forEach(d.categories, function(d, id) {
72296                 all.collection.push(presetCategory(id, d, all));
72297             });
72298         }
72299
72300         if (d.defaults) {
72301             var getItem = lodash.bind(all.item, all);
72302             defaults = {
72303                 area: presetCollection(d.defaults.area.map(getItem)),
72304                 line: presetCollection(d.defaults.line.map(getItem)),
72305                 point: presetCollection(d.defaults.point.map(getItem)),
72306                 vertex: presetCollection(d.defaults.vertex.map(getItem)),
72307                 relation: presetCollection(d.defaults.relation.map(getItem))
72308             };
72309         }
72310
72311         for (var i = 0; i < all.collection.length; i++) {
72312             var preset = all.collection[i],
72313                 geometry = preset.geometry;
72314
72315             for (var j = 0; j < geometry.length; j++) {
72316                 var g = index[geometry[j]];
72317                 for (var k in preset.tags) {
72318                     (g[k] = g[k] || []).push(preset);
72319                 }
72320             }
72321         }
72322
72323         return all;
72324     };
72325
72326     all.field = function(id) {
72327         return fields[id];
72328     };
72329
72330     all.universal = function() {
72331         return universal;
72332     };
72333
72334     all.defaults = function(geometry, n) {
72335         var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
72336             def = lodash.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
72337         return presetCollection(lodash.uniq(rec.concat(def).concat(all.item(geometry))));
72338     };
72339
72340     all.choose = function(preset) {
72341         if (!preset.isFallback()) {
72342             recent = presetCollection(lodash.uniq([preset].concat(recent.collection)));
72343         }
72344         return all;
72345     };
72346
72347     return all;
72348 }
72349
72350 var areaKeys = {};
72351
72352 function setAreaKeys(value) {
72353     areaKeys = value;
72354 }
72355
72356
72357 function coreContext() {
72358
72359     // create a special translation that contains the keys in place of the strings
72360     var tkeys = lodash.cloneDeep(en);
72361     var parents = [];
72362
72363     function traverser(v, k, obj) {
72364         parents.push(k);
72365         if (lodash.isObject(v)) {
72366             lodash.forOwn(v, traverser);
72367         } else if (lodash.isString(v)) {
72368             obj[k] = parents.join('.');
72369         }
72370         parents.pop();
72371     }
72372
72373     lodash.forOwn(tkeys, traverser);
72374     addTranslation('_tkeys_', tkeys);
72375
72376     addTranslation('en', en);
72377     setLocale('en');
72378
72379     var dispatch$$1 = dispatch('enter', 'exit', 'change'),
72380         context = {};
72381
72382     // https://github.com/openstreetmap/iD/issues/772
72383     // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
72384     var storage;
72385     try { storage = localStorage; } catch (e) {}  // eslint-disable-line no-empty
72386     storage = storage || (function() {
72387         var s = {};
72388         return {
72389             getItem: function(k) { return s[k]; },
72390             setItem: function(k, v) { s[k] = v; },
72391             removeItem: function(k) { delete s[k]; }
72392         };
72393     })();
72394
72395     context.storage = function(k, v) {
72396         try {
72397             if (arguments.length === 1) return storage.getItem(k);
72398             else if (v === null) storage.removeItem(k);
72399             else storage.setItem(k, v);
72400         } catch (e) {
72401             // localstorage quota exceeded
72402             /* eslint-disable no-console */
72403             if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
72404             /* eslint-enable no-console */
72405         }
72406     };
72407
72408
72409     /* Straight accessors. Avoid using these if you can. */
72410     var ui, connection, history;
72411     context.ui = function() { return ui; };
72412     context.connection = function() { return connection; };
72413     context.history = function() { return history; };
72414
72415
72416     /* Connection */
72417     function entitiesLoaded(err, result) {
72418         if (!err) history.merge(result.data, result.extent);
72419     }
72420
72421     context.preauth = function(options) {
72422         connection.switch(options);
72423         return context;
72424     };
72425
72426     context.loadTiles = function(projection, dimensions, callback) {
72427         function done(err, result) {
72428             entitiesLoaded(err, result);
72429             if (callback) callback(err, result);
72430         }
72431         connection.loadTiles(projection, dimensions, done);
72432     };
72433
72434     context.loadEntity = function(id, callback) {
72435         function done(err, result) {
72436             entitiesLoaded(err, result);
72437             if (callback) callback(err, result);
72438         }
72439         connection.loadEntity(id, done);
72440     };
72441
72442     context.zoomToEntity = function(id, zoomTo) {
72443         if (zoomTo !== false) {
72444             this.loadEntity(id, function(err, result) {
72445                 if (err) return;
72446                 var entity = lodash.find(result.data, function(e) { return e.id === id; });
72447                 if (entity) { map$$1.zoomTo(entity); }
72448             });
72449         }
72450
72451         map$$1.on('drawn.zoomToEntity', function() {
72452             if (!context.hasEntity(id)) return;
72453             map$$1.on('drawn.zoomToEntity', null);
72454             context.on('enter.zoomToEntity', null);
72455             context.enter(modeSelect(context, [id]));
72456         });
72457
72458         context.on('enter.zoomToEntity', function() {
72459             if (mode.id !== 'browse') {
72460                 map$$1.on('drawn.zoomToEntity', null);
72461                 context.on('enter.zoomToEntity', null);
72462             }
72463         });
72464     };
72465
72466     var minEditableZoom = 16;
72467     context.minEditableZoom = function(_) {
72468         if (!arguments.length) return minEditableZoom;
72469         minEditableZoom = _;
72470         connection.tileZoom(_);
72471         return context;
72472     };
72473
72474
72475     /* History */
72476     var inIntro = false;
72477     context.inIntro = function(_) {
72478         if (!arguments.length) return inIntro;
72479         inIntro = _;
72480         return context;
72481     };
72482
72483     context.save = function() {
72484         // no history save, no message onbeforeunload
72485         if (inIntro || select('.modal').size()) return;
72486
72487         var canSave;
72488         if (mode && mode.id === 'save') {
72489             canSave = false;
72490         } else {
72491             canSave = context.selectedIDs().every(function(id) {
72492                 var entity = context.hasEntity(id);
72493                 return entity && !entity.isDegenerate();
72494             });
72495         }
72496
72497         if (canSave) {
72498             history.save();
72499         }
72500         if (history.hasChanges()) {
72501             return t('save.unsaved_changes');
72502         }
72503     };
72504
72505
72506     /* Graph */
72507     context.hasEntity = function(id) {
72508         return history.graph().hasEntity(id);
72509     };
72510     context.entity = function(id) {
72511         return history.graph().entity(id);
72512     };
72513     context.childNodes = function(way) {
72514         return history.graph().childNodes(way);
72515     };
72516     context.geometry = function(id) {
72517         return context.entity(id).geometry(history.graph());
72518     };
72519
72520
72521     /* Modes */
72522     var mode;
72523     context.mode = function() {
72524         return mode;
72525     };
72526     context.enter = function(newMode) {
72527         if (mode) {
72528             mode.exit();
72529             dispatch$$1.call('exit', this, mode);
72530         }
72531
72532         mode = newMode;
72533         mode.enter();
72534         dispatch$$1.call('enter', this, mode);
72535     };
72536
72537     context.selectedIDs = function() {
72538         if (mode && mode.selectedIDs) {
72539             return mode.selectedIDs();
72540         } else {
72541             return [];
72542         }
72543     };
72544
72545
72546     /* Behaviors */
72547     context.install = function(behavior) {
72548         context.surface().call(behavior);
72549     };
72550     context.uninstall = function(behavior) {
72551         context.surface().call(behavior.off);
72552     };
72553
72554
72555     /* Copy/Paste */
72556     var copyIDs = [], copyGraph;
72557     context.copyGraph = function() { return copyGraph; };
72558     context.copyIDs = function(_) {
72559         if (!arguments.length) return copyIDs;
72560         copyIDs = _;
72561         copyGraph = history.graph();
72562         return context;
72563     };
72564
72565
72566     /* Background */
72567     var background;
72568     context.background = function() { return background; };
72569
72570
72571     /* Features */
72572     var features;
72573     context.features = function() { return features; };
72574     context.hasHiddenConnections = function(id) {
72575         var graph = history.graph(),
72576             entity = graph.entity(id);
72577         return features.hasHiddenConnections(entity, graph);
72578     };
72579
72580
72581     /* Presets */
72582     var presets;
72583     context.presets = function() { return presets; };
72584
72585
72586     /* Map */
72587     var map$$1;
72588     context.map = function() { return map$$1; };
72589     context.layers = function() { return map$$1.layers; };
72590     context.surface = function() { return map$$1.surface; };
72591     context.editable = function() { return map$$1.editable(); };
72592     context.surfaceRect = function() {
72593         return map$$1.surface.node().getBoundingClientRect();
72594     };
72595
72596
72597     /* Debug */
72598     var debugFlags = {
72599         tile: false,
72600         collision: false,
72601         imagery: false,
72602         imperial: false,
72603         driveLeft: false
72604     };
72605     context.debugFlags = function() {
72606         return debugFlags;
72607     };
72608     context.setDebug = function(flag, val) {
72609         if (arguments.length === 1) val = true;
72610         debugFlags[flag] = val;
72611         dispatch$$1.call('change');
72612         return context;
72613     };
72614     context.getDebug = function(flag) {
72615         return flag && debugFlags[flag];
72616     };
72617
72618
72619     /* Container */
72620     var container = select(document.body);
72621     context.container = function(_) {
72622         if (!arguments.length) return container;
72623         container = _;
72624         container.classed('id-container', true);
72625         return context;
72626     };
72627     var embed;
72628     context.embed = function(_) {
72629         if (!arguments.length) return embed;
72630         embed = _;
72631         return context;
72632     };
72633
72634
72635     /* Assets */
72636     var assetPath = '';
72637     context.assetPath = function(_) {
72638         if (!arguments.length) return assetPath;
72639         assetPath = _;
72640         return context;
72641     };
72642
72643     var assetMap = {};
72644     context.assetMap = function(_) {
72645         if (!arguments.length) return assetMap;
72646         assetMap = _;
72647         return context;
72648     };
72649
72650     context.asset = function(_) {
72651         var filename = assetPath + _;
72652         return assetMap[filename] || filename;
72653     };
72654
72655     context.imagePath = function(_) {
72656         return context.asset('img/' + _);
72657     };
72658
72659
72660     /* locales */
72661     // `locale` variable contains a "requested locale".
72662     // It won't become the `currentLocale` until after loadLocale() is called.
72663     var locale, localePath;
72664
72665     context.locale = function(loc, path$$1) {
72666         if (!arguments.length) return currentLocale;
72667         locale = loc;
72668         localePath = path$$1;
72669         return context;
72670     };
72671
72672     context.loadLocale = function(callback) {
72673         if (locale && locale !== 'en' && dataLocales.hasOwnProperty(locale)) {
72674             localePath = localePath || context.asset('locales/' + locale + '.json');
72675             json(localePath, function(err, result) {
72676                 if (!err) {
72677                     addTranslation(locale, result[locale]);
72678                     setLocale(locale);
72679                     utilDetect(true);
72680                 }
72681                 if (callback) {
72682                     callback(err);
72683                 }
72684             });
72685         } else {
72686             if (locale) {
72687                 setLocale(locale);
72688                 utilDetect(true);
72689             }
72690             if (callback) {
72691                 callback();
72692             }
72693         }
72694     };
72695
72696
72697     /* reset (aka flush) */
72698     context.reset = context.flush = function() {
72699         context.debouncedSave.cancel();
72700         lodash.each(services, function(service) {
72701             if (service && typeof service.reset === 'function') {
72702                 service.reset(context);
72703             }
72704         });
72705         features.reset();
72706         history.reset();
72707         return context;
72708     };
72709
72710
72711     /* Init */
72712     context.version = '2.2.0';
72713
72714     context.projection = geoRawMercator();
72715     context.curtainProjection = geoRawMercator();
72716
72717     locale = utilDetect().locale;
72718     if (locale && !dataLocales.hasOwnProperty(locale)) {
72719         locale = locale.split('-')[0];
72720     }
72721
72722     history = coreHistory(context);
72723     context.graph = history.graph;
72724     context.changes = history.changes;
72725     context.intersects = history.intersects;
72726
72727     // Debounce save, since it's a synchronous localStorage write,
72728     // and history changes can happen frequently (e.g. when dragging).
72729     context.debouncedSave = lodash.debounce(context.save, 350);
72730     function withDebouncedSave(fn) {
72731         return function() {
72732             var result = fn.apply(history, arguments);
72733             context.debouncedSave();
72734             return result;
72735         };
72736     }
72737
72738     context.perform = withDebouncedSave(history.perform);
72739     context.replace = withDebouncedSave(history.replace);
72740     context.pop = withDebouncedSave(history.pop);
72741     context.overwrite = withDebouncedSave(history.overwrite);
72742     context.undo = withDebouncedSave(history.undo);
72743     context.redo = withDebouncedSave(history.redo);
72744
72745     ui = uiInit(context);
72746
72747     connection = services.osm;
72748     background = rendererBackground(context);
72749     features = rendererFeatures(context);
72750     presets = presetIndex();
72751
72752     map$$1 = rendererMap(context);
72753     context.mouse = map$$1.mouse;
72754     context.extent = map$$1.extent;
72755     context.pan = map$$1.pan;
72756     context.zoomIn = map$$1.zoomIn;
72757     context.zoomOut = map$$1.zoomOut;
72758     context.zoomInFurther = map$$1.zoomInFurther;
72759     context.zoomOutFurther = map$$1.zoomOutFurther;
72760     context.redrawEnable = map$$1.redrawEnable;
72761
72762     lodash.each(services, function(service) {
72763         if (service && typeof service.init === 'function') {
72764             service.init(context);
72765         }
72766     });
72767
72768     background.init();
72769     presets.init();
72770     areaKeys = presets.areaKeys();
72771
72772
72773     return utilRebind(context, dispatch$$1, 'on');
72774 }
72775
72776 function osmWay() {
72777     if (!(this instanceof osmWay)) {
72778         return (new osmWay()).initialize(arguments);
72779     } else if (arguments.length) {
72780         this.initialize(arguments);
72781     }
72782 }
72783
72784
72785 osmEntity$$1.way = osmWay;
72786
72787 osmWay.prototype = Object.create(osmEntity$$1.prototype);
72788
72789
72790 lodash.extend(osmWay.prototype, {
72791     type: 'way',
72792     nodes: [],
72793
72794
72795     copy: function(resolver, copies) {
72796         if (copies[this.id])
72797             return copies[this.id];
72798
72799         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
72800
72801         var nodes = this.nodes.map(function(id) {
72802             return resolver.entity(id).copy(resolver, copies).id;
72803         });
72804
72805         copy = copy.update({ nodes: nodes });
72806         copies[this.id] = copy;
72807
72808         return copy;
72809     },
72810
72811
72812     extent: function(resolver) {
72813         return resolver.transient(this, 'extent', function() {
72814             var extent$$1 = geoExtent$$1();
72815             for (var i = 0; i < this.nodes.length; i++) {
72816                 var node = resolver.hasEntity(this.nodes[i]);
72817                 if (node) {
72818                     extent$$1._extend(node.extent());
72819                 }
72820             }
72821             return extent$$1;
72822         });
72823     },
72824
72825
72826     first: function() {
72827         return this.nodes[0];
72828     },
72829
72830
72831     last: function() {
72832         return this.nodes[this.nodes.length - 1];
72833     },
72834
72835
72836     contains: function(node) {
72837         return this.nodes.indexOf(node) >= 0;
72838     },
72839
72840
72841     affix: function(node) {
72842         if (this.nodes[0] === node) return 'prefix';
72843         if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
72844     },
72845
72846
72847     layer: function() {
72848         // explicit layer tag, clamp between -10, 10..
72849         if (isFinite(this.tags.layer)) {
72850             return Math.max(-10, Math.min(+(this.tags.layer), 10));
72851         }
72852
72853         // implied layer tag..
72854         if (this.tags.location === 'overground') return 1;
72855         if (this.tags.location === 'underground') return -1;
72856         if (this.tags.location === 'underwater') return -10;
72857
72858         if (this.tags.power === 'line') return 10;
72859         if (this.tags.power === 'minor_line') return 10;
72860         if (this.tags.aerialway) return 10;
72861         if (this.tags.bridge) return 1;
72862         if (this.tags.cutting) return -1;
72863         if (this.tags.tunnel) return -1;
72864         if (this.tags.waterway) return -1;
72865         if (this.tags.man_made === 'pipeline') return -10;
72866         if (this.tags.boundary) return -10;
72867         return 0;
72868     },
72869
72870
72871     isOneWay: function() {
72872         // explicit oneway tag..
72873         if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
72874         if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
72875
72876         // implied oneway tag..
72877         for (var key in this.tags) {
72878             if (key in osmOneWayTags && (this.tags[key] in osmOneWayTags[key]))
72879                 return true;
72880         }
72881         return false;
72882     },
72883
72884
72885     lanes: function() {
72886         return osmLanes(this);
72887     },
72888
72889
72890     isClosed: function() {
72891         return this.nodes.length > 1 && this.first() === this.last();
72892     },
72893
72894
72895     isConvex: function(resolver) {
72896         if (!this.isClosed() || this.isDegenerate()) return null;
72897
72898         var nodes = lodash.uniq(resolver.childNodes(this)),
72899             coords = lodash.map(nodes, 'loc'),
72900             curr = 0, prev = 0;
72901
72902         for (var i = 0; i < coords.length; i++) {
72903             var o = coords[(i+1) % coords.length],
72904                 a = coords[i],
72905                 b = coords[(i+2) % coords.length],
72906                 res = geoCross(o, a, b);
72907
72908             curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
72909             if (curr === 0) {
72910                 continue;
72911             } else if (prev && curr !== prev) {
72912                 return false;
72913             }
72914             prev = curr;
72915         }
72916         return true;
72917     },
72918
72919
72920     isArea: function() {
72921         if (this.tags.area === 'yes')
72922             return true;
72923         if (!this.isClosed() || this.tags.area === 'no')
72924             return false;
72925         for (var key in this.tags) {
72926             if (key in areaKeys && !(this.tags[key] in areaKeys[key])) {
72927                 return true;
72928             }
72929         }
72930         return false;
72931     },
72932
72933
72934     isDegenerate: function() {
72935         return lodash.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
72936     },
72937
72938
72939     areAdjacent: function(n1, n2) {
72940         for (var i = 0; i < this.nodes.length; i++) {
72941             if (this.nodes[i] === n1) {
72942                 if (this.nodes[i - 1] === n2) return true;
72943                 if (this.nodes[i + 1] === n2) return true;
72944             }
72945         }
72946         return false;
72947     },
72948
72949
72950     geometry: function(graph) {
72951         return graph.transient(this, 'geometry', function() {
72952             return this.isArea() ? 'area' : 'line';
72953         });
72954     },
72955
72956
72957     // If this way is not closed, append the beginning node to the end of the nodelist to close it.
72958     close: function() {
72959         if (this.isClosed() || !this.nodes.length) return this;
72960
72961         var nodes = this.nodes.slice();
72962         nodes = nodes.filter(noRepeatNodes);
72963         nodes.push(nodes[0]);
72964         return this.update({ nodes: nodes });
72965     },
72966
72967
72968     // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
72969     unclose: function() {
72970         if (!this.isClosed()) return this;
72971
72972         var nodes = this.nodes.slice(),
72973             connector = this.first(),
72974             i = nodes.length - 1;
72975
72976         // remove trailing connectors..
72977         while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
72978             nodes.splice(i, 1);
72979             i = nodes.length - 1;
72980         }
72981
72982         nodes = nodes.filter(noRepeatNodes);
72983         return this.update({ nodes: nodes });
72984     },
72985
72986
72987     // Adds a node (id) in front of the node which is currently at position index.
72988     // If index is undefined, the node will be added to the end of the way for linear ways,
72989     //   or just before the final connecting node for circular ways.
72990     // Consecutive duplicates are eliminated including existing ones.
72991     // Circularity is always preserved when adding a node.
72992     addNode: function(id, index) {
72993         var nodes = this.nodes.slice(),
72994             isClosed = this.isClosed(),
72995             max$$1 = isClosed ? nodes.length - 1 : nodes.length;
72996
72997         if (index === undefined) {
72998             index = max$$1;
72999         }
73000
73001         if (index < 0 || index > max$$1) {
73002             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
73003         }
73004
73005         // If this is a closed way, remove all connector nodes except the first one
73006         // (there may be duplicates) and adjust index if necessary..
73007         if (isClosed) {
73008             var connector = this.first();
73009
73010             // leading connectors..
73011             var i = 1;
73012             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
73013                 nodes.splice(i, 1);
73014                 if (index > i) index--;
73015             }
73016
73017             // trailing connectors..
73018             i = nodes.length - 1;
73019             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
73020                 nodes.splice(i, 1);
73021                 if (index > i) index--;
73022                 i = nodes.length - 1;
73023             }
73024         }
73025
73026         nodes.splice(index, 0, id);
73027         nodes = nodes.filter(noRepeatNodes);
73028
73029         // If the way was closed before, append a connector node to keep it closed..
73030         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73031             nodes.push(nodes[0]);
73032         }
73033
73034         return this.update({ nodes: nodes });
73035     },
73036
73037
73038     // Replaces the node which is currently at position index with the given node (id).
73039     // Consecutive duplicates are eliminated including existing ones.
73040     // Circularity is preserved when updating a node.
73041     updateNode: function(id, index) {
73042         var nodes = this.nodes.slice(),
73043             isClosed = this.isClosed(),
73044             max$$1 = nodes.length - 1;
73045
73046         if (index === undefined || index < 0 || index > max$$1) {
73047             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
73048         }
73049
73050         // If this is a closed way, remove all connector nodes except the first one
73051         // (there may be duplicates) and adjust index if necessary..
73052         if (isClosed) {
73053             var connector = this.first();
73054
73055             // leading connectors..
73056             var i = 1;
73057             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
73058                 nodes.splice(i, 1);
73059                 if (index > i) index--;
73060             }
73061
73062             // trailing connectors..
73063             i = nodes.length - 1;
73064             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
73065                 nodes.splice(i, 1);
73066                 if (index === i) index = 0;  // update leading connector instead
73067                 i = nodes.length - 1;
73068             }
73069         }
73070
73071         nodes.splice(index, 1, id);
73072         nodes = nodes.filter(noRepeatNodes);
73073
73074         // If the way was closed before, append a connector node to keep it closed..
73075         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73076             nodes.push(nodes[0]);
73077         }
73078
73079         return this.update({nodes: nodes});
73080     },
73081
73082
73083     // Replaces each occurrence of node id needle with replacement.
73084     // Consecutive duplicates are eliminated including existing ones.
73085     // Circularity is preserved.
73086     replaceNode: function(needle, replacement) {
73087         var nodes = this.nodes.slice(),
73088             isClosed = this.isClosed();
73089
73090         for (var i = 0; i < nodes.length; i++) {
73091             if (nodes[i] === needle) {
73092                 nodes[i] = replacement;
73093             }
73094         }
73095
73096         nodes = nodes.filter(noRepeatNodes);
73097
73098         // If the way was closed before, append a connector node to keep it closed..
73099         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73100             nodes.push(nodes[0]);
73101         }
73102
73103         return this.update({nodes: nodes});
73104     },
73105
73106
73107     // Removes each occurrence of node id needle with replacement.
73108     // Consecutive duplicates are eliminated including existing ones.
73109     // Circularity is preserved.
73110     removeNode: function(id) {
73111         var nodes = this.nodes.slice(),
73112             isClosed = this.isClosed();
73113
73114         nodes = nodes
73115             .filter(function(node) { return node !== id; })
73116             .filter(noRepeatNodes);
73117
73118         // If the way was closed before, append a connector node to keep it closed..
73119         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73120             nodes.push(nodes[0]);
73121         }
73122
73123         return this.update({nodes: nodes});
73124     },
73125
73126
73127     asJXON: function(changeset_id) {
73128         var r = {
73129             way: {
73130                 '@id': this.osmId(),
73131                 '@version': this.version || 0,
73132                 nd: lodash.map(this.nodes, function(id) {
73133                     return { keyAttributes: { ref: osmEntity$$1.id.toOSM(id) } };
73134                 }),
73135                 tag: lodash.map(this.tags, function(v, k) {
73136                     return { keyAttributes: { k: k, v: v } };
73137                 })
73138             }
73139         };
73140         if (changeset_id) {
73141             r.way['@changeset'] = changeset_id;
73142         }
73143         return r;
73144     },
73145
73146
73147     asGeoJSON: function(resolver) {
73148         return resolver.transient(this, 'GeoJSON', function() {
73149             var coordinates = lodash.map(resolver.childNodes(this), 'loc');
73150             if (this.isArea() && this.isClosed()) {
73151                 return {
73152                     type: 'Polygon',
73153                     coordinates: [coordinates]
73154                 };
73155             } else {
73156                 return {
73157                     type: 'LineString',
73158                     coordinates: coordinates
73159                 };
73160             }
73161         });
73162     },
73163
73164
73165     area: function(resolver) {
73166         return resolver.transient(this, 'area', function() {
73167             var nodes = resolver.childNodes(this);
73168
73169             var json$$1 = {
73170                 type: 'Polygon',
73171                 coordinates: [lodash.map(nodes, 'loc')]
73172             };
73173
73174             if (!this.isClosed() && nodes.length) {
73175                 json$$1.coordinates[0].push(nodes[0].loc);
73176             }
73177
73178             var area$$1 = area(json$$1);
73179
73180             // Heuristic for detecting counterclockwise winding order. Assumes
73181             // that OpenStreetMap polygons are not hemisphere-spanning.
73182             if (area$$1 > 2 * Math.PI) {
73183                 json$$1.coordinates[0] = json$$1.coordinates[0].reverse();
73184                 area$$1 = area(json$$1);
73185             }
73186
73187             return isNaN(area$$1) ? 0 : area$$1;
73188         });
73189     }
73190 });
73191
73192
73193 // Filter function to eliminate consecutive duplicates.
73194 function noRepeatNodes(node, i, arr) {
73195     return i === 0 || node !== arr[i - 1];
73196 }
73197
73198 function osmTurn(turn) {
73199     if (!(this instanceof osmTurn))
73200         return new osmTurn(turn);
73201     lodash.extend(this, turn);
73202 }
73203
73204
73205 function osmIntersection(graph, vertexId) {
73206     var vertex = graph.entity(vertexId),
73207         parentWays = graph.parentWays(vertex),
73208         coincident = [],
73209         highways = {};
73210
73211     function addHighway(way, adjacentNodeId) {
73212         if (highways[adjacentNodeId]) {
73213             coincident.push(adjacentNodeId);
73214         } else {
73215             highways[adjacentNodeId] = way;
73216         }
73217     }
73218
73219     // Pre-split ways that would need to be split in
73220     // order to add a restriction. The real split will
73221     // happen when the restriction is added.
73222     parentWays.forEach(function(way) {
73223         if (!way.tags.highway || way.isArea() || way.isDegenerate())
73224             return;
73225
73226         var isFirst = (vertexId === way.first()),
73227             isLast = (vertexId === way.last()),
73228             isAffix = (isFirst || isLast),
73229             isClosingNode = (isFirst && isLast);
73230
73231         if (isAffix && !isClosingNode) {
73232             var index = (isFirst ? 1 : way.nodes.length - 2);
73233             addHighway(way, way.nodes[index]);
73234
73235         } else {
73236             var splitIndex, wayA, wayB, indexA, indexB;
73237             if (isClosingNode) {
73238                 splitIndex = Math.ceil(way.nodes.length / 2);  // split at midpoint
73239                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
73240                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
73241                 indexA = 1;
73242                 indexB = way.nodes.length - 2;
73243             } else {
73244                 splitIndex = lodash.indexOf(way.nodes, vertex.id, 1);  // split at vertexid
73245                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
73246                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
73247                 indexA = splitIndex - 1;
73248                 indexB = splitIndex + 1;
73249             }
73250             graph = graph.replace(wayA).replace(wayB);
73251             addHighway(wayA, way.nodes[indexA]);
73252             addHighway(wayB, way.nodes[indexB]);
73253         }
73254     });
73255
73256     // remove any ways from this intersection that are coincident
73257     // (i.e. any adjacent node used by more than one intersecting way)
73258     coincident.forEach(function (n) {
73259         delete highways[n];
73260     });
73261
73262
73263     var intersection = {
73264         highways: highways,
73265         ways: lodash.values(highways),
73266         graph: graph
73267     };
73268
73269
73270     intersection.adjacentNodeId = function(fromWayId) {
73271         return lodash.find(lodash.keys(highways), function(k) {
73272             return highways[k].id === fromWayId;
73273         });
73274     };
73275
73276
73277     intersection.turns = function(fromNodeId) {
73278         var start = highways[fromNodeId];
73279         if (!start)
73280             return [];
73281
73282         if (start.first() === vertex.id && start.tags.oneway === 'yes')
73283             return [];
73284         if (start.last() === vertex.id && start.tags.oneway === '-1')
73285             return [];
73286
73287         function withRestriction(turn) {
73288             graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
73289                 if (relation.tags.type !== 'restriction')
73290                     return;
73291
73292                 var f = relation.memberByRole('from'),
73293                     t = relation.memberByRole('to'),
73294                     v = relation.memberByRole('via');
73295
73296                 if (f && f.id === turn.from.way &&
73297                     v && v.id === turn.via.node &&
73298                     t && t.id === turn.to.way) {
73299                     turn.restriction = relation.id;
73300                 } else if (/^only_/.test(relation.tags.restriction) &&
73301                     f && f.id === turn.from.way &&
73302                     v && v.id === turn.via.node &&
73303                     t && t.id !== turn.to.way) {
73304                     turn.restriction = relation.id;
73305                     turn.indirect_restriction = true;
73306                 }
73307             });
73308
73309             return osmTurn(turn);
73310         }
73311
73312
73313         var from = {
73314                 node: fromNodeId,
73315                 way: start.id.split(/-(a|b)/)[0]
73316             },
73317             via = { node: vertex.id },
73318             turns = [];
73319
73320         lodash.each(highways, function(end, adjacentNodeId) {
73321             if (end === start)
73322                 return;
73323
73324             // backward
73325             if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
73326                 turns.push(withRestriction({
73327                     from: from,
73328                     via: via,
73329                     to: {
73330                         node: adjacentNodeId,
73331                         way: end.id.split(/-(a|b)/)[0]
73332                     }
73333                 }));
73334             }
73335
73336             // forward
73337             if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
73338                 turns.push(withRestriction({
73339                     from: from,
73340                     via: via,
73341                     to: {
73342                         node: adjacentNodeId,
73343                         way: end.id.split(/-(a|b)/)[0]
73344                     }
73345                 }));
73346             }
73347
73348         });
73349
73350         // U-turn
73351         if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
73352             turns.push(withRestriction({
73353                 from: from,
73354                 via: via,
73355                 to: from,
73356                 u: true
73357             }));
73358         }
73359
73360         return turns;
73361     };
73362
73363     return intersection;
73364 }
73365
73366
73367 function osmInferRestriction(graph, from, via, to, projection) {
73368     var fromWay = graph.entity(from.way),
73369         fromNode = graph.entity(from.node),
73370         toWay = graph.entity(to.way),
73371         toNode = graph.entity(to.node),
73372         viaNode = graph.entity(via.node),
73373         fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
73374             (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
73375         toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
73376             (toWay.tags.oneway === '-1' && toWay.last() === via.node),
73377         angle = geoAngle(viaNode, fromNode, projection) -
73378                 geoAngle(viaNode, toNode, projection);
73379
73380     angle = angle * 180 / Math.PI;
73381
73382     while (angle < 0)
73383         angle += 360;
73384
73385     if (fromNode === toNode)
73386         return 'no_u_turn';
73387     if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
73388         return 'no_u_turn';
73389     if (angle < 158)
73390         return 'no_right_turn';
73391     if (angle > 202)
73392         return 'no_left_turn';
73393
73394     return 'no_straight_on';
73395 }
73396
73397 function actionAddMember(relationId, member, memberIndex) {
73398     return function(graph) {
73399         var relation = graph.entity(relationId);
73400
73401         if (isNaN(memberIndex) && member.type === 'way') {
73402             var members = relation.indexedMembers();
73403             members.push(member);
73404
73405             var joined = osmJoinWays(members, graph);
73406             for (var i = 0; i < joined.length; i++) {
73407                 var segment = joined[i];
73408                 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
73409                     if (segment[j] !== member)
73410                         continue;
73411
73412                     if (j === 0) {
73413                         memberIndex = segment[j + 1].index;
73414                     } else if (j === segment.length - 1) {
73415                         memberIndex = segment[j - 1].index + 1;
73416                     } else {
73417                         memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
73418                     }
73419                 }
73420             }
73421         }
73422
73423         return graph.replace(relation.addMember(member, memberIndex));
73424     };
73425 }
73426
73427 function actionAddMidpoint(midpoint, node) {
73428     return function(graph) {
73429         graph = graph.replace(node.move(midpoint.loc));
73430
73431         var parents = lodash.intersection(
73432             graph.parentWays(graph.entity(midpoint.edge[0])),
73433             graph.parentWays(graph.entity(midpoint.edge[1])));
73434
73435         parents.forEach(function(way) {
73436             for (var i = 0; i < way.nodes.length - 1; i++) {
73437                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
73438                     graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
73439
73440                     // Add only one midpoint on doubled-back segments,
73441                     // turning them into self-intersections.
73442                     return;
73443                 }
73444             }
73445         });
73446
73447         return graph;
73448     };
73449 }
73450
73451 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
73452 function actionAddVertex(wayId, nodeId, index) {
73453     return function(graph) {
73454         return graph.replace(graph.entity(wayId).addNode(nodeId, index));
73455     };
73456 }
73457
73458 function actionChangeMember(relationId, member, memberIndex) {
73459     return function(graph) {
73460         return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
73461     };
73462 }
73463
73464 function actionChangePreset(entityId, oldPreset, newPreset) {
73465     return function(graph) {
73466         var entity = graph.entity(entityId),
73467             geometry = entity.geometry(graph),
73468             tags = entity.tags;
73469
73470         if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
73471         if (newPreset) tags = newPreset.applyTags(tags, geometry);
73472
73473         return graph.replace(entity.update({tags: tags}));
73474     };
73475 }
73476
73477 function actionChangeTags(entityId, tags) {
73478     return function(graph) {
73479         var entity = graph.entity(entityId);
73480         return graph.replace(entity.update({tags: tags}));
73481     };
73482 }
73483
73484 function actionCircularize(wayId, projection, maxAngle) {
73485     maxAngle = (maxAngle || 20) * Math.PI / 180;
73486
73487
73488     var action = function(graph, t) {
73489         if (t === null || !isFinite(t)) t = 1;
73490         t = Math.min(Math.max(+t, 0), 1);
73491
73492         var way = graph.entity(wayId),
73493             origNodes = {};
73494
73495         graph.childNodes(way).forEach(function(node) {
73496             if (!origNodes[node.id]) origNodes[node.id] = node;
73497         });
73498
73499         if (!way.isConvex(graph)) {
73500             graph = action.makeConvex(graph);
73501         }
73502
73503         var nodes = lodash.uniq(graph.childNodes(way)),
73504             keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
73505             points = nodes.map(function(n) { return projection(n.loc); }),
73506             keyPoints = keyNodes.map(function(n) { return projection(n.loc); }),
73507             centroid = (points.length === 2) ? geoInterp(points[0], points[1], 0.5) : d3polygonCentroid(points),
73508             radius = median(points, function(p) { return geoEuclideanDistance(centroid, p); }),
73509             sign = d3polygonArea(points) > 0 ? 1 : -1,
73510             ids;
73511
73512         // we need atleast two key nodes for the algorithm to work
73513         if (!keyNodes.length) {
73514             keyNodes = [nodes[0]];
73515             keyPoints = [points[0]];
73516         }
73517
73518         if (keyNodes.length === 1) {
73519             var index = nodes.indexOf(keyNodes[0]),
73520                 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
73521
73522             keyNodes.push(nodes[oppositeIndex]);
73523             keyPoints.push(points[oppositeIndex]);
73524         }
73525
73526         // key points and nodes are those connected to the ways,
73527         // they are projected onto the circle, inbetween nodes are moved
73528         // to constant intervals between key nodes, extra inbetween nodes are
73529         // added if necessary.
73530         for (var i = 0; i < keyPoints.length; i++) {
73531             var nextKeyNodeIndex = (i + 1) % keyNodes.length,
73532                 startNode = keyNodes[i],
73533                 endNode = keyNodes[nextKeyNodeIndex],
73534                 startNodeIndex = nodes.indexOf(startNode),
73535                 endNodeIndex = nodes.indexOf(endNode),
73536                 numberNewPoints = -1,
73537                 indexRange = endNodeIndex - startNodeIndex,
73538                 nearNodes = {},
73539                 inBetweenNodes = [],
73540                 startAngle, endAngle, totalAngle, eachAngle,
73541                 angle, loc, node, origNode, j;
73542
73543             if (indexRange < 0) {
73544                 indexRange += nodes.length;
73545             }
73546
73547             // position this key node
73548             var distance = geoEuclideanDistance(centroid, keyPoints[i]);
73549             if (distance === 0) { distance = 1e-4; }
73550             keyPoints[i] = [
73551                 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius,
73552                 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius
73553             ];
73554             loc = projection.invert(keyPoints[i]);
73555             node = keyNodes[i];
73556             origNode = origNodes[node.id];
73557             node = node.move(geoInterp(origNode.loc, loc, t));
73558             graph = graph.replace(node);
73559
73560             // figure out the between delta angle we want to match to
73561             startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
73562             endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
73563             totalAngle = endAngle - startAngle;
73564
73565             // detects looping around -pi/pi
73566             if (totalAngle * sign > 0) {
73567                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
73568             }
73569
73570             do {
73571                 numberNewPoints++;
73572                 eachAngle = totalAngle / (indexRange + numberNewPoints);
73573             } while (Math.abs(eachAngle) > maxAngle);
73574
73575
73576             // move existing nodes
73577             for (j = 1; j < indexRange; j++) {
73578                 angle = startAngle + j * eachAngle;
73579                 loc = projection.invert([
73580                     centroid[0] + Math.cos(angle) * radius,
73581                     centroid[1] + Math.sin(angle) * radius
73582                 ]);
73583
73584                 node = nodes[(j + startNodeIndex) % nodes.length];
73585                 origNode = origNodes[node.id];
73586                 nearNodes[node.id] = angle;
73587
73588                 node = node.move(geoInterp(origNode.loc, loc, t));
73589                 graph = graph.replace(node);
73590             }
73591
73592             // add new inbetween nodes if necessary
73593             for (j = 0; j < numberNewPoints; j++) {
73594                 angle = startAngle + (indexRange + j) * eachAngle;
73595                 loc = projection.invert([
73596                     centroid[0] + Math.cos(angle) * radius,
73597                     centroid[1] + Math.sin(angle) * radius
73598                 ]);
73599
73600                 // choose a nearnode to use as the original
73601                 var min$$1 = Infinity;
73602                 for (var nodeId in nearNodes) {
73603                     var nearAngle = nearNodes[nodeId],
73604                         dist = Math.abs(nearAngle - angle);
73605                     if (dist < min$$1) {
73606                         dist = min$$1;
73607                         origNode = origNodes[nodeId];
73608                     }
73609                 }
73610
73611                 node = osmNode({ loc: geoInterp(origNode.loc, loc, t) });
73612                 graph = graph.replace(node);
73613
73614                 nodes.splice(endNodeIndex + j, 0, node);
73615                 inBetweenNodes.push(node.id);
73616             }
73617
73618             // Check for other ways that share these keyNodes..
73619             // If keyNodes are adjacent in both ways,
73620             // we can add inBetween nodes to that shared way too..
73621             if (indexRange === 1 && inBetweenNodes.length) {
73622                 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
73623                     endIndex1 = way.nodes.lastIndexOf(endNode.id),
73624                     wayDirection1 = (endIndex1 - startIndex1);
73625                 if (wayDirection1 < -1) { wayDirection1 = 1; }
73626
73627                 /* eslint-disable no-loop-func */
73628                 lodash.each(lodash.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
73629                     if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
73630                         var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
73631                             endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
73632                             wayDirection2 = (endIndex2 - startIndex2),
73633                             insertAt = endIndex2;
73634                         if (wayDirection2 < -1) { wayDirection2 = 1; }
73635
73636                         if (wayDirection1 !== wayDirection2) {
73637                             inBetweenNodes.reverse();
73638                             insertAt = startIndex2;
73639                         }
73640                         for (j = 0; j < inBetweenNodes.length; j++) {
73641                             sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
73642                         }
73643                         graph = graph.replace(sharedWay);
73644                     }
73645                 });
73646                 /* eslint-enable no-loop-func */
73647             }
73648
73649         }
73650
73651         // update the way to have all the new nodes
73652         ids = nodes.map(function(n) { return n.id; });
73653         ids.push(ids[0]);
73654
73655         way = way.update({nodes: ids});
73656         graph = graph.replace(way);
73657
73658         return graph;
73659     };
73660
73661
73662     action.makeConvex = function(graph) {
73663         var way = graph.entity(wayId),
73664             nodes = lodash.uniq(graph.childNodes(way)),
73665             points = nodes.map(function(n) { return projection(n.loc); }),
73666             sign = d3polygonArea(points) > 0 ? 1 : -1,
73667             hull = d3polygonHull(points);
73668
73669         // D3 convex hulls go counterclockwise..
73670         if (sign === -1) {
73671             nodes.reverse();
73672             points.reverse();
73673         }
73674
73675         for (var i = 0; i < hull.length - 1; i++) {
73676             var startIndex = points.indexOf(hull[i]),
73677                 endIndex = points.indexOf(hull[i+1]),
73678                 indexRange = (endIndex - startIndex);
73679
73680             if (indexRange < 0) {
73681                 indexRange += nodes.length;
73682             }
73683
73684             // move interior nodes to the surface of the convex hull..
73685             for (var j = 1; j < indexRange; j++) {
73686                 var point = geoInterp(hull[i], hull[i+1], j / indexRange),
73687                     node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
73688                 graph = graph.replace(node);
73689             }
73690         }
73691         return graph;
73692     };
73693
73694
73695     action.disabled = function(graph) {
73696         if (!graph.entity(wayId).isClosed())
73697             return 'not_closed';
73698     };
73699
73700
73701     action.transitionable = true;
73702
73703
73704     return action;
73705 }
73706
73707 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
73708 function actionDeleteWay(wayId) {
73709
73710
73711     function canDeleteNode(node, graph) {
73712         return !graph.parentWays(node).length &&
73713             !graph.parentRelations(node).length &&
73714             !node.hasInterestingTags();
73715     }
73716
73717
73718     var action = function(graph) {
73719         var way = graph.entity(wayId);
73720
73721         graph.parentRelations(way)
73722             .forEach(function(parent) {
73723                 parent = parent.removeMembersWithID(wayId);
73724                 graph = graph.replace(parent);
73725
73726                 if (parent.isDegenerate()) {
73727                     graph = actionDeleteRelation(parent.id)(graph);
73728                 }
73729             });
73730
73731         lodash.uniq(way.nodes).forEach(function(nodeId) {
73732             graph = graph.replace(way.removeNode(nodeId));
73733
73734             var node = graph.entity(nodeId);
73735             if (canDeleteNode(node, graph)) {
73736                 graph = graph.remove(node);
73737             }
73738         });
73739
73740         return graph.remove(way);
73741     };
73742
73743
73744     return action;
73745 }
73746
73747 function actionDeleteMultiple(ids) {
73748     var actions = {
73749         way: actionDeleteWay,
73750         node: actionDeleteNode,
73751         relation: actionDeleteRelation
73752     };
73753
73754
73755     var action = function(graph) {
73756         ids.forEach(function(id) {
73757             if (graph.hasEntity(id)) { // It may have been deleted aready.
73758                 graph = actions[graph.entity(id).type](id)(graph);
73759             }
73760         });
73761
73762         return graph;
73763     };
73764
73765
73766     return action;
73767 }
73768
73769 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
73770 function actionDeleteRelation(relationId) {
73771
73772
73773     function canDeleteEntity(entity, graph) {
73774         return !graph.parentWays(entity).length &&
73775             !graph.parentRelations(entity).length &&
73776             !entity.hasInterestingTags();
73777     }
73778
73779
73780     var action = function(graph) {
73781         var relation = graph.entity(relationId);
73782
73783         graph.parentRelations(relation)
73784             .forEach(function(parent) {
73785                 parent = parent.removeMembersWithID(relationId);
73786                 graph = graph.replace(parent);
73787
73788                 if (parent.isDegenerate()) {
73789                     graph = actionDeleteRelation(parent.id)(graph);
73790                 }
73791             });
73792
73793         lodash.uniq(lodash.map(relation.members, 'id')).forEach(function(memberId) {
73794             graph = graph.replace(relation.removeMembersWithID(memberId));
73795
73796             var entity = graph.entity(memberId);
73797             if (canDeleteEntity(entity, graph)) {
73798                 graph = actionDeleteMultiple([memberId])(graph);
73799             }
73800         });
73801
73802         return graph.remove(relation);
73803     };
73804
73805
73806     return action;
73807 }
73808
73809 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
73810 function actionDeleteNode(nodeId) {
73811     var action = function(graph) {
73812         var node = graph.entity(nodeId);
73813
73814         graph.parentWays(node)
73815             .forEach(function(parent) {
73816                 parent = parent.removeNode(nodeId);
73817                 graph = graph.replace(parent);
73818
73819                 if (parent.isDegenerate()) {
73820                     graph = actionDeleteWay(parent.id)(graph);
73821                 }
73822             });
73823
73824         graph.parentRelations(node)
73825             .forEach(function(parent) {
73826                 parent = parent.removeMembersWithID(nodeId);
73827                 graph = graph.replace(parent);
73828
73829                 if (parent.isDegenerate()) {
73830                     graph = actionDeleteRelation(parent.id)(graph);
73831                 }
73832             });
73833
73834         return graph.remove(node);
73835     };
73836
73837
73838     return action;
73839 }
73840
73841 // Connect the ways at the given nodes.
73842 //
73843 // The last node will survive. All other nodes will be replaced with
73844 // the surviving node in parent ways, and then removed.
73845 //
73846 // Tags and relation memberships of of non-surviving nodes are merged
73847 // to the survivor.
73848 //
73849 // This is the inverse of `iD.actionDisconnect`.
73850 //
73851 // Reference:
73852 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
73853 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
73854 //
73855 function actionConnect(nodeIds) {
73856     return function(graph) {
73857         var survivor = graph.entity(lodash.last(nodeIds));
73858
73859         for (var i = 0; i < nodeIds.length - 1; i++) {
73860             var node = graph.entity(nodeIds[i]);
73861
73862             /* eslint-disable no-loop-func */
73863             graph.parentWays(node).forEach(function(parent) {
73864                 if (!parent.areAdjacent(node.id, survivor.id)) {
73865                     graph = graph.replace(parent.replaceNode(node.id, survivor.id));
73866                 }
73867             });
73868
73869             graph.parentRelations(node).forEach(function(parent) {
73870                 graph = graph.replace(parent.replaceMember(node, survivor));
73871             });
73872             /* eslint-enable no-loop-func */
73873
73874             survivor = survivor.mergeTags(node.tags);
73875             graph = actionDeleteNode(node.id)(graph);
73876         }
73877
73878         graph = graph.replace(survivor);
73879
73880         return graph;
73881     };
73882 }
73883
73884 function actionCopyEntities(ids, fromGraph) {
73885     var copies = {};
73886
73887
73888     var action = function(graph) {
73889         ids.forEach(function(id) {
73890             fromGraph.entity(id).copy(fromGraph, copies);
73891         });
73892
73893         for (var id in copies) {
73894             graph = graph.replace(copies[id]);
73895         }
73896
73897         return graph;
73898     };
73899
73900
73901     action.copies = function() {
73902         return copies;
73903     };
73904
73905
73906     return action;
73907 }
73908
73909 function actionDeleteMember(relationId, memberIndex) {
73910     return function(graph) {
73911         var relation = graph.entity(relationId)
73912             .removeMember(memberIndex);
73913
73914         graph = graph.replace(relation);
73915
73916         if (relation.isDegenerate())
73917             graph = actionDeleteRelation(relation.id)(graph);
73918
73919         return graph;
73920     };
73921 }
73922
73923 function actionDeprecateTags(entityId) {
73924
73925     return function(graph) {
73926         var entity = graph.entity(entityId),
73927             newtags = lodash.clone(entity.tags),
73928             change = false,
73929             rule;
73930
73931         // This handles dataDeprecated tags with a single condition
73932         for (var i = 0; i < dataDeprecated.length; i++) {
73933
73934             rule = dataDeprecated[i];
73935             var match = lodash.toPairs(rule.old)[0],
73936                 replacements = rule.replace ? lodash.toPairs(rule.replace) : null;
73937
73938             if (entity.tags[match[0]] && match[1] === '*') {
73939
73940                 var value = entity.tags[match[0]];
73941                 if (replacements && !newtags[replacements[0][0]]) {
73942                     newtags[replacements[0][0]] = value;
73943                 }
73944                 delete newtags[match[0]];
73945                 change = true;
73946
73947             } else if (entity.tags[match[0]] === match[1]) {
73948                 newtags = lodash.assign({}, rule.replace || {}, lodash.omit(newtags, match[0]));
73949                 change = true;
73950             }
73951         }
73952
73953         if (change) {
73954             return graph.replace(entity.update({tags: newtags}));
73955         } else {
73956             return graph;
73957         }
73958     };
73959 }
73960
73961 function actionDiscardTags(difference) {
73962
73963     return function(graph) {
73964         function discardTags(entity) {
73965             if (!lodash.isEmpty(entity.tags)) {
73966                 var tags = {};
73967                 lodash.each(entity.tags, function(v, k) {
73968                     if (v) tags[k] = v;
73969                 });
73970
73971                 graph = graph.replace(entity.update({
73972                     tags: lodash.omit(tags, dataDiscarded)
73973                 }));
73974             }
73975         }
73976
73977         difference.modified().forEach(discardTags);
73978         difference.created().forEach(discardTags);
73979
73980         return graph;
73981     };
73982 }
73983
73984 // Disconect the ways at the given node.
73985 //
73986 // Optionally, disconnect only the given ways.
73987 //
73988 // For testing convenience, accepts an ID to assign to the (first) new node.
73989 // Normally, this will be undefined and the way will automatically
73990 // be assigned a new ID.
73991 //
73992 // This is the inverse of `iD.actionConnect`.
73993 //
73994 // Reference:
73995 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
73996 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
73997 //
73998 function actionDisconnect(nodeId, newNodeId) {
73999     var wayIds;
74000
74001
74002     var action = function(graph) {
74003         var node = graph.entity(nodeId),
74004             connections = action.connections(graph);
74005
74006         connections.forEach(function(connection) {
74007             var way = graph.entity(connection.wayID),
74008                 newNode = osmNode({id: newNodeId, loc: node.loc, tags: node.tags});
74009
74010             graph = graph.replace(newNode);
74011             if (connection.index === 0 && way.isArea()) {
74012                 // replace shared node with shared node..
74013                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
74014             } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
74015                 // replace closing node with new new node..
74016                 graph = graph.replace(way.unclose().addNode(newNode.id));
74017             } else {
74018                 // replace shared node with multiple new nodes..
74019                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
74020             }
74021         });
74022
74023         return graph;
74024     };
74025
74026
74027     action.connections = function(graph) {
74028         var candidates = [],
74029             keeping = false,
74030             parentWays = graph.parentWays(graph.entity(nodeId));
74031
74032         parentWays.forEach(function(way) {
74033             if (wayIds && wayIds.indexOf(way.id) === -1) {
74034                 keeping = true;
74035                 return;
74036             }
74037             if (way.isArea() && (way.nodes[0] === nodeId)) {
74038                 candidates.push({ wayID: way.id, index: 0 });
74039             } else {
74040                 way.nodes.forEach(function(waynode, index) {
74041                     if (waynode === nodeId) {
74042                         candidates.push({ wayID: way.id, index: index });
74043                     }
74044                 });
74045             }
74046         });
74047
74048         return keeping ? candidates : candidates.slice(1);
74049     };
74050
74051
74052     action.disabled = function(graph) {
74053         var connections = action.connections(graph);
74054         if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
74055             return 'not_connected';
74056
74057         var parentWays = graph.parentWays(graph.entity(nodeId)),
74058             seenRelationIds = {},
74059             sharedRelation;
74060
74061         parentWays.forEach(function(way) {
74062             if (wayIds && wayIds.indexOf(way.id) === -1)
74063                 return;
74064
74065             var relations = graph.parentRelations(way);
74066             relations.forEach(function(relation) {
74067                 if (relation.id in seenRelationIds) {
74068                     sharedRelation = relation;
74069                 } else {
74070                     seenRelationIds[relation.id] = true;
74071                 }
74072             });
74073         });
74074
74075         if (sharedRelation)
74076             return 'relation';
74077     };
74078
74079
74080     action.limitWays = function(_) {
74081         if (!arguments.length) return wayIds;
74082         wayIds = _;
74083         return action;
74084     };
74085
74086
74087     return action;
74088 }
74089
74090 // Join ways at the end node they share.
74091 //
74092 // This is the inverse of `iD.actionSplit`.
74093 //
74094 // Reference:
74095 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
74096 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
74097 //
74098 function actionJoin(ids) {
74099
74100     function groupEntitiesByGeometry(graph) {
74101         var entities = ids.map(function(id) { return graph.entity(id); });
74102         return lodash.extend({line: []}, lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
74103     }
74104
74105
74106     var action = function(graph) {
74107         var ways = ids.map(graph.entity, graph),
74108             survivor = ways[0];
74109
74110         // Prefer to keep an existing way.
74111         for (var i = 0; i < ways.length; i++) {
74112             if (!ways[i].isNew()) {
74113                 survivor = ways[i];
74114                 break;
74115             }
74116         }
74117
74118         var joined = osmJoinWays(ways, graph)[0];
74119
74120         survivor = survivor.update({nodes: lodash.map(joined.nodes, 'id')});
74121         graph = graph.replace(survivor);
74122
74123         joined.forEach(function(way) {
74124             if (way.id === survivor.id)
74125                 return;
74126
74127             graph.parentRelations(way).forEach(function(parent) {
74128                 graph = graph.replace(parent.replaceMember(way, survivor));
74129             });
74130
74131             survivor = survivor.mergeTags(way.tags);
74132
74133             graph = graph.replace(survivor);
74134             graph = actionDeleteWay(way.id)(graph);
74135         });
74136
74137         return graph;
74138     };
74139
74140
74141     action.disabled = function(graph) {
74142         var geometries = groupEntitiesByGeometry(graph);
74143         if (ids.length < 2 || ids.length !== geometries.line.length)
74144             return 'not_eligible';
74145
74146         var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
74147         if (joined.length > 1)
74148             return 'not_adjacent';
74149
74150         var nodeIds = lodash.map(joined[0].nodes, 'id').slice(1, -1),
74151             relation,
74152             tags = {},
74153             conflicting = false;
74154
74155         joined[0].forEach(function(way) {
74156             var parents = graph.parentRelations(way);
74157             parents.forEach(function(parent) {
74158                 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
74159                     relation = parent;
74160             });
74161
74162             for (var k in way.tags) {
74163                 if (!(k in tags)) {
74164                     tags[k] = way.tags[k];
74165                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
74166                     conflicting = true;
74167                 }
74168             }
74169         });
74170
74171         if (relation)
74172             return 'restriction';
74173
74174         if (conflicting)
74175             return 'conflicting_tags';
74176     };
74177
74178
74179     return action;
74180 }
74181
74182 function actionMerge(ids) {
74183
74184     function groupEntitiesByGeometry(graph) {
74185         var entities = ids.map(function(id) { return graph.entity(id); });
74186         return lodash.extend({point: [], area: [], line: [], relation: []},
74187             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
74188     }
74189
74190
74191     var action = function(graph) {
74192         var geometries = groupEntitiesByGeometry(graph),
74193             target = geometries.area[0] || geometries.line[0],
74194             points = geometries.point;
74195
74196         points.forEach(function(point) {
74197             target = target.mergeTags(point.tags);
74198             graph = graph.replace(target);
74199
74200             graph.parentRelations(point).forEach(function(parent) {
74201                 graph = graph.replace(parent.replaceMember(point, target));
74202             });
74203
74204             var nodes = lodash.uniq(graph.childNodes(target)),
74205                 removeNode = point;
74206
74207             for (var i = 0; i < nodes.length; i++) {
74208                 var node = nodes[i];
74209                 if (graph.parentWays(node).length > 1 ||
74210                     graph.parentRelations(node).length ||
74211                     node.hasInterestingTags()) {
74212                     continue;
74213                 }
74214
74215                 // Found an uninteresting child node on the target way.
74216                 // Move orig point into its place to preserve point's history. #3683
74217                 graph = graph.replace(point.update({ tags: {}, loc: node.loc }));
74218                 target = target.replaceNode(node.id, point.id);
74219                 graph = graph.replace(target);
74220                 removeNode = node;
74221                 break;
74222             }
74223
74224             graph = graph.remove(removeNode);
74225         });
74226
74227         return graph;
74228     };
74229
74230
74231     action.disabled = function(graph) {
74232         var geometries = groupEntitiesByGeometry(graph);
74233         if (geometries.point.length === 0 ||
74234             (geometries.area.length + geometries.line.length) !== 1 ||
74235             geometries.relation.length !== 0)
74236             return 'not_eligible';
74237     };
74238
74239
74240     return action;
74241 }
74242
74243 function actionMergePolygon(ids, newRelationId) {
74244
74245     function groupEntities(graph) {
74246         var entities = ids.map(function (id) { return graph.entity(id); });
74247         return lodash.extend({
74248                 closedWay: [],
74249                 multipolygon: [],
74250                 other: []
74251             }, lodash.groupBy(entities, function(entity) {
74252                 if (entity.type === 'way' && entity.isClosed()) {
74253                     return 'closedWay';
74254                 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
74255                     return 'multipolygon';
74256                 } else {
74257                     return 'other';
74258                 }
74259             }));
74260     }
74261
74262
74263     var action = function(graph) {
74264         var entities = groupEntities(graph);
74265
74266         // An array representing all the polygons that are part of the multipolygon.
74267         //
74268         // Each element is itself an array of objects with an id property, and has a
74269         // locs property which is an array of the locations forming the polygon.
74270         var polygons = entities.multipolygon.reduce(function(polygons, m) {
74271             return polygons.concat(osmJoinWays(m.members, graph));
74272         }, []).concat(entities.closedWay.map(function(d) {
74273             var member = [{id: d.id}];
74274             member.nodes = graph.childNodes(d);
74275             return member;
74276         }));
74277
74278         // contained is an array of arrays of boolean values,
74279         // where contained[j][k] is true iff the jth way is
74280         // contained by the kth way.
74281         var contained = polygons.map(function(w, i) {
74282             return polygons.map(function(d, n) {
74283                 if (i === n) return null;
74284                 return geoPolygonContainsPolygon(
74285                     lodash.map(d.nodes, 'loc'),
74286                     lodash.map(w.nodes, 'loc'));
74287             });
74288         });
74289
74290         // Sort all polygons as either outer or inner ways
74291         var members = [],
74292             outer = true;
74293
74294         while (polygons.length) {
74295             extractUncontained(polygons);
74296             polygons = polygons.filter(isContained);
74297             contained = contained.filter(isContained).map(filterContained);
74298         }
74299
74300         function isContained(d, i) {
74301             return lodash.some(contained[i]);
74302         }
74303
74304         function filterContained(d) {
74305             return d.filter(isContained);
74306         }
74307
74308         function extractUncontained(polygons) {
74309             polygons.forEach(function(d, i) {
74310                 if (!isContained(d, i)) {
74311                     d.forEach(function(member) {
74312                         members.push({
74313                             type: 'way',
74314                             id: member.id,
74315                             role: outer ? 'outer' : 'inner'
74316                         });
74317                     });
74318                 }
74319             });
74320             outer = !outer;
74321         }
74322
74323         // Move all tags to one relation
74324         var relation = entities.multipolygon[0] ||
74325             osmRelation({ id: newRelationId, tags: { type: 'multipolygon' }});
74326
74327         entities.multipolygon.slice(1).forEach(function(m) {
74328             relation = relation.mergeTags(m.tags);
74329             graph = graph.remove(m);
74330         });
74331
74332         entities.closedWay.forEach(function(way) {
74333             function isThisOuter(m) {
74334                 return m.id === way.id && m.role !== 'inner';
74335             }
74336             if (members.some(isThisOuter)) {
74337                 relation = relation.mergeTags(way.tags);
74338                 graph = graph.replace(way.update({ tags: {} }));
74339             }
74340         });
74341
74342         return graph.replace(relation.update({
74343             members: members,
74344             tags: lodash.omit(relation.tags, 'area')
74345         }));
74346     };
74347
74348
74349     action.disabled = function(graph) {
74350         var entities = groupEntities(graph);
74351         if (entities.other.length > 0 ||
74352             entities.closedWay.length + entities.multipolygon.length < 2)
74353             return 'not_eligible';
74354         if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
74355             return 'incomplete_relation';
74356     };
74357
74358
74359     return action;
74360 }
74361
74362 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
74363 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
74364 //
74365 // Permission is hereby granted, free of charge, to any person
74366 // obtaining a copy of this software and associated documentation files
74367 // (the "Software"), to deal in the Software without restriction,
74368 // including without limitation the rights to use, copy, modify, merge,
74369 // publish, distribute, sublicense, and/or sell copies of the Software,
74370 // and to permit persons to whom the Software is furnished to do so,
74371 // subject to the following conditions:
74372 //
74373 // The above copyright notice and this permission notice shall be
74374 // included in all copies or substantial portions of the Software.
74375 //
74376 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
74377 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
74378 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
74379 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
74380 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
74381 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
74382 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
74383 // SOFTWARE.
74384
74385 // source:  https://bitbucket.org/lshift/synchrotron/src
74386 function longest_common_subsequence(file1, file2) {
74387     /* Text diff algorithm following Hunt and McIlroy 1976.
74388      * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
74389      * comparison, Bell Telephone Laboratories CSTR #41 (1976)
74390      * http://www.cs.dartmouth.edu/~doug/
74391      *
74392      * Expects two arrays of strings.
74393      */
74394     var equivalenceClasses;
74395     var file2indices;
74396     var newCandidate;
74397     var candidates;
74398     var line;
74399     var c, i, j, jX, r, s;
74400
74401     equivalenceClasses = {};
74402     for (j = 0; j < file2.length; j++) {
74403         line = file2[j];
74404         if (equivalenceClasses[line]) {
74405             equivalenceClasses[line].push(j);
74406         } else {
74407             equivalenceClasses[line] = [j];
74408         }
74409     }
74410
74411     candidates = [{file1index: -1,
74412                    file2index: -1,
74413                    chain: null}];
74414
74415     for (i = 0; i < file1.length; i++) {
74416         line = file1[i];
74417         file2indices = equivalenceClasses[line] || [];
74418
74419         r = 0;
74420         c = candidates[0];
74421
74422         for (jX = 0; jX < file2indices.length; jX++) {
74423             j = file2indices[jX];
74424
74425             for (s = 0; s < candidates.length; s++) {
74426                 if ((candidates[s].file2index < j) &&
74427                     ((s === candidates.length - 1) ||
74428                      (candidates[s + 1].file2index > j)))
74429                     break;
74430             }
74431
74432             if (s < candidates.length) {
74433                 newCandidate = {file1index: i,
74434                                 file2index: j,
74435                                 chain: candidates[s]};
74436                 if (r === candidates.length) {
74437                     candidates.push(c);
74438                 } else {
74439                     candidates[r] = c;
74440                 }
74441                 r = s + 1;
74442                 c = newCandidate;
74443                 if (r === candidates.length) {
74444                     break; // no point in examining further (j)s
74445                 }
74446             }
74447         }
74448
74449         candidates[r] = c;
74450     }
74451
74452     // At this point, we know the LCS: it's in the reverse of the
74453     // linked-list through .chain of
74454     // candidates[candidates.length - 1].
74455
74456     return candidates[candidates.length - 1];
74457 }
74458
74459
74460
74461
74462
74463
74464
74465
74466
74467
74468
74469 function diff_indices(file1, file2) {
74470     // We apply the LCS to give a simple representation of the
74471     // offsets and lengths of mismatched chunks in the input
74472     // files. This is used by diff3_merge_indices below.
74473
74474     var result = [];
74475     var tail1 = file1.length;
74476     var tail2 = file2.length;
74477
74478     for (var candidate = longest_common_subsequence(file1, file2);
74479          candidate !== null;
74480          candidate = candidate.chain)
74481     {
74482         var mismatchLength1 = tail1 - candidate.file1index - 1;
74483         var mismatchLength2 = tail2 - candidate.file2index - 1;
74484         tail1 = candidate.file1index;
74485         tail2 = candidate.file2index;
74486
74487         if (mismatchLength1 || mismatchLength2) {
74488             result.push({file1: [tail1 + 1, mismatchLength1],
74489                          file2: [tail2 + 1, mismatchLength2]});
74490         }
74491     }
74492
74493     result.reverse();
74494     return result;
74495 }
74496
74497 function diff3_merge_indices (a, o, b) {
74498     // Given three files, A, O, and B, where both A and B are
74499     // independently derived from O, returns a fairly complicated
74500     // internal representation of merge decisions it's taken. The
74501     // interested reader may wish to consult
74502     //
74503     // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
74504     // Formal Investigation of Diff3." In Arvind and Prasad,
74505     // editors, Foundations of Software Technology and Theoretical
74506     // Computer Science (FSTTCS), December 2007.
74507     //
74508     // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
74509     var i;
74510
74511     var m1 = diff_indices(o, a);
74512     var m2 = diff_indices(o, b);
74513
74514     var hunks = [];
74515     function addHunk(h, side) {
74516         hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
74517     }
74518     for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
74519     for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
74520     hunks.sort();
74521
74522     var result = [];
74523     var commonOffset = 0;
74524     function copyCommon(targetOffset) {
74525         if (targetOffset > commonOffset) {
74526             result.push([1, commonOffset, targetOffset - commonOffset]);
74527             commonOffset = targetOffset;
74528         }
74529     }
74530
74531     for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
74532         var firstHunkIndex = hunkIndex;
74533         var hunk = hunks[hunkIndex];
74534         var regionLhs = hunk[0];
74535         var regionRhs = regionLhs + hunk[2];
74536         while (hunkIndex < hunks.length - 1) {
74537             var maybeOverlapping = hunks[hunkIndex + 1];
74538             var maybeLhs = maybeOverlapping[0];
74539             if (maybeLhs > regionRhs) break;
74540             regionRhs = maybeLhs + maybeOverlapping[2];
74541             hunkIndex++;
74542         }
74543
74544         copyCommon(regionLhs);
74545         if (firstHunkIndex === hunkIndex) {
74546     // The "overlap" was only one hunk long, meaning that
74547     // there's no conflict here. Either a and o were the
74548     // same, or b and o were the same.
74549             if (hunk[4] > 0) {
74550                 result.push([hunk[1], hunk[3], hunk[4]]);
74551             }
74552         } else {
74553     // A proper conflict. Determine the extents of the
74554     // regions involved from a, o and b. Effectively merge
74555     // all the hunks on the left into one giant hunk, and
74556     // do the same for the right; then, correct for skew
74557     // in the regions of o that each side changed, and
74558     // report appropriate spans for the three sides.
74559     var regions = {
74560         0: [a.length, -1, o.length, -1],
74561         2: [b.length, -1, o.length, -1]
74562     };
74563             for (i = firstHunkIndex; i <= hunkIndex; i++) {
74564         hunk = hunks[i];
74565                 var side = hunk[1];
74566         var r = regions[side];
74567         var oLhs = hunk[0];
74568         var oRhs = oLhs + hunk[2];
74569                 var abLhs = hunk[3];
74570                 var abRhs = abLhs + hunk[4];
74571         r[0] = Math.min(abLhs, r[0]);
74572         r[1] = Math.max(abRhs, r[1]);
74573         r[2] = Math.min(oLhs, r[2]);
74574         r[3] = Math.max(oRhs, r[3]);
74575             }
74576     var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
74577     var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
74578     var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
74579     var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
74580             result.push([-1,
74581              aLhs,      aRhs      - aLhs,
74582              regionLhs, regionRhs - regionLhs,
74583              bLhs,      bRhs      - bLhs]);
74584         }
74585         commonOffset = regionRhs;
74586     }
74587
74588     copyCommon(o.length);
74589     return result;
74590 }
74591
74592 function diff3_merge (a, o, b, excludeFalseConflicts) {
74593     // Applies the output of Diff3.diff3_merge_indices to actually
74594     // construct the merged file; the returned result alternates
74595     // between "ok" and "conflict" blocks.
74596
74597     var result = [];
74598     var files = [a, o, b];
74599     var indices = diff3_merge_indices(a, o, b);
74600
74601     var okLines = [];
74602     function flushOk() {
74603         if (okLines.length) {
74604             result.push({ok: okLines});
74605         }
74606         okLines = [];
74607     }
74608     function pushOk(xs) {
74609         for (var j = 0; j < xs.length; j++) {
74610             okLines.push(xs[j]);
74611         }
74612     }
74613
74614     function isTrueConflict(rec) {
74615         if (rec[2] !== rec[6]) return true;
74616         var aoff = rec[1];
74617         var boff = rec[5];
74618         for (var j = 0; j < rec[2]; j++) {
74619             if (a[j + aoff] !== b[j + boff]) return true;
74620         }
74621         return false;
74622     }
74623
74624     for (var i = 0; i < indices.length; i++) {
74625         var x = indices[i];
74626         var side = x[0];
74627         if (side === -1) {
74628             if (excludeFalseConflicts && !isTrueConflict(x)) {
74629                 pushOk(files[0].slice(x[1], x[1] + x[2]));
74630             } else {
74631                 flushOk();
74632                 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
74633                                         aIndex: x[1],
74634                                         o: o.slice(x[3], x[3] + x[4]),
74635                                         oIndex: x[3],
74636                                         b: b.slice(x[5], x[5] + x[6]),
74637                                         bIndex: x[5]}});
74638             }
74639         } else {
74640             pushOk(files[side].slice(x[1], x[1] + x[2]));
74641         }
74642     }
74643
74644     flushOk();
74645     return result;
74646 }
74647
74648 function actionMergeRemoteChanges(id, localGraph, remoteGraph, formatUser) {
74649     var option = 'safe',  // 'safe', 'force_local', 'force_remote'
74650         conflicts = [];
74651
74652
74653     function user(d) {
74654         return lodash.isFunction(formatUser) ? formatUser(d) : d;
74655     }
74656
74657
74658     function mergeLocation(remote, target) {
74659         function pointEqual(a, b) {
74660             var epsilon = 1e-6;
74661             return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
74662         }
74663
74664         if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
74665             return target;
74666         }
74667         if (option === 'force_remote') {
74668             return target.update({loc: remote.loc});
74669         }
74670
74671         conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
74672         return target;
74673     }
74674
74675
74676     function mergeNodes(base, remote, target) {
74677         if (option === 'force_local' || lodash.isEqual(target.nodes, remote.nodes)) {
74678             return target;
74679         }
74680         if (option === 'force_remote') {
74681             return target.update({nodes: remote.nodes});
74682         }
74683
74684         var ccount = conflicts.length,
74685             o = base.nodes || [],
74686             a = target.nodes || [],
74687             b = remote.nodes || [],
74688             nodes = [],
74689             hunks = diff3_merge(a, o, b, true);
74690
74691         for (var i = 0; i < hunks.length; i++) {
74692             var hunk = hunks[i];
74693             if (hunk.ok) {
74694                 nodes.push.apply(nodes, hunk.ok);
74695             } else {
74696                 // for all conflicts, we can assume c.a !== c.b
74697                 // because `diff3_merge` called with `true` option to exclude false conflicts..
74698                 var c = hunk.conflict;
74699                 if (lodash.isEqual(c.o, c.a)) {  // only changed remotely
74700                     nodes.push.apply(nodes, c.b);
74701                 } else if (lodash.isEqual(c.o, c.b)) {  // only changed locally
74702                     nodes.push.apply(nodes, c.a);
74703                 } else {       // changed both locally and remotely
74704                     conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
74705                     break;
74706                 }
74707             }
74708         }
74709
74710         return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
74711     }
74712
74713
74714     function mergeChildren(targetWay, children, updates, graph) {
74715         function isUsed(node, targetWay) {
74716             var parentWays = lodash.map(graph.parentWays(node), 'id');
74717             return node.hasInterestingTags() ||
74718                 lodash.without(parentWays, targetWay.id).length > 0 ||
74719                 graph.parentRelations(node).length > 0;
74720         }
74721
74722         var ccount = conflicts.length;
74723
74724         for (var i = 0; i < children.length; i++) {
74725             var id = children[i],
74726                 node = graph.hasEntity(id);
74727
74728             // remove unused childNodes..
74729             if (targetWay.nodes.indexOf(id) === -1) {
74730                 if (node && !isUsed(node, targetWay)) {
74731                     updates.removeIds.push(id);
74732                 }
74733                 continue;
74734             }
74735
74736             // restore used childNodes..
74737             var local = localGraph.hasEntity(id),
74738                 remote = remoteGraph.hasEntity(id),
74739                 target;
74740
74741             if (option === 'force_remote' && remote && remote.visible) {
74742                 updates.replacements.push(remote);
74743
74744             } else if (option === 'force_local' && local) {
74745                 target = osmEntity$$1(local);
74746                 if (remote) {
74747                     target = target.update({ version: remote.version });
74748                 }
74749                 updates.replacements.push(target);
74750
74751             } else if (option === 'safe' && local && remote && local.version !== remote.version) {
74752                 target = osmEntity$$1(local, { version: remote.version });
74753                 if (remote.visible) {
74754                     target = mergeLocation(remote, target);
74755                 } else {
74756                     conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
74757                 }
74758
74759                 if (conflicts.length !== ccount) break;
74760                 updates.replacements.push(target);
74761             }
74762         }
74763
74764         return targetWay;
74765     }
74766
74767
74768     function updateChildren(updates, graph) {
74769         for (var i = 0; i < updates.replacements.length; i++) {
74770             graph = graph.replace(updates.replacements[i]);
74771         }
74772         if (updates.removeIds.length) {
74773             graph = actionDeleteMultiple(updates.removeIds)(graph);
74774         }
74775         return graph;
74776     }
74777
74778
74779     function mergeMembers(remote, target) {
74780         if (option === 'force_local' || lodash.isEqual(target.members, remote.members)) {
74781             return target;
74782         }
74783         if (option === 'force_remote') {
74784             return target.update({members: remote.members});
74785         }
74786
74787         conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
74788         return target;
74789     }
74790
74791
74792     function mergeTags(base, remote, target) {
74793         function ignoreKey(k) {
74794             return lodash.includes(dataDiscarded, k);
74795         }
74796
74797         if (option === 'force_local' || lodash.isEqual(target.tags, remote.tags)) {
74798             return target;
74799         }
74800         if (option === 'force_remote') {
74801             return target.update({tags: remote.tags});
74802         }
74803
74804         var ccount = conflicts.length,
74805             o = base.tags || {},
74806             a = target.tags || {},
74807             b = remote.tags || {},
74808             keys = lodash.reject(lodash.union(lodash.keys(o), lodash.keys(a), lodash.keys(b)), ignoreKey),
74809             tags = lodash.clone(a),
74810             changed = false;
74811
74812         for (var i = 0; i < keys.length; i++) {
74813             var k = keys[i];
74814
74815             if (o[k] !== b[k] && a[k] !== b[k]) {    // changed remotely..
74816                 if (o[k] !== a[k]) {      // changed locally..
74817                     conflicts.push(t('merge_remote_changes.conflict.tags',
74818                         { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
74819
74820                 } else {                  // unchanged locally, accept remote change..
74821                     if (b.hasOwnProperty(k)) {
74822                         tags[k] = b[k];
74823                     } else {
74824                         delete tags[k];
74825                     }
74826                     changed = true;
74827                 }
74828             }
74829         }
74830
74831         return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
74832     }
74833
74834
74835     //  `graph.base()` is the common ancestor of the two graphs.
74836     //  `localGraph` contains user's edits up to saving
74837     //  `remoteGraph` contains remote edits to modified nodes
74838     //  `graph` must be a descendent of `localGraph` and may include
74839     //      some conflict resolution actions performed on it.
74840     //
74841     //                  --- ... --- `localGraph` -- ... -- `graph`
74842     //                 /
74843     //  `graph.base()` --- ... --- `remoteGraph`
74844     //
74845     var action = function(graph) {
74846         var updates = { replacements: [], removeIds: [] },
74847             base = graph.base().entities[id],
74848             local = localGraph.entity(id),
74849             remote = remoteGraph.entity(id),
74850             target = osmEntity$$1(local, { version: remote.version });
74851
74852         // delete/undelete
74853         if (!remote.visible) {
74854             if (option === 'force_remote') {
74855                 return actionDeleteMultiple([id])(graph);
74856
74857             } else if (option === 'force_local') {
74858                 if (target.type === 'way') {
74859                     target = mergeChildren(target, lodash.uniq(local.nodes), updates, graph);
74860                     graph = updateChildren(updates, graph);
74861                 }
74862                 return graph.replace(target);
74863
74864             } else {
74865                 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
74866                 return graph;  // do nothing
74867             }
74868         }
74869
74870         // merge
74871         if (target.type === 'node') {
74872             target = mergeLocation(remote, target);
74873
74874         } else if (target.type === 'way') {
74875             // pull in any child nodes that may not be present locally..
74876             graph.rebase(remoteGraph.childNodes(remote), [graph], false);
74877             target = mergeNodes(base, remote, target);
74878             target = mergeChildren(target, lodash.union(local.nodes, remote.nodes), updates, graph);
74879
74880         } else if (target.type === 'relation') {
74881             target = mergeMembers(remote, target);
74882         }
74883
74884         target = mergeTags(base, remote, target);
74885
74886         if (!conflicts.length) {
74887             graph = updateChildren(updates, graph).replace(target);
74888         }
74889
74890         return graph;
74891     };
74892
74893
74894     action.withOption = function(opt) {
74895         option = opt;
74896         return action;
74897     };
74898
74899
74900     action.conflicts = function() {
74901         return conflicts;
74902     };
74903
74904
74905     return action;
74906 }
74907
74908 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
74909 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
74910 function actionMove(moveIds, tryDelta, projection, cache) {
74911     var delta = tryDelta;
74912
74913     function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
74914     function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
74915
74916     function setupCache(graph) {
74917         function canMove(nodeId) {
74918             // Allow movement of any node that is in the selectedIDs list..
74919             if (moveIds.indexOf(nodeId) !== -1) return true;
74920
74921             // Allow movement of a vertex where 2 ways meet..
74922             var parents = lodash.map(graph.parentWays(graph.entity(nodeId)), 'id');
74923             if (parents.length < 3) return true;
74924
74925             // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
74926             var parentsMoving = lodash.every(parents, function(id) { return cache.moving[id]; });
74927             if (!parentsMoving) delete cache.moving[nodeId];
74928
74929             return parentsMoving;
74930         }
74931
74932         function cacheEntities(ids) {
74933             ids.forEach(function(id) {
74934                 if (cache.moving[id]) return;
74935                 cache.moving[id] = true;
74936
74937                 var entity = graph.hasEntity(id);
74938                 if (!entity) return;
74939
74940                 if (entity.type === 'node') {
74941                     cache.nodes.push(id);
74942                     cache.startLoc[id] = entity.loc;
74943                 } else if (entity.type === 'way') {
74944                     cache.ways.push(id);
74945                     cacheEntities(entity.nodes);
74946                 } else {
74947                     cacheEntities(entity.members.map(function(member) {
74948                         return member.id;
74949                     }));
74950                 }
74951             });
74952         }
74953
74954         function cacheIntersections(ids) {
74955             function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
74956
74957             ids.forEach(function(id) {
74958                 // consider only intersections with 1 moved and 1 unmoved way.
74959                 var childNodes = graph.childNodes(graph.entity(id));
74960                 childNodes.forEach(function(node) {
74961                     var parents = graph.parentWays(node);
74962                     if (parents.length !== 2) return;
74963
74964                     var moved = graph.entity(id),
74965                         unmoved = lodash.find(parents, function(way) { return !cache.moving[way.id]; });
74966                     if (!unmoved) return;
74967
74968                     // exclude ways that are overly connected..
74969                     if (lodash.intersection(moved.nodes, unmoved.nodes).length > 2) return;
74970
74971                     if (moved.isArea() || unmoved.isArea()) return;
74972
74973                     cache.intersection[node.id] = {
74974                         nodeId: node.id,
74975                         movedId: moved.id,
74976                         unmovedId: unmoved.id,
74977                         movedIsEP: isEndpoint(moved, node.id),
74978                         unmovedIsEP: isEndpoint(unmoved, node.id)
74979                     };
74980                 });
74981             });
74982         }
74983
74984
74985         if (!cache) {
74986             cache = {};
74987         }
74988         if (!cache.ok) {
74989             cache.moving = {};
74990             cache.intersection = {};
74991             cache.replacedVertex = {};
74992             cache.startLoc = {};
74993             cache.nodes = [];
74994             cache.ways = [];
74995
74996             cacheEntities(moveIds);
74997             cacheIntersections(cache.ways);
74998             cache.nodes = lodash.filter(cache.nodes, canMove);
74999
75000             cache.ok = true;
75001         }
75002     }
75003
75004
75005     // Place a vertex where the moved vertex used to be, to preserve way shape..
75006     function replaceMovedVertex(nodeId, wayId, graph, delta) {
75007         var way = graph.entity(wayId),
75008             moved = graph.entity(nodeId),
75009             movedIndex = way.nodes.indexOf(nodeId),
75010             len, prevIndex, nextIndex;
75011
75012         if (way.isClosed()) {
75013             len = way.nodes.length - 1;
75014             prevIndex = (movedIndex + len - 1) % len;
75015             nextIndex = (movedIndex + len + 1) % len;
75016         } else {
75017             len = way.nodes.length;
75018             prevIndex = movedIndex - 1;
75019             nextIndex = movedIndex + 1;
75020         }
75021
75022         var prev = graph.hasEntity(way.nodes[prevIndex]),
75023             next = graph.hasEntity(way.nodes[nextIndex]);
75024
75025         // Don't add orig vertex at endpoint..
75026         if (!prev || !next) return graph;
75027
75028         var key = wayId + '_' + nodeId,
75029             orig = cache.replacedVertex[key];
75030         if (!orig) {
75031             orig = osmNode();
75032             cache.replacedVertex[key] = orig;
75033             cache.startLoc[orig.id] = cache.startLoc[nodeId];
75034         }
75035
75036         var start, end;
75037         if (delta) {
75038             start = projection(cache.startLoc[nodeId]);
75039             end = projection.invert(vecAdd(start, delta));
75040         } else {
75041             end = cache.startLoc[nodeId];
75042         }
75043         orig = orig.move(end);
75044
75045         var angle = Math.abs(geoAngle(orig, prev, projection) -
75046                 geoAngle(orig, next, projection)) * 180 / Math.PI;
75047
75048         // Don't add orig vertex if it would just make a straight line..
75049         if (angle > 175 && angle < 185) return graph;
75050
75051         // Don't add orig vertex if another point is already nearby (within 10m)
75052         if (geoSphericalDistance(prev.loc, orig.loc) < 10 ||
75053             geoSphericalDistance(orig.loc, next.loc) < 10) return graph;
75054
75055         // moving forward or backward along way?
75056         var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
75057             p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
75058             d1 = geoPathLength(p1),
75059             d2 = geoPathLength(p2),
75060             insertAt = (d1 < d2) ? movedIndex : nextIndex;
75061
75062         // moving around closed loop?
75063         if (way.isClosed() && insertAt === 0) insertAt = len;
75064
75065         way = way.addNode(orig.id, insertAt);
75066         return graph.replace(orig).replace(way);
75067     }
75068
75069
75070     // Reorder nodes around intersections that have moved..
75071     function unZorroIntersection(intersection, graph) {
75072         var vertex = graph.entity(intersection.nodeId),
75073             way1 = graph.entity(intersection.movedId),
75074             way2 = graph.entity(intersection.unmovedId),
75075             isEP1 = intersection.movedIsEP,
75076             isEP2 = intersection.unmovedIsEP;
75077
75078         // don't move the vertex if it is the endpoint of both ways.
75079         if (isEP1 && isEP2) return graph;
75080
75081         var nodes1 = lodash.without(graph.childNodes(way1), vertex),
75082             nodes2 = lodash.without(graph.childNodes(way2), vertex);
75083
75084         if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
75085         if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
75086
75087         var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection),
75088             edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection),
75089             loc;
75090
75091         // snap vertex to nearest edge (or some point between them)..
75092         if (!isEP1 && !isEP2) {
75093             var epsilon = 1e-4, maxIter = 10;
75094             for (var i = 0; i < maxIter; i++) {
75095                 loc = geoInterp(edge1.loc, edge2.loc, 0.5);
75096                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
75097                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
75098                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
75099             }
75100         } else if (!isEP1) {
75101             loc = edge1.loc;
75102         } else {
75103             loc = edge2.loc;
75104         }
75105
75106         graph = graph.replace(vertex.move(loc));
75107
75108         // if zorro happened, reorder nodes..
75109         if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
75110             way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
75111             graph = graph.replace(way1);
75112         }
75113         if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
75114             way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
75115             graph = graph.replace(way2);
75116         }
75117
75118         return graph;
75119     }
75120
75121
75122     function cleanupIntersections(graph) {
75123         lodash.each(cache.intersection, function(obj) {
75124             graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
75125             graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
75126             graph = unZorroIntersection(obj, graph);
75127         });
75128
75129         return graph;
75130     }
75131
75132
75133     // check if moving way endpoint can cross an unmoved way, if so limit delta..
75134     function limitDelta(graph) {
75135         lodash.each(cache.intersection, function(obj) {
75136             // Don't limit movement if this is vertex joins 2 endpoints..
75137             if (obj.movedIsEP && obj.unmovedIsEP) return;
75138             // Don't limit movement if this vertex is not an endpoint anyway..
75139             if (!obj.movedIsEP) return;
75140
75141             var node = graph.entity(obj.nodeId),
75142                 start = projection(node.loc),
75143                 end = vecAdd(start, delta),
75144                 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
75145                 movedPath = lodash.map(lodash.map(movedNodes, 'loc'),
75146                     function(loc) { return vecAdd(projection(loc), delta); }),
75147                 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
75148                 unmovedPath = lodash.map(lodash.map(unmovedNodes, 'loc'), projection),
75149                 hits = geoPathIntersections(movedPath, unmovedPath);
75150
75151             for (var i = 0; i < hits.length; i++) {
75152                 if (lodash.isEqual(hits[i], end)) continue;
75153                 var edge = geoChooseEdge(unmovedNodes, end, projection);
75154                 delta = vecSub(projection(edge.loc), start);
75155             }
75156         });
75157     }
75158
75159
75160     var action = function(graph) {
75161         if (delta[0] === 0 && delta[1] === 0) return graph;
75162
75163         setupCache(graph);
75164
75165         if (!lodash.isEmpty(cache.intersection)) {
75166             limitDelta(graph);
75167         }
75168
75169         lodash.each(cache.nodes, function(id) {
75170             var node = graph.entity(id),
75171                 start = projection(node.loc),
75172                 end = vecAdd(start, delta);
75173             graph = graph.replace(node.move(projection.invert(end)));
75174         });
75175
75176         if (!lodash.isEmpty(cache.intersection)) {
75177             graph = cleanupIntersections(graph);
75178         }
75179
75180         return graph;
75181     };
75182
75183
75184     action.delta = function() {
75185         return delta;
75186     };
75187
75188
75189     return action;
75190 }
75191
75192 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
75193 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
75194 function actionMoveNode(nodeId, loc) {
75195     return function(graph) {
75196         return graph.replace(graph.entity(nodeId).move(loc));
75197     };
75198 }
75199
75200 function actionNoop() {
75201     return function(graph) {
75202         return graph;
75203     };
75204 }
75205
75206 /*
75207  * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
75208  */
75209 function actionOrthogonalize(wayId, projection) {
75210     var threshold = 12, // degrees within right or straight to alter
75211         lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
75212         upperThreshold = Math.cos(threshold * Math.PI / 180);
75213
75214
75215     var action = function(graph, t) {
75216         if (t === null || !isFinite(t)) t = 1;
75217         t = Math.min(Math.max(+t, 0), 1);
75218
75219         var way = graph.entity(wayId),
75220             nodes = graph.childNodes(way),
75221             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); }),
75222             corner = {i: 0, dotp: 1},
75223             epsilon = 1e-4,
75224             node, loc, score, motions, i, j;
75225
75226         if (points.length === 3) {   // move only one vertex for right triangle
75227             for (i = 0; i < 1000; i++) {
75228                 motions = points.map(calcMotion);
75229                 points[corner.i] = addPoints(points[corner.i], motions[corner.i]);
75230                 score = corner.dotp;
75231                 if (score < epsilon) {
75232                     break;
75233                 }
75234             }
75235
75236             node = graph.entity(nodes[corner.i].id);
75237             loc = projection.invert(points[corner.i]);
75238             graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
75239
75240         } else {
75241             var best,
75242                 originalPoints = lodash.clone(points);
75243             score = Infinity;
75244
75245             for (i = 0; i < 1000; i++) {
75246                 motions = points.map(calcMotion);
75247                 for (j = 0; j < motions.length; j++) {
75248                     points[j] = addPoints(points[j],motions[j]);
75249                 }
75250                 var newScore = squareness(points);
75251                 if (newScore < score) {
75252                     best = lodash.clone(points);
75253                     score = newScore;
75254                 }
75255                 if (score < epsilon) {
75256                     break;
75257                 }
75258             }
75259
75260             points = best;
75261
75262             for (i = 0; i < points.length; i++) {
75263                 // only move the points that actually moved
75264                 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
75265                     loc = projection.invert(points[i]);
75266                     node = graph.entity(nodes[i].id);
75267                     graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
75268                 }
75269             }
75270
75271             // remove empty nodes on straight sections
75272             for (i = 0; t === 1 && i < points.length; i++) {
75273                 node = graph.entity(nodes[i].id);
75274
75275                 if (graph.parentWays(node).length > 1 ||
75276                     graph.parentRelations(node).length ||
75277                     node.hasInterestingTags()) {
75278                     continue;
75279                 }
75280
75281                 var dotp = normalizedDotProduct(i, points);
75282                 if (dotp < -1 + epsilon) {
75283                     graph = actionDeleteNode(node.id)(graph);
75284                 }
75285             }
75286         }
75287
75288         return graph;
75289
75290
75291         function calcMotion(b, i, array) {
75292             var a = array[(i - 1 + array.length) % array.length],
75293                 c = array[(i + 1) % array.length],
75294                 p = subtractPoints(a, b),
75295                 q = subtractPoints(c, b),
75296                 scale, dotp;
75297
75298             scale = 2 * Math.min(geoEuclideanDistance(p, [0, 0]), geoEuclideanDistance(q, [0, 0]));
75299             p = normalizePoint(p, 1.0);
75300             q = normalizePoint(q, 1.0);
75301
75302             dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
75303
75304             // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
75305             if (array.length > 3) {
75306                 if (dotp < -0.707106781186547) {
75307                     dotp += 1.0;
75308                 }
75309             } else if (dotp && Math.abs(dotp) < corner.dotp) {
75310                 corner.i = i;
75311                 corner.dotp = Math.abs(dotp);
75312             }
75313
75314             return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
75315         }
75316     };
75317
75318
75319     function squareness(points) {
75320         return points.reduce(function(sum, val, i, array) {
75321             var dotp = normalizedDotProduct(i, array);
75322
75323             dotp = filterDotProduct(dotp);
75324             return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
75325         }, 0);
75326     }
75327
75328
75329     function normalizedDotProduct(i, points) {
75330         var a = points[(i - 1 + points.length) % points.length],
75331             b = points[i],
75332             c = points[(i + 1) % points.length],
75333             p = subtractPoints(a, b),
75334             q = subtractPoints(c, b);
75335
75336         p = normalizePoint(p, 1.0);
75337         q = normalizePoint(q, 1.0);
75338
75339         return p[0] * q[0] + p[1] * q[1];
75340     }
75341
75342
75343     function subtractPoints(a, b) {
75344         return [a[0] - b[0], a[1] - b[1]];
75345     }
75346
75347
75348     function addPoints(a, b) {
75349         return [a[0] + b[0], a[1] + b[1]];
75350     }
75351
75352
75353     function normalizePoint(point, scale) {
75354         var vector = [0, 0];
75355         var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
75356         if (length !== 0) {
75357             vector[0] = point[0] / length;
75358             vector[1] = point[1] / length;
75359         }
75360
75361         vector[0] *= scale;
75362         vector[1] *= scale;
75363
75364         return vector;
75365     }
75366
75367
75368     function filterDotProduct(dotp) {
75369         if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
75370             return dotp;
75371         }
75372
75373         return 0;
75374     }
75375
75376
75377     action.disabled = function(graph) {
75378         var way = graph.entity(wayId),
75379             nodes = graph.childNodes(way),
75380             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); });
75381
75382         if (squareness(points)) {
75383             return false;
75384         }
75385
75386         return 'not_squarish';
75387     };
75388
75389
75390     action.transitionable = true;
75391
75392
75393     return action;
75394 }
75395
75396 // Split a way at the given node.
75397 //
75398 // Optionally, split only the given ways, if multiple ways share
75399 // the given node.
75400 //
75401 // This is the inverse of `iD.actionJoin`.
75402 //
75403 // For testing convenience, accepts an ID to assign to the new way.
75404 // Normally, this will be undefined and the way will automatically
75405 // be assigned a new ID.
75406 //
75407 // Reference:
75408 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
75409 //
75410 function actionSplit(nodeId, newWayIds) {
75411     var wayIds;
75412
75413     // if the way is closed, we need to search for a partner node
75414     // to split the way at.
75415     //
75416     // The following looks for a node that is both far away from
75417     // the initial node in terms of way segment length and nearby
75418     // in terms of beeline-distance. This assures that areas get
75419     // split on the most "natural" points (independent of the number
75420     // of nodes).
75421     // For example: bone-shaped areas get split across their waist
75422     // line, circles across the diameter.
75423     function splitArea(nodes, idxA, graph) {
75424         var lengths = new Array(nodes.length),
75425             length,
75426             i,
75427             best = 0,
75428             idxB;
75429
75430         function wrap(index) {
75431             return utilWrap(index, nodes.length);
75432         }
75433
75434         function dist(nA, nB) {
75435             return geoSphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
75436         }
75437
75438         // calculate lengths
75439         length = 0;
75440         for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
75441             length += dist(nodes[i], nodes[wrap(i-1)]);
75442             lengths[i] = length;
75443         }
75444
75445         length = 0;
75446         for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
75447             length += dist(nodes[i], nodes[wrap(i+1)]);
75448             if (length < lengths[i])
75449                 lengths[i] = length;
75450         }
75451
75452         // determine best opposite node to split
75453         for (i = 0; i < nodes.length; i++) {
75454             var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
75455             if (cost > best) {
75456                 idxB = i;
75457                 best = cost;
75458             }
75459         }
75460
75461         return idxB;
75462     }
75463
75464
75465     function split(graph, wayA, newWayId) {
75466         var wayB = osmWay({id: newWayId, tags: wayA.tags}),
75467             nodesA,
75468             nodesB,
75469             isArea = wayA.isArea(),
75470             isOuter = osmIsSimpleMultipolygonOuterMember(wayA, graph);
75471
75472         if (wayA.isClosed()) {
75473             var nodes = wayA.nodes.slice(0, -1),
75474                 idxA = lodash.indexOf(nodes, nodeId),
75475                 idxB = splitArea(nodes, idxA, graph);
75476
75477             if (idxB < idxA) {
75478                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
75479                 nodesB = nodes.slice(idxB, idxA + 1);
75480             } else {
75481                 nodesA = nodes.slice(idxA, idxB + 1);
75482                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
75483             }
75484         } else {
75485             var idx = lodash.indexOf(wayA.nodes, nodeId, 1);
75486             nodesA = wayA.nodes.slice(0, idx + 1);
75487             nodesB = wayA.nodes.slice(idx);
75488         }
75489
75490         wayA = wayA.update({nodes: nodesA});
75491         wayB = wayB.update({nodes: nodesB});
75492
75493         graph = graph.replace(wayA);
75494         graph = graph.replace(wayB);
75495
75496         graph.parentRelations(wayA).forEach(function(relation) {
75497             if (relation.isRestriction()) {
75498                 var via = relation.memberByRole('via');
75499                 if (via && wayB.contains(via.id)) {
75500                     relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
75501                     graph = graph.replace(relation);
75502                 }
75503             } else {
75504                 if (relation === isOuter) {
75505                     graph = graph.replace(relation.mergeTags(wayA.tags));
75506                     graph = graph.replace(wayA.update({tags: {}}));
75507                     graph = graph.replace(wayB.update({tags: {}}));
75508                 }
75509
75510                 var member = {
75511                     id: wayB.id,
75512                     type: 'way',
75513                     role: relation.memberById(wayA.id).role
75514                 };
75515
75516                 graph = actionAddMember(relation.id, member)(graph);
75517             }
75518         });
75519
75520         if (!isOuter && isArea) {
75521             var multipolygon = osmRelation({
75522                 tags: lodash.extend({}, wayA.tags, {type: 'multipolygon'}),
75523                 members: [
75524                     {id: wayA.id, role: 'outer', type: 'way'},
75525                     {id: wayB.id, role: 'outer', type: 'way'}
75526                 ]});
75527
75528             graph = graph.replace(multipolygon);
75529             graph = graph.replace(wayA.update({tags: {}}));
75530             graph = graph.replace(wayB.update({tags: {}}));
75531         }
75532
75533         return graph;
75534     }
75535
75536
75537     var action = function(graph) {
75538         var candidates = action.ways(graph);
75539         for (var i = 0; i < candidates.length; i++) {
75540             graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
75541         }
75542         return graph;
75543     };
75544
75545
75546     action.ways = function(graph) {
75547         var node = graph.entity(nodeId),
75548             parents = graph.parentWays(node),
75549             hasLines = lodash.some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
75550
75551         return parents.filter(function(parent) {
75552             if (wayIds && wayIds.indexOf(parent.id) === -1)
75553                 return false;
75554
75555             if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
75556                 return false;
75557
75558             if (parent.isClosed()) {
75559                 return true;
75560             }
75561
75562             for (var i = 1; i < parent.nodes.length - 1; i++) {
75563                 if (parent.nodes[i] === nodeId) {
75564                     return true;
75565                 }
75566             }
75567
75568             return false;
75569         });
75570     };
75571
75572
75573     action.disabled = function(graph) {
75574         var candidates = action.ways(graph);
75575         if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
75576             return 'not_eligible';
75577     };
75578
75579
75580     action.limitWays = function(_) {
75581         if (!arguments.length) return wayIds;
75582         wayIds = _;
75583         return action;
75584     };
75585
75586
75587     return action;
75588 }
75589
75590 // Create a restriction relation for `turn`, which must have the following structure:
75591 //
75592 //     {
75593 //         from: { node: <node ID>, way: <way ID> },
75594 //         via:  { node: <node ID> },
75595 //         to:   { node: <node ID>, way: <way ID> },
75596 //         restriction: <'no_right_turn', 'no_left_turn', etc.>
75597 //     }
75598 //
75599 // This specifies a restriction of type `restriction` when traveling from
75600 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
75601 // (The action does not check that these entities form a valid intersection.)
75602 //
75603 // If `restriction` is not provided, it is automatically determined by
75604 // osmInferRestriction.
75605 //
75606 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
75607 // and `to.node` are used to determine which portion of the split ways become
75608 // members of the restriction.
75609 //
75610 // For testing convenience, accepts an ID to assign to the new relation.
75611 // Normally, this will be undefined and the relation will automatically
75612 // be assigned a new ID.
75613 //
75614 function actionRestrictTurn(turn, projection, restrictionId) {
75615
75616     return function(graph) {
75617         var from = graph.entity(turn.from.way),
75618             via  = graph.entity(turn.via.node),
75619             to   = graph.entity(turn.to.way);
75620
75621         function isClosingNode(way, nodeId) {
75622             return nodeId === way.first() && nodeId === way.last();
75623         }
75624
75625         function split(toOrFrom) {
75626             var newID = toOrFrom.newID || osmWay().id;
75627             graph = actionSplit(via.id, [newID])
75628                 .limitWays([toOrFrom.way])(graph);
75629
75630             var a = graph.entity(newID),
75631                 b = graph.entity(toOrFrom.way);
75632
75633             if (a.nodes.indexOf(toOrFrom.node) !== -1) {
75634                 return [a, b];
75635             } else {
75636                 return [b, a];
75637             }
75638         }
75639
75640         if (!from.affix(via.id) || isClosingNode(from, via.id)) {
75641             if (turn.from.node === turn.to.node) {
75642                 // U-turn
75643                 from = to = split(turn.from)[0];
75644             } else if (turn.from.way === turn.to.way) {
75645                 // Straight-on or circular
75646                 var s = split(turn.from);
75647                 from = s[0];
75648                 to   = s[1];
75649             } else {
75650                 // Other
75651                 from = split(turn.from)[0];
75652             }
75653         }
75654
75655         if (!to.affix(via.id) || isClosingNode(to, via.id)) {
75656             to = split(turn.to)[0];
75657         }
75658
75659         return graph.replace(osmRelation({
75660             id: restrictionId,
75661             tags: {
75662                 type: 'restriction',
75663                 restriction: turn.restriction ||
75664                     osmInferRestriction(
75665                         graph,
75666                         turn.from,
75667                         turn.via,
75668                         turn.to,
75669                         projection)
75670             },
75671             members: [
75672                 {id: from.id, type: 'way',  role: 'from'},
75673                 {id: via.id,  type: 'node', role: 'via'},
75674                 {id: to.id,   type: 'way',  role: 'to'}
75675             ]
75676         }));
75677     };
75678 }
75679
75680 function actionRevert(id) {
75681     var action = function(graph) {
75682         var entity = graph.hasEntity(id),
75683             base = graph.base().entities[id];
75684
75685         if (entity && !base) {    // entity will be removed..
75686             if (entity.type === 'node') {
75687                 graph.parentWays(entity)
75688                     .forEach(function(parent) {
75689                         parent = parent.removeNode(id);
75690                         graph = graph.replace(parent);
75691
75692                         if (parent.isDegenerate()) {
75693                             graph = actionDeleteWay(parent.id)(graph);
75694                         }
75695                     });
75696             }
75697
75698             graph.parentRelations(entity)
75699                 .forEach(function(parent) {
75700                     parent = parent.removeMembersWithID(id);
75701                     graph = graph.replace(parent);
75702
75703                     if (parent.isDegenerate()) {
75704                         graph = actionDeleteRelation(parent.id)(graph);
75705                     }
75706                 });
75707         }
75708
75709         return graph.revert(id);
75710     };
75711
75712     return action;
75713 }
75714
75715 function actionRotate(rotateIds, pivot, angle, projection) {
75716
75717     var action = function(graph) {
75718         return graph.update(function(graph) {
75719             utilGetAllNodes(rotateIds, graph).forEach(function(node) {
75720                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
75721                 graph = graph.replace(node.move(projection.invert(point)));
75722             });
75723         });
75724     };
75725
75726     return action;
75727 }
75728
75729 /*
75730  * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
75731  */
75732 function actionStraighten(wayId, projection) {
75733
75734     function positionAlongWay(n, s, e) {
75735         return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1])) /
75736                 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
75737     }
75738
75739
75740     var action = function(graph, t) {
75741         if (t === null || !isFinite(t)) t = 1;
75742         t = Math.min(Math.max(+t, 0), 1);
75743
75744         var way = graph.entity(wayId),
75745             nodes = graph.childNodes(way),
75746             points = nodes.map(function(n) { return projection(n.loc); }),
75747             startPoint = points[0],
75748             endPoint = points[points.length-1],
75749             toDelete = [],
75750             i;
75751
75752         for (i = 1; i < points.length-1; i++) {
75753             var node = nodes[i],
75754                 point = points[i];
75755
75756             if (t < 1 || graph.parentWays(node).length > 1 ||
75757                 graph.parentRelations(node).length ||
75758                 node.hasInterestingTags()) {
75759
75760                 var u = positionAlongWay(point, startPoint, endPoint),
75761                     p = [
75762                         startPoint[0] + u * (endPoint[0] - startPoint[0]),
75763                         startPoint[1] + u * (endPoint[1] - startPoint[1])
75764                     ],
75765                     loc2 = projection.invert(p);
75766
75767                 graph = graph.replace(node.move(geoInterp(node.loc, loc2, t)));
75768
75769             } else {
75770                 // safe to delete
75771                 if (toDelete.indexOf(node) === -1) {
75772                     toDelete.push(node);
75773                 }
75774             }
75775         }
75776
75777         for (i = 0; i < toDelete.length; i++) {
75778             graph = actionDeleteNode(toDelete[i].id)(graph);
75779         }
75780
75781         return graph;
75782     };
75783
75784
75785     action.disabled = function(graph) {
75786         // check way isn't too bendy
75787         var way = graph.entity(wayId),
75788             nodes = graph.childNodes(way),
75789             points = nodes.map(function(n) { return projection(n.loc); }),
75790             startPoint = points[0],
75791             endPoint = points[points.length-1],
75792             threshold = 0.2 * geoEuclideanDistance(startPoint, endPoint),
75793             i;
75794
75795         if (threshold === 0) {
75796             return 'too_bendy';
75797         }
75798
75799         for (i = 1; i < points.length-1; i++) {
75800             var point = points[i],
75801                 u = positionAlongWay(point, startPoint, endPoint),
75802                 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
75803                 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
75804                 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
75805
75806             // to bendy if point is off by 20% of total start/end distance in projected space
75807             if (isNaN(dist) || dist > threshold) {
75808                 return 'too_bendy';
75809             }
75810         }
75811     };
75812
75813
75814     action.transitionable = true;
75815
75816
75817     return action;
75818 }
75819
75820 // Remove the effects of `turn.restriction` on `turn`, which must have the
75821 // following structure:
75822 //
75823 //     {
75824 //         from: { node: <node ID>, way: <way ID> },
75825 //         via:  { node: <node ID> },
75826 //         to:   { node: <node ID>, way: <way ID> },
75827 //         restriction: <relation ID>
75828 //     }
75829 //
75830 // In the simple case, `restriction` is a reference to a `no_*` restriction
75831 // on the turn itself. In this case, it is simply deleted.
75832 //
75833 // The more complex case is where `restriction` references an `only_*`
75834 // restriction on a different turn in the same intersection. In that case,
75835 // that restriction is also deleted, but at the same time restrictions on
75836 // the turns other than the first two are created.
75837 //
75838 function actionUnrestrictTurn(turn) {
75839     return function(graph) {
75840         return actionDeleteRelation(turn.restriction)(graph);
75841     };
75842 }
75843
75844 /* Reflect the given area around its axis of symmetry */
75845 function actionReflect(reflectIds, projection) {
75846     var useLongAxis = true;
75847
75848
75849     // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
75850     // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
75851     function getSmallestSurroundingRectangle(graph, nodes) {
75852         var points = nodes.map(function(n) { return projection(n.loc); }),
75853             hull = d3polygonHull(points),
75854             centroid = d3polygonCentroid(hull),
75855             minArea = Infinity,
75856             ssrExtent = [],
75857             ssrAngle = 0,
75858             c1 = hull[0];
75859
75860         for (var i = 0; i < hull.length - 1; i++) {
75861             var c2 = hull[i + 1],
75862                 angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]),
75863                 poly = geoRotate(hull, -angle, centroid),
75864                 extent$$1 = poly.reduce(function(extent$$1, point) {
75865                         return extent$$1.extend(geoExtent$$1(point));
75866                     }, geoExtent$$1()),
75867                 area$$1 = extent$$1.area();
75868
75869             if (area$$1 < minArea) {
75870                 minArea = area$$1;
75871                 ssrExtent = extent$$1;
75872                 ssrAngle = angle;
75873             }
75874             c1 = c2;
75875         }
75876
75877         return {
75878             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
75879             angle: ssrAngle
75880         };
75881     }
75882
75883
75884     var action = function(graph, t) {
75885         if (t === null || !isFinite(t)) t = 1;
75886         t = Math.min(Math.max(+t, 0), 1);
75887
75888         var nodes = utilGetAllNodes(reflectIds, graph),
75889             ssr = getSmallestSurroundingRectangle(graph, nodes);
75890
75891         // Choose line pq = axis of symmetry.
75892         // The shape's surrounding rectangle has 2 axes of symmetry.
75893         // Reflect across the longer axis by default.
75894         var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2 ],
75895             q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2 ],
75896             p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2 ],
75897             q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2 ],
75898             p, q;
75899
75900         var isLong = (geoEuclideanDistance(p1, q1) > geoEuclideanDistance(p2, q2));
75901         if ((useLongAxis && isLong) || (!useLongAxis && !isLong)) {
75902             p = p1;
75903             q = q1;
75904         } else {
75905             p = p2;
75906             q = q2;
75907         }
75908
75909         // reflect c across pq
75910         // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
75911         var dx = q[0] - p[0];
75912         var dy = q[1] - p[1];
75913         var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
75914         var b = 2 * dx * dy / (dx * dx + dy * dy);
75915         for (var i = 0; i < nodes.length; i++) {
75916             var node = nodes[i];
75917             var c = projection(node.loc);
75918             var c2 = [
75919                 a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0],
75920                 b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]
75921             ];
75922             var loc2 = projection.invert(c2);
75923             node = node.move(geoInterp(node.loc, loc2, t));
75924             graph = graph.replace(node);
75925         }
75926
75927         return graph;
75928     };
75929
75930
75931     action.useLongAxis = function(_) {
75932         if (!arguments.length) return useLongAxis;
75933         useLongAxis = _;
75934         return action;
75935     };
75936
75937
75938     action.transitionable = true;
75939
75940
75941     return action;
75942 }
75943
75944
75945
75946 var index$17 = Object.freeze({
75947         d3combobox: d3combobox,
75948         d3geoTile: d3geoTile,
75949         d3keybinding: d3keybinding
75950 });
75951
75952 /* export some legacy symbols: */
75953 var Connection = services.osm;
75954 var debug = false;
75955
75956
75957
75958
75959 var iD = Object.freeze({
75960         Connection: Connection,
75961         debug: debug,
75962         d3: index$2,
75963         _: lodash$1,
75964         lib: index$17,
75965         Context: coreContext,
75966         setAreaKeys: setAreaKeys,
75967         Difference: coreDifference,
75968         Graph: coreGraph$$1,
75969         History: coreHistory,
75970         Tree: coreTree,
75971         Entity: osmEntity$$1,
75972         Node: osmNode,
75973         Relation: osmRelation,
75974         Way: osmWay,
75975         BackgroundSource: rendererBackgroundSource,
75976         Background: rendererBackground,
75977         Features: rendererFeatures,
75978         Map: rendererMap,
75979         TileLayer: rendererTileLayer,
75980         Detect: utilDetect,
75981         actionAddEntity: actionAddEntity,
75982         actionAddMember: actionAddMember,
75983         actionAddMidpoint: actionAddMidpoint,
75984         actionAddVertex: actionAddVertex,
75985         actionChangeMember: actionChangeMember,
75986         actionChangePreset: actionChangePreset,
75987         actionChangeTags: actionChangeTags,
75988         actionCircularize: actionCircularize,
75989         actionConnect: actionConnect,
75990         actionCopyEntities: actionCopyEntities,
75991         actionDeleteMember: actionDeleteMember,
75992         actionDeleteMultiple: actionDeleteMultiple,
75993         actionDeleteNode: actionDeleteNode,
75994         actionDeleteRelation: actionDeleteRelation,
75995         actionDeleteWay: actionDeleteWay,
75996         actionDeprecateTags: actionDeprecateTags,
75997         actionDiscardTags: actionDiscardTags,
75998         actionDisconnect: actionDisconnect,
75999         actionJoin: actionJoin,
76000         actionMerge: actionMerge,
76001         actionMergePolygon: actionMergePolygon,
76002         actionMergeRemoteChanges: actionMergeRemoteChanges,
76003         actionMove: actionMove,
76004         actionMoveNode: actionMoveNode,
76005         actionNoop: actionNoop,
76006         actionOrthogonalize: actionOrthogonalize,
76007         actionRestrictTurn: actionRestrictTurn,
76008         actionReverse: actionReverse,
76009         actionRevert: actionRevert,
76010         actionRotate: actionRotate,
76011         actionSplit: actionSplit,
76012         actionStraighten: actionStraighten,
76013         actionUnrestrictTurn: actionUnrestrictTurn,
76014         actionReflect: actionReflect,
76015         behaviorAddWay: behaviorAddWay,
76016         behaviorBreathe: behaviorBreathe,
76017         behaviorCopy: behaviorCopy,
76018         behaviorDrag: behaviorDrag,
76019         behaviorDrawWay: behaviorDrawWay,
76020         behaviorDraw: behaviorDraw,
76021         behaviorEdit: behaviorEdit,
76022         behaviorHash: behaviorHash,
76023         behaviorHover: behaviorHover,
76024         behaviorLasso: behaviorLasso,
76025         behaviorOperation: behaviorOperation,
76026         behaviorPaste: behaviorPaste,
76027         behaviorSelect: behaviorSelect,
76028         behaviorTail: behaviorTail,
76029         coreContext: coreContext,
76030         coreDifference: coreDifference,
76031         coreGraph: coreGraph$$1,
76032         coreHistory: coreHistory,
76033         coreTree: coreTree,
76034         dataFeatureIcons: dataFeatureIcons,
76035         data: data,
76036         dataWikipedia: dataWikipedia,
76037         dataSuggestions: dataSuggestions,
76038         dataAddressFormats: dataAddressFormats,
76039         dataDeprecated: dataDeprecated,
76040         dataDiscarded: dataDiscarded,
76041         dataLocales: dataLocales,
76042         dataPhoneFormats: dataPhoneFormats,
76043         dataImperial: dataImperial,
76044         dataDriveLeft: dataDriveLeft,
76045         dataEn: en,
76046         geoAngle: geoAngle,
76047         geoChooseEdge: geoChooseEdge,
76048         geoCross: geoCross,
76049         geoEdgeEqual: geoEdgeEqual,
76050         geoEuclideanDistance: geoEuclideanDistance,
76051         geoExtent: geoExtent$$1,
76052         geoInterp: geoInterp,
76053         geoRawMercator: geoRawMercator,
76054         geoRoundCoords: geoRoundCoords,
76055         geoRotate: geoRotate,
76056         geoLatToMeters: geoLatToMeters,
76057         geoLineIntersection: geoLineIntersection,
76058         geoLonToMeters: geoLonToMeters,
76059         geoMetersToLat: geoMetersToLat,
76060         geoMetersToLon: geoMetersToLon,
76061         geoMetersToOffset: geoMetersToOffset,
76062         geoOffsetToMeters: geoOffsetToMeters,
76063         geoPathIntersections: geoPathIntersections,
76064         geoPathLength: geoPathLength,
76065         geoPointInPolygon: geoPointInPolygon,
76066         geoPolygonContainsPolygon: geoPolygonContainsPolygon,
76067         geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
76068         geoSphericalDistance: geoSphericalDistance,
76069         modeAddArea: modeAddArea$$1,
76070         modeAddLine: modeAddLine$$1,
76071         modeAddPoint: modeAddPoint$$1,
76072         modeBrowse: modeBrowse,
76073         modeDragNode: modeDragNode$$1,
76074         modeDrawArea: modeDrawArea,
76075         modeDrawLine: modeDrawLine,
76076         modeMove: modeMove$$1,
76077         modeRotate: modeRotate$$1,
76078         modeSave: modeSave$$1,
76079         modeSelect: modeSelect,
76080         operationCircularize: operationCircularize,
76081         operationContinue: operationContinue,
76082         operationDelete: operationDelete,
76083         operationDisconnect: operationDisconnect,
76084         operationMerge: operationMerge,
76085         operationMove: operationMove,
76086         operationOrthogonalize: operationOrthogonalize,
76087         operationReflectShort: operationReflectShort,
76088         operationReflectLong: operationReflectLong,
76089         operationReverse: operationReverse,
76090         operationRotate: operationRotate,
76091         operationSplit: operationSplit,
76092         operationStraighten: operationStraighten,
76093         osmChangeset: osmChangeset,
76094         osmEntity: osmEntity$$1,
76095         osmNode: osmNode,
76096         osmRelation: osmRelation,
76097         osmWay: osmWay,
76098         osmIntersection: osmIntersection,
76099         osmTurn: osmTurn,
76100         osmInferRestriction: osmInferRestriction,
76101         osmLanes: osmLanes,
76102         osmIsSimpleMultipolygonOuterMember: osmIsSimpleMultipolygonOuterMember,
76103         osmSimpleMultipolygonOuterMember: osmSimpleMultipolygonOuterMember,
76104         osmJoinWays: osmJoinWays,
76105         osmOneWayTags: osmOneWayTags,
76106         osmPavedTags: osmPavedTags,
76107         osmIsInterestingTag: osmIsInterestingTag,
76108         presetCategory: presetCategory,
76109         presetCollection: presetCollection,
76110         presetField: presetField,
76111         presetPreset: presetPreset,
76112         presetIndex: presetIndex,
76113         rendererBackgroundSource: rendererBackgroundSource,
76114         rendererBackground: rendererBackground,
76115         rendererFeatures: rendererFeatures,
76116         rendererMap: rendererMap,
76117         rendererTileLayer: rendererTileLayer,
76118         services: services,
76119         svgAreas: svgAreas$$1,
76120         svgDebug: svgDebug,
76121         svgDefs: svgDefs,
76122         svgGpx: svgGpx,
76123         svgIcon: svgIcon,
76124         svgLabels: svgLabels,
76125         svgLayers: svgLayers,
76126         svgLines: svgLines$$1,
76127         svgMapillaryImages: svgMapillaryImages,
76128         svgMapillarySigns: svgMapillarySigns,
76129         svgMidpoints: svgMidpoints$$1,
76130         svgOneWaySegments: svgOneWaySegments,
76131         svgOsm: svgOsm,
76132         svgPath: svgPath,
76133         svgPointTransform: svgPointTransform,
76134         svgPoints: svgPoints$$1,
76135         svgRelationMemberTags: svgRelationMemberTags,
76136         svgTagClasses: svgTagClasses,
76137         svgTurns: svgTurns,
76138         svgVertices: svgVertices$$1,
76139         uiFields: uiFields,
76140         uiFieldDefaultCheck: uiFieldCheck,
76141         uiFieldOnewayCheck: uiFieldCheck,
76142         uiFieldCheck: uiFieldCheck,
76143         uiFieldMultiCombo: uiFieldCombo,
76144         uiFieldNetworkCombo: uiFieldCombo,
76145         uiFieldSemiCombo: uiFieldCombo,
76146         uiFieldTypeCombo: uiFieldCombo,
76147         uiFieldCombo: uiFieldCombo,
76148         uiFieldUrl: uiFieldText,
76149         uiFieldNumber: uiFieldText,
76150         uiFieldTel: uiFieldText,
76151         uiFieldEmail: uiFieldText,
76152         uiFieldText: uiFieldText,
76153         uiFieldAccess: uiFieldAccess,
76154         uiFieldAddress: uiFieldAddress,
76155         uiFieldCycleway: uiFieldCycleway,
76156         uiFieldLanes: uiFieldLanes,
76157         uiFieldLocalized: uiFieldLocalized,
76158         uiFieldMaxspeed: uiFieldMaxspeed,
76159         uiFieldStructureRadio: uiFieldRadio,
76160         uiFieldRadio: uiFieldRadio,
76161         uiFieldRestrictions: uiFieldRestrictions,
76162         uiFieldTextarea: uiFieldTextarea,
76163         uiFieldWikipedia: uiFieldWikipedia,
76164         uiIntro: uiIntro,
76165         uiInit: uiInit,
76166         uiAccount: uiAccount,
76167         uiAttribution: uiAttribution,
76168         uiBackground: uiBackground,
76169         uiCmd: uiCmd,
76170         uiCommit: uiCommit,
76171         uiConfirm: uiConfirm,
76172         uiConflicts: uiConflicts,
76173         uiContributors: uiContributors,
76174         uiCurtain: uiCurtain,
76175         uiDisclosure: uiDisclosure,
76176         uiEditMenu: uiEditMenu,
76177         uiEntityEditor: uiEntityEditor,
76178         uiFeatureInfo: uiFeatureInfo,
76179         uiFeatureList: uiFeatureList,
76180         uiFlash: uiFlash,
76181         uiFullScreen: uiFullScreen,
76182         uiGeolocate: uiGeolocate,
76183         uiHelp: uiHelp,
76184         uiInfo: uiInfo,
76185         uiInspector: uiInspector,
76186         uiLasso: uiLasso,
76187         uiLoading: uiLoading,
76188         uiMapData: uiMapData,
76189         uiMapInMap: uiMapInMap,
76190         uiModal: uiModal,
76191         uiModes: uiModes,
76192         uiNotice: uiNotice,
76193         uiPreset: uiPreset,
76194         uiPresetIcon: uiPresetIcon,
76195         uiPresetList: uiPresetList,
76196         uiRadialMenu: uiRadialMenu,
76197         uiRawMemberEditor: uiRawMemberEditor,
76198         uiRawMembershipEditor: uiRawMembershipEditor,
76199         uiRawTagEditor: uiRawTagEditor,
76200         uiRestore: uiRestore,
76201         uiSave: uiSave,
76202         uiScale: uiScale,
76203         uiSelectionList: uiSelectionList,
76204         uiSidebar: uiSidebar,
76205         uiSourceSwitch: uiSourceSwitch,
76206         uiSpinner: uiSpinner,
76207         uiSplash: uiSplash,
76208         uiStatus: uiStatus,
76209         uiSuccess: uiSuccess,
76210         uiTagReference: uiTagReference,
76211         uiToggle: uiToggle,
76212         uiTooltipHtml: uiTooltipHtml,
76213         uiUndoRedo: uiUndoRedo,
76214         uiVersion: uiVersion,
76215         uiViewOnOSM: uiViewOnOSM,
76216         uiZoom: uiZoom,
76217         utilAsyncMap: utilAsyncMap,
76218         utilDisplayName: utilDisplayName,
76219         utilDisplayNameForPath: utilDisplayNameForPath,
76220         utilDisplayType: utilDisplayType,
76221         utilEditDistance: utilEditDistance,
76222         utilEntitySelector: utilEntitySelector,
76223         utilEntityOrMemberSelector: utilEntityOrMemberSelector,
76224         utilFastMouse: utilFastMouse,
76225         utilFunctor: utilFunctor,
76226         utilGetAllNodes: utilGetAllNodes,
76227         utilGetPrototypeOf: utilGetPrototypeOf,
76228         utilGetSetValue: utilGetSetValue,
76229         utilNoAuto: utilNoAuto,
76230         utilPrefixCSSProperty: utilPrefixCSSProperty,
76231         utilPrefixDOMProperty: utilPrefixDOMProperty,
76232         utilQsString: utilQsString,
76233         utilRebind: utilRebind,
76234         utilSetTransform: utilSetTransform,
76235         utilSessionMutex: utilSessionMutex,
76236         utilStringQs: utilStringQs,
76237         utilSuggestNames: utilSuggestNames,
76238         utilTagText: utilTagText,
76239         utilTriggerEvent: utilTriggerEvent,
76240         utilWrap: utilWrap,
76241         d3combobox: d3combobox,
76242         d3geoTile: d3geoTile,
76243         d3keybinding: d3keybinding,
76244         validationDeprecatedTag: validationDeprecatedTag,
76245         validationDisconnectedHighway: validationDisconnectedHighway,
76246         validationManyDeletions: validationManyDeletions,
76247         validationMissingTag: validationMissingTag,
76248         validationOldMultipolygon: validationOldMultipolygon,
76249         validationTagSuggestsArea: validationTagSuggestsArea
76250 });
76251
76252 window.iD = iD;
76253
76254 }());
76255 //# sourceMappingURL=iD.js.map