]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Merge pull request #1588 from Georeactor/master
[rails.git] / vendor / assets / iD / iD.js
1 (function () {
2 function actionAddEntity(way) {
3     return function(graph) {
4         return graph.replace(way);
5     };
6 }
7
8 var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
9
10
11
12
13
14 function createCommonjsModule(fn, module) {
15         return module = { exports: {} }, fn(module, module.exports), module.exports;
16 }
17
18 var lodash = createCommonjsModule(function (module, exports) {
19 /**
20  * @license
21  * Lodash <https://lodash.com/>
22  * Copyright JS Foundation and other contributors <https://js.foundation/>
23  * Released under MIT license <https://lodash.com/license>
24  * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
25  * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
26  */
27 (function() {
28
29   /** Used as a safe reference for `undefined` in pre-ES5 environments. */
30   var undefined;
31
32   /** Used as the semantic version number. */
33   var VERSION = '4.17.4';
34
35   /** Used as the size to enable large array optimizations. */
36   var LARGE_ARRAY_SIZE = 200;
37
38   /** Error message constants. */
39   var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
40       FUNC_ERROR_TEXT = 'Expected a function';
41
42   /** Used to stand-in for `undefined` hash values. */
43   var HASH_UNDEFINED = '__lodash_hash_undefined__';
44
45   /** Used as the maximum memoize cache size. */
46   var MAX_MEMOIZE_SIZE = 500;
47
48   /** Used as the internal argument placeholder. */
49   var PLACEHOLDER = '__lodash_placeholder__';
50
51   /** Used to compose bitmasks for cloning. */
52   var CLONE_DEEP_FLAG = 1,
53       CLONE_FLAT_FLAG = 2,
54       CLONE_SYMBOLS_FLAG = 4;
55
56   /** Used to compose bitmasks for value comparisons. */
57   var COMPARE_PARTIAL_FLAG = 1,
58       COMPARE_UNORDERED_FLAG = 2;
59
60   /** Used to compose bitmasks for function metadata. */
61   var WRAP_BIND_FLAG = 1,
62       WRAP_BIND_KEY_FLAG = 2,
63       WRAP_CURRY_BOUND_FLAG = 4,
64       WRAP_CURRY_FLAG = 8,
65       WRAP_CURRY_RIGHT_FLAG = 16,
66       WRAP_PARTIAL_FLAG = 32,
67       WRAP_PARTIAL_RIGHT_FLAG = 64,
68       WRAP_ARY_FLAG = 128,
69       WRAP_REARG_FLAG = 256,
70       WRAP_FLIP_FLAG = 512;
71
72   /** Used as default options for `_.truncate`. */
73   var DEFAULT_TRUNC_LENGTH = 30,
74       DEFAULT_TRUNC_OMISSION = '...';
75
76   /** Used to detect hot functions by number of calls within a span of milliseconds. */
77   var HOT_COUNT = 800,
78       HOT_SPAN = 16;
79
80   /** Used to indicate the type of lazy iteratees. */
81   var LAZY_FILTER_FLAG = 1,
82       LAZY_MAP_FLAG = 2,
83       LAZY_WHILE_FLAG = 3;
84
85   /** Used as references for various `Number` constants. */
86   var INFINITY = 1 / 0,
87       MAX_SAFE_INTEGER = 9007199254740991,
88       MAX_INTEGER = 1.7976931348623157e+308,
89       NAN = 0 / 0;
90
91   /** Used as references for the maximum length and index of an array. */
92   var MAX_ARRAY_LENGTH = 4294967295,
93       MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
94       HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
95
96   /** Used to associate wrap methods with their bit flags. */
97   var wrapFlags = [
98     ['ary', WRAP_ARY_FLAG],
99     ['bind', WRAP_BIND_FLAG],
100     ['bindKey', WRAP_BIND_KEY_FLAG],
101     ['curry', WRAP_CURRY_FLAG],
102     ['curryRight', WRAP_CURRY_RIGHT_FLAG],
103     ['flip', WRAP_FLIP_FLAG],
104     ['partial', WRAP_PARTIAL_FLAG],
105     ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
106     ['rearg', WRAP_REARG_FLAG]
107   ];
108
109   /** `Object#toString` result references. */
110   var argsTag = '[object Arguments]',
111       arrayTag = '[object Array]',
112       asyncTag = '[object AsyncFunction]',
113       boolTag = '[object Boolean]',
114       dateTag = '[object Date]',
115       domExcTag = '[object DOMException]',
116       errorTag = '[object Error]',
117       funcTag = '[object Function]',
118       genTag = '[object GeneratorFunction]',
119       mapTag = '[object Map]',
120       numberTag = '[object Number]',
121       nullTag = '[object Null]',
122       objectTag = '[object Object]',
123       promiseTag = '[object Promise]',
124       proxyTag = '[object Proxy]',
125       regexpTag = '[object RegExp]',
126       setTag = '[object Set]',
127       stringTag = '[object String]',
128       symbolTag = '[object Symbol]',
129       undefinedTag = '[object Undefined]',
130       weakMapTag = '[object WeakMap]',
131       weakSetTag = '[object WeakSet]';
132
133   var arrayBufferTag = '[object ArrayBuffer]',
134       dataViewTag = '[object DataView]',
135       float32Tag = '[object Float32Array]',
136       float64Tag = '[object Float64Array]',
137       int8Tag = '[object Int8Array]',
138       int16Tag = '[object Int16Array]',
139       int32Tag = '[object Int32Array]',
140       uint8Tag = '[object Uint8Array]',
141       uint8ClampedTag = '[object Uint8ClampedArray]',
142       uint16Tag = '[object Uint16Array]',
143       uint32Tag = '[object Uint32Array]';
144
145   /** Used to match empty string literals in compiled template source. */
146   var reEmptyStringLeading = /\b__p \+= '';/g,
147       reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
148       reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
149
150   /** Used to match HTML entities and HTML characters. */
151   var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
152       reUnescapedHtml = /[&<>"']/g,
153       reHasEscapedHtml = RegExp(reEscapedHtml.source),
154       reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
155
156   /** Used to match template delimiters. */
157   var reEscape = /<%-([\s\S]+?)%>/g,
158       reEvaluate = /<%([\s\S]+?)%>/g,
159       reInterpolate = /<%=([\s\S]+?)%>/g;
160
161   /** Used to match property names within property paths. */
162   var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
163       reIsPlainProp = /^\w*$/,
164       reLeadingDot = /^\./,
165       rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
166
167   /**
168    * Used to match `RegExp`
169    * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
170    */
171   var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
172       reHasRegExpChar = RegExp(reRegExpChar.source);
173
174   /** Used to match leading and trailing whitespace. */
175   var reTrim = /^\s+|\s+$/g,
176       reTrimStart = /^\s+/,
177       reTrimEnd = /\s+$/;
178
179   /** Used to match wrap detail comments. */
180   var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
181       reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
182       reSplitDetails = /,? & /;
183
184   /** Used to match words composed of alphanumeric characters. */
185   var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
186
187   /** Used to match backslashes in property paths. */
188   var reEscapeChar = /\\(\\)?/g;
189
190   /**
191    * Used to match
192    * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
193    */
194   var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
195
196   /** Used to match `RegExp` flags from their coerced string values. */
197   var reFlags = /\w*$/;
198
199   /** Used to detect bad signed hexadecimal string values. */
200   var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
201
202   /** Used to detect binary string values. */
203   var reIsBinary = /^0b[01]+$/i;
204
205   /** Used to detect host constructors (Safari). */
206   var reIsHostCtor = /^\[object .+?Constructor\]$/;
207
208   /** Used to detect octal string values. */
209   var reIsOctal = /^0o[0-7]+$/i;
210
211   /** Used to detect unsigned integer values. */
212   var reIsUint = /^(?:0|[1-9]\d*)$/;
213
214   /** Used to match Latin Unicode letters (excluding mathematical operators). */
215   var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
216
217   /** Used to ensure capturing order of template delimiters. */
218   var reNoMatch = /($^)/;
219
220   /** Used to match unescaped characters in compiled string literals. */
221   var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
222
223   /** Used to compose unicode character classes. */
224   var rsAstralRange = '\\ud800-\\udfff',
225       rsComboMarksRange = '\\u0300-\\u036f',
226       reComboHalfMarksRange = '\\ufe20-\\ufe2f',
227       rsComboSymbolsRange = '\\u20d0-\\u20ff',
228       rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
229       rsDingbatRange = '\\u2700-\\u27bf',
230       rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
231       rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
232       rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
233       rsPunctuationRange = '\\u2000-\\u206f',
234       rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
235       rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
236       rsVarRange = '\\ufe0e\\ufe0f',
237       rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
238
239   /** Used to compose unicode capture groups. */
240   var rsApos = "['\u2019]",
241       rsAstral = '[' + rsAstralRange + ']',
242       rsBreak = '[' + rsBreakRange + ']',
243       rsCombo = '[' + rsComboRange + ']',
244       rsDigits = '\\d+',
245       rsDingbat = '[' + rsDingbatRange + ']',
246       rsLower = '[' + rsLowerRange + ']',
247       rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
248       rsFitz = '\\ud83c[\\udffb-\\udfff]',
249       rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
250       rsNonAstral = '[^' + rsAstralRange + ']',
251       rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
252       rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
253       rsUpper = '[' + rsUpperRange + ']',
254       rsZWJ = '\\u200d';
255
256   /** Used to compose unicode regexes. */
257   var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
258       rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
259       rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
260       rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
261       reOptMod = rsModifier + '?',
262       rsOptVar = '[' + rsVarRange + ']?',
263       rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
264       rsOrdLower = '\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)',
265       rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)',
266       rsSeq = rsOptVar + reOptMod + rsOptJoin,
267       rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
268       rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
269
270   /** Used to match apostrophes. */
271   var reApos = RegExp(rsApos, 'g');
272
273   /**
274    * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
275    * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
276    */
277   var reComboMark = RegExp(rsCombo, 'g');
278
279   /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
280   var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
281
282   /** Used to match complex or compound words. */
283   var reUnicodeWord = RegExp([
284     rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
285     rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
286     rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
287     rsUpper + '+' + rsOptContrUpper,
288     rsOrdUpper,
289     rsOrdLower,
290     rsDigits,
291     rsEmoji
292   ].join('|'), 'g');
293
294   /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
295   var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange  + rsComboRange + rsVarRange + ']');
296
297   /** Used to detect strings that need a more robust regexp to match words. */
298   var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
299
300   /** Used to assign default `context` object properties. */
301   var contextProps = [
302     'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
303     'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
304     'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
305     'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
306     '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
307   ];
308
309   /** Used to make template sourceURLs easier to identify. */
310   var templateCounter = -1;
311
312   /** Used to identify `toStringTag` values of typed arrays. */
313   var typedArrayTags = {};
314   typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
315   typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
316   typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
317   typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
318   typedArrayTags[uint32Tag] = true;
319   typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
320   typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
321   typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
322   typedArrayTags[errorTag] = typedArrayTags[funcTag] =
323   typedArrayTags[mapTag] = typedArrayTags[numberTag] =
324   typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
325   typedArrayTags[setTag] = typedArrayTags[stringTag] =
326   typedArrayTags[weakMapTag] = false;
327
328   /** Used to identify `toStringTag` values supported by `_.clone`. */
329   var cloneableTags = {};
330   cloneableTags[argsTag] = cloneableTags[arrayTag] =
331   cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
332   cloneableTags[boolTag] = cloneableTags[dateTag] =
333   cloneableTags[float32Tag] = cloneableTags[float64Tag] =
334   cloneableTags[int8Tag] = cloneableTags[int16Tag] =
335   cloneableTags[int32Tag] = cloneableTags[mapTag] =
336   cloneableTags[numberTag] = cloneableTags[objectTag] =
337   cloneableTags[regexpTag] = cloneableTags[setTag] =
338   cloneableTags[stringTag] = cloneableTags[symbolTag] =
339   cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
340   cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
341   cloneableTags[errorTag] = cloneableTags[funcTag] =
342   cloneableTags[weakMapTag] = false;
343
344   /** Used to map Latin Unicode letters to basic Latin letters. */
345   var deburredLetters = {
346     // Latin-1 Supplement block.
347     '\xc0': 'A',  '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
348     '\xe0': 'a',  '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
349     '\xc7': 'C',  '\xe7': 'c',
350     '\xd0': 'D',  '\xf0': 'd',
351     '\xc8': 'E',  '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
352     '\xe8': 'e',  '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
353     '\xcc': 'I',  '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
354     '\xec': 'i',  '\xed': 'i', '\xee': 'i', '\xef': 'i',
355     '\xd1': 'N',  '\xf1': 'n',
356     '\xd2': 'O',  '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
357     '\xf2': 'o',  '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
358     '\xd9': 'U',  '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
359     '\xf9': 'u',  '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
360     '\xdd': 'Y',  '\xfd': 'y', '\xff': 'y',
361     '\xc6': 'Ae', '\xe6': 'ae',
362     '\xde': 'Th', '\xfe': 'th',
363     '\xdf': 'ss',
364     // Latin Extended-A block.
365     '\u0100': 'A',  '\u0102': 'A', '\u0104': 'A',
366     '\u0101': 'a',  '\u0103': 'a', '\u0105': 'a',
367     '\u0106': 'C',  '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
368     '\u0107': 'c',  '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
369     '\u010e': 'D',  '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
370     '\u0112': 'E',  '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
371     '\u0113': 'e',  '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
372     '\u011c': 'G',  '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
373     '\u011d': 'g',  '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
374     '\u0124': 'H',  '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
375     '\u0128': 'I',  '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
376     '\u0129': 'i',  '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
377     '\u0134': 'J',  '\u0135': 'j',
378     '\u0136': 'K',  '\u0137': 'k', '\u0138': 'k',
379     '\u0139': 'L',  '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
380     '\u013a': 'l',  '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
381     '\u0143': 'N',  '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
382     '\u0144': 'n',  '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
383     '\u014c': 'O',  '\u014e': 'O', '\u0150': 'O',
384     '\u014d': 'o',  '\u014f': 'o', '\u0151': 'o',
385     '\u0154': 'R',  '\u0156': 'R', '\u0158': 'R',
386     '\u0155': 'r',  '\u0157': 'r', '\u0159': 'r',
387     '\u015a': 'S',  '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
388     '\u015b': 's',  '\u015d': 's', '\u015f': 's', '\u0161': 's',
389     '\u0162': 'T',  '\u0164': 'T', '\u0166': 'T',
390     '\u0163': 't',  '\u0165': 't', '\u0167': 't',
391     '\u0168': 'U',  '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
392     '\u0169': 'u',  '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
393     '\u0174': 'W',  '\u0175': 'w',
394     '\u0176': 'Y',  '\u0177': 'y', '\u0178': 'Y',
395     '\u0179': 'Z',  '\u017b': 'Z', '\u017d': 'Z',
396     '\u017a': 'z',  '\u017c': 'z', '\u017e': 'z',
397     '\u0132': 'IJ', '\u0133': 'ij',
398     '\u0152': 'Oe', '\u0153': 'oe',
399     '\u0149': "'n", '\u017f': 's'
400   };
401
402   /** Used to map characters to HTML entities. */
403   var htmlEscapes = {
404     '&': '&amp;',
405     '<': '&lt;',
406     '>': '&gt;',
407     '"': '&quot;',
408     "'": '&#39;'
409   };
410
411   /** Used to map HTML entities to characters. */
412   var htmlUnescapes = {
413     '&amp;': '&',
414     '&lt;': '<',
415     '&gt;': '>',
416     '&quot;': '"',
417     '&#39;': "'"
418   };
419
420   /** Used to escape characters for inclusion in compiled string literals. */
421   var stringEscapes = {
422     '\\': '\\',
423     "'": "'",
424     '\n': 'n',
425     '\r': 'r',
426     '\u2028': 'u2028',
427     '\u2029': 'u2029'
428   };
429
430   /** Built-in method references without a dependency on `root`. */
431   var freeParseFloat = parseFloat,
432       freeParseInt = parseInt;
433
434   /** Detect free variable `global` from Node.js. */
435   var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
436
437   /** Detect free variable `self`. */
438   var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
439
440   /** Used as a reference to the global object. */
441   var root = freeGlobal || freeSelf || Function('return this')();
442
443   /** Detect free variable `exports`. */
444   var freeExports = 'object' == 'object' && exports && !exports.nodeType && exports;
445
446   /** Detect free variable `module`. */
447   var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module;
448
449   /** Detect the popular CommonJS extension `module.exports`. */
450   var moduleExports = freeModule && freeModule.exports === freeExports;
451
452   /** Detect free variable `process` from Node.js. */
453   var freeProcess = moduleExports && freeGlobal.process;
454
455   /** Used to access faster Node.js helpers. */
456   var nodeUtil = (function() {
457     try {
458       return freeProcess && freeProcess.binding && freeProcess.binding('util');
459     } catch (e) {}
460   }());
461
462   /* Node.js helper references. */
463   var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
464       nodeIsDate = nodeUtil && nodeUtil.isDate,
465       nodeIsMap = nodeUtil && nodeUtil.isMap,
466       nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
467       nodeIsSet = nodeUtil && nodeUtil.isSet,
468       nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
469
470   /*--------------------------------------------------------------------------*/
471
472   /**
473    * Adds the key-value `pair` to `map`.
474    *
475    * @private
476    * @param {Object} map The map to modify.
477    * @param {Array} pair The key-value pair to add.
478    * @returns {Object} Returns `map`.
479    */
480   function addMapEntry(map, pair) {
481     // Don't return `map.set` because it's not chainable in IE 11.
482     map.set(pair[0], pair[1]);
483     return map;
484   }
485
486   /**
487    * Adds `value` to `set`.
488    *
489    * @private
490    * @param {Object} set The set to modify.
491    * @param {*} value The value to add.
492    * @returns {Object} Returns `set`.
493    */
494   function addSetEntry(set, value) {
495     // Don't return `set.add` because it's not chainable in IE 11.
496     set.add(value);
497     return set;
498   }
499
500   /**
501    * A faster alternative to `Function#apply`, this function invokes `func`
502    * with the `this` binding of `thisArg` and the arguments of `args`.
503    *
504    * @private
505    * @param {Function} func The function to invoke.
506    * @param {*} thisArg The `this` binding of `func`.
507    * @param {Array} args The arguments to invoke `func` with.
508    * @returns {*} Returns the result of `func`.
509    */
510   function apply(func, thisArg, args) {
511     switch (args.length) {
512       case 0: return func.call(thisArg);
513       case 1: return func.call(thisArg, args[0]);
514       case 2: return func.call(thisArg, args[0], args[1]);
515       case 3: return func.call(thisArg, args[0], args[1], args[2]);
516     }
517     return func.apply(thisArg, args);
518   }
519
520   /**
521    * A specialized version of `baseAggregator` for arrays.
522    *
523    * @private
524    * @param {Array} [array] The array to iterate over.
525    * @param {Function} setter The function to set `accumulator` values.
526    * @param {Function} iteratee The iteratee to transform keys.
527    * @param {Object} accumulator The initial aggregated object.
528    * @returns {Function} Returns `accumulator`.
529    */
530   function arrayAggregator(array, setter, iteratee, accumulator) {
531     var index = -1,
532         length = array == null ? 0 : array.length;
533
534     while (++index < length) {
535       var value = array[index];
536       setter(accumulator, value, iteratee(value), array);
537     }
538     return accumulator;
539   }
540
541   /**
542    * A specialized version of `_.forEach` for arrays without support for
543    * iteratee shorthands.
544    *
545    * @private
546    * @param {Array} [array] The array to iterate over.
547    * @param {Function} iteratee The function invoked per iteration.
548    * @returns {Array} Returns `array`.
549    */
550   function arrayEach(array, iteratee) {
551     var index = -1,
552         length = array == null ? 0 : array.length;
553
554     while (++index < length) {
555       if (iteratee(array[index], index, array) === false) {
556         break;
557       }
558     }
559     return array;
560   }
561
562   /**
563    * A specialized version of `_.forEachRight` for arrays without support for
564    * iteratee shorthands.
565    *
566    * @private
567    * @param {Array} [array] The array to iterate over.
568    * @param {Function} iteratee The function invoked per iteration.
569    * @returns {Array} Returns `array`.
570    */
571   function arrayEachRight(array, iteratee) {
572     var length = array == null ? 0 : array.length;
573
574     while (length--) {
575       if (iteratee(array[length], length, array) === false) {
576         break;
577       }
578     }
579     return array;
580   }
581
582   /**
583    * A specialized version of `_.every` for arrays without support for
584    * iteratee shorthands.
585    *
586    * @private
587    * @param {Array} [array] The array to iterate over.
588    * @param {Function} predicate The function invoked per iteration.
589    * @returns {boolean} Returns `true` if all elements pass the predicate check,
590    *  else `false`.
591    */
592   function arrayEvery(array, predicate) {
593     var index = -1,
594         length = array == null ? 0 : array.length;
595
596     while (++index < length) {
597       if (!predicate(array[index], index, array)) {
598         return false;
599       }
600     }
601     return true;
602   }
603
604   /**
605    * A specialized version of `_.filter` for arrays without support for
606    * iteratee shorthands.
607    *
608    * @private
609    * @param {Array} [array] The array to iterate over.
610    * @param {Function} predicate The function invoked per iteration.
611    * @returns {Array} Returns the new filtered array.
612    */
613   function arrayFilter(array, predicate) {
614     var index = -1,
615         length = array == null ? 0 : array.length,
616         resIndex = 0,
617         result = [];
618
619     while (++index < length) {
620       var value = array[index];
621       if (predicate(value, index, array)) {
622         result[resIndex++] = value;
623       }
624     }
625     return result;
626   }
627
628   /**
629    * A specialized version of `_.includes` for arrays without support for
630    * specifying an index to search from.
631    *
632    * @private
633    * @param {Array} [array] The array to inspect.
634    * @param {*} target The value to search for.
635    * @returns {boolean} Returns `true` if `target` is found, else `false`.
636    */
637   function arrayIncludes(array, value) {
638     var length = array == null ? 0 : array.length;
639     return !!length && baseIndexOf(array, value, 0) > -1;
640   }
641
642   /**
643    * This function is like `arrayIncludes` except that it accepts a comparator.
644    *
645    * @private
646    * @param {Array} [array] The array to inspect.
647    * @param {*} target The value to search for.
648    * @param {Function} comparator The comparator invoked per element.
649    * @returns {boolean} Returns `true` if `target` is found, else `false`.
650    */
651   function arrayIncludesWith(array, value, comparator) {
652     var index = -1,
653         length = array == null ? 0 : array.length;
654
655     while (++index < length) {
656       if (comparator(value, array[index])) {
657         return true;
658       }
659     }
660     return false;
661   }
662
663   /**
664    * A specialized version of `_.map` for arrays without support for iteratee
665    * shorthands.
666    *
667    * @private
668    * @param {Array} [array] The array to iterate over.
669    * @param {Function} iteratee The function invoked per iteration.
670    * @returns {Array} Returns the new mapped array.
671    */
672   function arrayMap(array, iteratee) {
673     var index = -1,
674         length = array == null ? 0 : array.length,
675         result = Array(length);
676
677     while (++index < length) {
678       result[index] = iteratee(array[index], index, array);
679     }
680     return result;
681   }
682
683   /**
684    * Appends the elements of `values` to `array`.
685    *
686    * @private
687    * @param {Array} array The array to modify.
688    * @param {Array} values The values to append.
689    * @returns {Array} Returns `array`.
690    */
691   function arrayPush(array, values) {
692     var index = -1,
693         length = values.length,
694         offset = array.length;
695
696     while (++index < length) {
697       array[offset + index] = values[index];
698     }
699     return array;
700   }
701
702   /**
703    * A specialized version of `_.reduce` for arrays without support for
704    * iteratee shorthands.
705    *
706    * @private
707    * @param {Array} [array] The array to iterate over.
708    * @param {Function} iteratee The function invoked per iteration.
709    * @param {*} [accumulator] The initial value.
710    * @param {boolean} [initAccum] Specify using the first element of `array` as
711    *  the initial value.
712    * @returns {*} Returns the accumulated value.
713    */
714   function arrayReduce(array, iteratee, accumulator, initAccum) {
715     var index = -1,
716         length = array == null ? 0 : array.length;
717
718     if (initAccum && length) {
719       accumulator = array[++index];
720     }
721     while (++index < length) {
722       accumulator = iteratee(accumulator, array[index], index, array);
723     }
724     return accumulator;
725   }
726
727   /**
728    * A specialized version of `_.reduceRight` for arrays without support for
729    * iteratee shorthands.
730    *
731    * @private
732    * @param {Array} [array] The array to iterate over.
733    * @param {Function} iteratee The function invoked per iteration.
734    * @param {*} [accumulator] The initial value.
735    * @param {boolean} [initAccum] Specify using the last element of `array` as
736    *  the initial value.
737    * @returns {*} Returns the accumulated value.
738    */
739   function arrayReduceRight(array, iteratee, accumulator, initAccum) {
740     var length = array == null ? 0 : array.length;
741     if (initAccum && length) {
742       accumulator = array[--length];
743     }
744     while (length--) {
745       accumulator = iteratee(accumulator, array[length], length, array);
746     }
747     return accumulator;
748   }
749
750   /**
751    * A specialized version of `_.some` for arrays without support for iteratee
752    * shorthands.
753    *
754    * @private
755    * @param {Array} [array] The array to iterate over.
756    * @param {Function} predicate The function invoked per iteration.
757    * @returns {boolean} Returns `true` if any element passes the predicate check,
758    *  else `false`.
759    */
760   function arraySome(array, predicate) {
761     var index = -1,
762         length = array == null ? 0 : array.length;
763
764     while (++index < length) {
765       if (predicate(array[index], index, array)) {
766         return true;
767       }
768     }
769     return false;
770   }
771
772   /**
773    * Gets the size of an ASCII `string`.
774    *
775    * @private
776    * @param {string} string The string inspect.
777    * @returns {number} Returns the string size.
778    */
779   var asciiSize = baseProperty('length');
780
781   /**
782    * Converts an ASCII `string` to an array.
783    *
784    * @private
785    * @param {string} string The string to convert.
786    * @returns {Array} Returns the converted array.
787    */
788   function asciiToArray(string) {
789     return string.split('');
790   }
791
792   /**
793    * Splits an ASCII `string` into an array of its words.
794    *
795    * @private
796    * @param {string} The string to inspect.
797    * @returns {Array} Returns the words of `string`.
798    */
799   function asciiWords(string) {
800     return string.match(reAsciiWord) || [];
801   }
802
803   /**
804    * The base implementation of methods like `_.findKey` and `_.findLastKey`,
805    * without support for iteratee shorthands, which iterates over `collection`
806    * using `eachFunc`.
807    *
808    * @private
809    * @param {Array|Object} collection The collection to inspect.
810    * @param {Function} predicate The function invoked per iteration.
811    * @param {Function} eachFunc The function to iterate over `collection`.
812    * @returns {*} Returns the found element or its key, else `undefined`.
813    */
814   function baseFindKey(collection, predicate, eachFunc) {
815     var result;
816     eachFunc(collection, function(value, key, collection) {
817       if (predicate(value, key, collection)) {
818         result = key;
819         return false;
820       }
821     });
822     return result;
823   }
824
825   /**
826    * The base implementation of `_.findIndex` and `_.findLastIndex` without
827    * support for iteratee shorthands.
828    *
829    * @private
830    * @param {Array} array The array to inspect.
831    * @param {Function} predicate The function invoked per iteration.
832    * @param {number} fromIndex The index to search from.
833    * @param {boolean} [fromRight] Specify iterating from right to left.
834    * @returns {number} Returns the index of the matched value, else `-1`.
835    */
836   function baseFindIndex(array, predicate, fromIndex, fromRight) {
837     var length = array.length,
838         index = fromIndex + (fromRight ? 1 : -1);
839
840     while ((fromRight ? index-- : ++index < length)) {
841       if (predicate(array[index], index, array)) {
842         return index;
843       }
844     }
845     return -1;
846   }
847
848   /**
849    * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
850    *
851    * @private
852    * @param {Array} array The array to inspect.
853    * @param {*} value The value to search for.
854    * @param {number} fromIndex The index to search from.
855    * @returns {number} Returns the index of the matched value, else `-1`.
856    */
857   function baseIndexOf(array, value, fromIndex) {
858     return value === value
859       ? strictIndexOf(array, value, fromIndex)
860       : baseFindIndex(array, baseIsNaN, fromIndex);
861   }
862
863   /**
864    * This function is like `baseIndexOf` except that it accepts a comparator.
865    *
866    * @private
867    * @param {Array} array The array to inspect.
868    * @param {*} value The value to search for.
869    * @param {number} fromIndex The index to search from.
870    * @param {Function} comparator The comparator invoked per element.
871    * @returns {number} Returns the index of the matched value, else `-1`.
872    */
873   function baseIndexOfWith(array, value, fromIndex, comparator) {
874     var index = fromIndex - 1,
875         length = array.length;
876
877     while (++index < length) {
878       if (comparator(array[index], value)) {
879         return index;
880       }
881     }
882     return -1;
883   }
884
885   /**
886    * The base implementation of `_.isNaN` without support for number objects.
887    *
888    * @private
889    * @param {*} value The value to check.
890    * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
891    */
892   function baseIsNaN(value) {
893     return value !== value;
894   }
895
896   /**
897    * The base implementation of `_.mean` and `_.meanBy` without support for
898    * iteratee shorthands.
899    *
900    * @private
901    * @param {Array} array The array to iterate over.
902    * @param {Function} iteratee The function invoked per iteration.
903    * @returns {number} Returns the mean.
904    */
905   function baseMean(array, iteratee) {
906     var length = array == null ? 0 : array.length;
907     return length ? (baseSum(array, iteratee) / length) : NAN;
908   }
909
910   /**
911    * The base implementation of `_.property` without support for deep paths.
912    *
913    * @private
914    * @param {string} key The key of the property to get.
915    * @returns {Function} Returns the new accessor function.
916    */
917   function baseProperty(key) {
918     return function(object) {
919       return object == null ? undefined : object[key];
920     };
921   }
922
923   /**
924    * The base implementation of `_.propertyOf` without support for deep paths.
925    *
926    * @private
927    * @param {Object} object The object to query.
928    * @returns {Function} Returns the new accessor function.
929    */
930   function basePropertyOf(object) {
931     return function(key) {
932       return object == null ? undefined : object[key];
933     };
934   }
935
936   /**
937    * The base implementation of `_.reduce` and `_.reduceRight`, without support
938    * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
939    *
940    * @private
941    * @param {Array|Object} collection The collection to iterate over.
942    * @param {Function} iteratee The function invoked per iteration.
943    * @param {*} accumulator The initial value.
944    * @param {boolean} initAccum Specify using the first or last element of
945    *  `collection` as the initial value.
946    * @param {Function} eachFunc The function to iterate over `collection`.
947    * @returns {*} Returns the accumulated value.
948    */
949   function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
950     eachFunc(collection, function(value, index, collection) {
951       accumulator = initAccum
952         ? (initAccum = false, value)
953         : iteratee(accumulator, value, index, collection);
954     });
955     return accumulator;
956   }
957
958   /**
959    * The base implementation of `_.sortBy` which uses `comparer` to define the
960    * sort order of `array` and replaces criteria objects with their corresponding
961    * values.
962    *
963    * @private
964    * @param {Array} array The array to sort.
965    * @param {Function} comparer The function to define sort order.
966    * @returns {Array} Returns `array`.
967    */
968   function baseSortBy(array, comparer) {
969     var length = array.length;
970
971     array.sort(comparer);
972     while (length--) {
973       array[length] = array[length].value;
974     }
975     return array;
976   }
977
978   /**
979    * The base implementation of `_.sum` and `_.sumBy` without support for
980    * iteratee shorthands.
981    *
982    * @private
983    * @param {Array} array The array to iterate over.
984    * @param {Function} iteratee The function invoked per iteration.
985    * @returns {number} Returns the sum.
986    */
987   function baseSum(array, iteratee) {
988     var result,
989         index = -1,
990         length = array.length;
991
992     while (++index < length) {
993       var current = iteratee(array[index]);
994       if (current !== undefined) {
995         result = result === undefined ? current : (result + current);
996       }
997     }
998     return result;
999   }
1000
1001   /**
1002    * The base implementation of `_.times` without support for iteratee shorthands
1003    * or max array length checks.
1004    *
1005    * @private
1006    * @param {number} n The number of times to invoke `iteratee`.
1007    * @param {Function} iteratee The function invoked per iteration.
1008    * @returns {Array} Returns the array of results.
1009    */
1010   function baseTimes(n, iteratee) {
1011     var index = -1,
1012         result = Array(n);
1013
1014     while (++index < n) {
1015       result[index] = iteratee(index);
1016     }
1017     return result;
1018   }
1019
1020   /**
1021    * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
1022    * of key-value pairs for `object` corresponding to the property names of `props`.
1023    *
1024    * @private
1025    * @param {Object} object The object to query.
1026    * @param {Array} props The property names to get values for.
1027    * @returns {Object} Returns the key-value pairs.
1028    */
1029   function baseToPairs(object, props) {
1030     return arrayMap(props, function(key) {
1031       return [key, object[key]];
1032     });
1033   }
1034
1035   /**
1036    * The base implementation of `_.unary` without support for storing metadata.
1037    *
1038    * @private
1039    * @param {Function} func The function to cap arguments for.
1040    * @returns {Function} Returns the new capped function.
1041    */
1042   function baseUnary(func) {
1043     return function(value) {
1044       return func(value);
1045     };
1046   }
1047
1048   /**
1049    * The base implementation of `_.values` and `_.valuesIn` which creates an
1050    * array of `object` property values corresponding to the property names
1051    * of `props`.
1052    *
1053    * @private
1054    * @param {Object} object The object to query.
1055    * @param {Array} props The property names to get values for.
1056    * @returns {Object} Returns the array of property values.
1057    */
1058   function baseValues(object, props) {
1059     return arrayMap(props, function(key) {
1060       return object[key];
1061     });
1062   }
1063
1064   /**
1065    * Checks if a `cache` value for `key` exists.
1066    *
1067    * @private
1068    * @param {Object} cache The cache to query.
1069    * @param {string} key The key of the entry to check.
1070    * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
1071    */
1072   function cacheHas(cache, key) {
1073     return cache.has(key);
1074   }
1075
1076   /**
1077    * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
1078    * that is not found in the character symbols.
1079    *
1080    * @private
1081    * @param {Array} strSymbols The string symbols to inspect.
1082    * @param {Array} chrSymbols The character symbols to find.
1083    * @returns {number} Returns the index of the first unmatched string symbol.
1084    */
1085   function charsStartIndex(strSymbols, chrSymbols) {
1086     var index = -1,
1087         length = strSymbols.length;
1088
1089     while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
1090     return index;
1091   }
1092
1093   /**
1094    * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
1095    * that is not found in the character symbols.
1096    *
1097    * @private
1098    * @param {Array} strSymbols The string symbols to inspect.
1099    * @param {Array} chrSymbols The character symbols to find.
1100    * @returns {number} Returns the index of the last unmatched string symbol.
1101    */
1102   function charsEndIndex(strSymbols, chrSymbols) {
1103     var index = strSymbols.length;
1104
1105     while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
1106     return index;
1107   }
1108
1109   /**
1110    * Gets the number of `placeholder` occurrences in `array`.
1111    *
1112    * @private
1113    * @param {Array} array The array to inspect.
1114    * @param {*} placeholder The placeholder to search for.
1115    * @returns {number} Returns the placeholder count.
1116    */
1117   function countHolders(array, placeholder) {
1118     var length = array.length,
1119         result = 0;
1120
1121     while (length--) {
1122       if (array[length] === placeholder) {
1123         ++result;
1124       }
1125     }
1126     return result;
1127   }
1128
1129   /**
1130    * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
1131    * letters to basic Latin letters.
1132    *
1133    * @private
1134    * @param {string} letter The matched letter to deburr.
1135    * @returns {string} Returns the deburred letter.
1136    */
1137   var deburrLetter = basePropertyOf(deburredLetters);
1138
1139   /**
1140    * Used by `_.escape` to convert characters to HTML entities.
1141    *
1142    * @private
1143    * @param {string} chr The matched character to escape.
1144    * @returns {string} Returns the escaped character.
1145    */
1146   var escapeHtmlChar = basePropertyOf(htmlEscapes);
1147
1148   /**
1149    * Used by `_.template` to escape characters for inclusion in compiled string literals.
1150    *
1151    * @private
1152    * @param {string} chr The matched character to escape.
1153    * @returns {string} Returns the escaped character.
1154    */
1155   function escapeStringChar(chr) {
1156     return '\\' + stringEscapes[chr];
1157   }
1158
1159   /**
1160    * Gets the value at `key` of `object`.
1161    *
1162    * @private
1163    * @param {Object} [object] The object to query.
1164    * @param {string} key The key of the property to get.
1165    * @returns {*} Returns the property value.
1166    */
1167   function getValue(object, key) {
1168     return object == null ? undefined : object[key];
1169   }
1170
1171   /**
1172    * Checks if `string` contains Unicode symbols.
1173    *
1174    * @private
1175    * @param {string} string The string to inspect.
1176    * @returns {boolean} Returns `true` if a symbol is found, else `false`.
1177    */
1178   function hasUnicode(string) {
1179     return reHasUnicode.test(string);
1180   }
1181
1182   /**
1183    * Checks if `string` contains a word composed of Unicode symbols.
1184    *
1185    * @private
1186    * @param {string} string The string to inspect.
1187    * @returns {boolean} Returns `true` if a word is found, else `false`.
1188    */
1189   function hasUnicodeWord(string) {
1190     return reHasUnicodeWord.test(string);
1191   }
1192
1193   /**
1194    * Converts `iterator` to an array.
1195    *
1196    * @private
1197    * @param {Object} iterator The iterator to convert.
1198    * @returns {Array} Returns the converted array.
1199    */
1200   function iteratorToArray(iterator) {
1201     var data,
1202         result = [];
1203
1204     while (!(data = iterator.next()).done) {
1205       result.push(data.value);
1206     }
1207     return result;
1208   }
1209
1210   /**
1211    * Converts `map` to its key-value pairs.
1212    *
1213    * @private
1214    * @param {Object} map The map to convert.
1215    * @returns {Array} Returns the key-value pairs.
1216    */
1217   function mapToArray(map) {
1218     var index = -1,
1219         result = Array(map.size);
1220
1221     map.forEach(function(value, key) {
1222       result[++index] = [key, value];
1223     });
1224     return result;
1225   }
1226
1227   /**
1228    * Creates a unary function that invokes `func` with its argument transformed.
1229    *
1230    * @private
1231    * @param {Function} func The function to wrap.
1232    * @param {Function} transform The argument transform.
1233    * @returns {Function} Returns the new function.
1234    */
1235   function overArg(func, transform) {
1236     return function(arg) {
1237       return func(transform(arg));
1238     };
1239   }
1240
1241   /**
1242    * Replaces all `placeholder` elements in `array` with an internal placeholder
1243    * and returns an array of their indexes.
1244    *
1245    * @private
1246    * @param {Array} array The array to modify.
1247    * @param {*} placeholder The placeholder to replace.
1248    * @returns {Array} Returns the new array of placeholder indexes.
1249    */
1250   function replaceHolders(array, placeholder) {
1251     var index = -1,
1252         length = array.length,
1253         resIndex = 0,
1254         result = [];
1255
1256     while (++index < length) {
1257       var value = array[index];
1258       if (value === placeholder || value === PLACEHOLDER) {
1259         array[index] = PLACEHOLDER;
1260         result[resIndex++] = index;
1261       }
1262     }
1263     return result;
1264   }
1265
1266   /**
1267    * Converts `set` to an array of its values.
1268    *
1269    * @private
1270    * @param {Object} set The set to convert.
1271    * @returns {Array} Returns the values.
1272    */
1273   function setToArray(set) {
1274     var index = -1,
1275         result = Array(set.size);
1276
1277     set.forEach(function(value) {
1278       result[++index] = value;
1279     });
1280     return result;
1281   }
1282
1283   /**
1284    * Converts `set` to its value-value pairs.
1285    *
1286    * @private
1287    * @param {Object} set The set to convert.
1288    * @returns {Array} Returns the value-value pairs.
1289    */
1290   function setToPairs(set) {
1291     var index = -1,
1292         result = Array(set.size);
1293
1294     set.forEach(function(value) {
1295       result[++index] = [value, value];
1296     });
1297     return result;
1298   }
1299
1300   /**
1301    * A specialized version of `_.indexOf` which performs strict equality
1302    * comparisons of values, i.e. `===`.
1303    *
1304    * @private
1305    * @param {Array} array The array to inspect.
1306    * @param {*} value The value to search for.
1307    * @param {number} fromIndex The index to search from.
1308    * @returns {number} Returns the index of the matched value, else `-1`.
1309    */
1310   function strictIndexOf(array, value, fromIndex) {
1311     var index = fromIndex - 1,
1312         length = array.length;
1313
1314     while (++index < length) {
1315       if (array[index] === value) {
1316         return index;
1317       }
1318     }
1319     return -1;
1320   }
1321
1322   /**
1323    * A specialized version of `_.lastIndexOf` which performs strict equality
1324    * comparisons of values, i.e. `===`.
1325    *
1326    * @private
1327    * @param {Array} array The array to inspect.
1328    * @param {*} value The value to search for.
1329    * @param {number} fromIndex The index to search from.
1330    * @returns {number} Returns the index of the matched value, else `-1`.
1331    */
1332   function strictLastIndexOf(array, value, fromIndex) {
1333     var index = fromIndex + 1;
1334     while (index--) {
1335       if (array[index] === value) {
1336         return index;
1337       }
1338     }
1339     return index;
1340   }
1341
1342   /**
1343    * Gets the number of symbols in `string`.
1344    *
1345    * @private
1346    * @param {string} string The string to inspect.
1347    * @returns {number} Returns the string size.
1348    */
1349   function stringSize(string) {
1350     return hasUnicode(string)
1351       ? unicodeSize(string)
1352       : asciiSize(string);
1353   }
1354
1355   /**
1356    * Converts `string` to an array.
1357    *
1358    * @private
1359    * @param {string} string The string to convert.
1360    * @returns {Array} Returns the converted array.
1361    */
1362   function stringToArray(string) {
1363     return hasUnicode(string)
1364       ? unicodeToArray(string)
1365       : asciiToArray(string);
1366   }
1367
1368   /**
1369    * Used by `_.unescape` to convert HTML entities to characters.
1370    *
1371    * @private
1372    * @param {string} chr The matched character to unescape.
1373    * @returns {string} Returns the unescaped character.
1374    */
1375   var unescapeHtmlChar = basePropertyOf(htmlUnescapes);
1376
1377   /**
1378    * Gets the size of a Unicode `string`.
1379    *
1380    * @private
1381    * @param {string} string The string inspect.
1382    * @returns {number} Returns the string size.
1383    */
1384   function unicodeSize(string) {
1385     var result = reUnicode.lastIndex = 0;
1386     while (reUnicode.test(string)) {
1387       ++result;
1388     }
1389     return result;
1390   }
1391
1392   /**
1393    * Converts a Unicode `string` to an array.
1394    *
1395    * @private
1396    * @param {string} string The string to convert.
1397    * @returns {Array} Returns the converted array.
1398    */
1399   function unicodeToArray(string) {
1400     return string.match(reUnicode) || [];
1401   }
1402
1403   /**
1404    * Splits a Unicode `string` into an array of its words.
1405    *
1406    * @private
1407    * @param {string} The string to inspect.
1408    * @returns {Array} Returns the words of `string`.
1409    */
1410   function unicodeWords(string) {
1411     return string.match(reUnicodeWord) || [];
1412   }
1413
1414   /*--------------------------------------------------------------------------*/
1415
1416   /**
1417    * Create a new pristine `lodash` function using the `context` object.
1418    *
1419    * @static
1420    * @memberOf _
1421    * @since 1.1.0
1422    * @category Util
1423    * @param {Object} [context=root] The context object.
1424    * @returns {Function} Returns a new `lodash` function.
1425    * @example
1426    *
1427    * _.mixin({ 'foo': _.constant('foo') });
1428    *
1429    * var lodash = _.runInContext();
1430    * lodash.mixin({ 'bar': lodash.constant('bar') });
1431    *
1432    * _.isFunction(_.foo);
1433    * // => true
1434    * _.isFunction(_.bar);
1435    * // => false
1436    *
1437    * lodash.isFunction(lodash.foo);
1438    * // => false
1439    * lodash.isFunction(lodash.bar);
1440    * // => true
1441    *
1442    * // Create a suped-up `defer` in Node.js.
1443    * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
1444    */
1445   var runInContext = (function runInContext(context) {
1446     context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));
1447
1448     /** Built-in constructor references. */
1449     var Array = context.Array,
1450         Date = context.Date,
1451         Error = context.Error,
1452         Function = context.Function,
1453         Math = context.Math,
1454         Object = context.Object,
1455         RegExp = context.RegExp,
1456         String = context.String,
1457         TypeError = context.TypeError;
1458
1459     /** Used for built-in method references. */
1460     var arrayProto = Array.prototype,
1461         funcProto = Function.prototype,
1462         objectProto = Object.prototype;
1463
1464     /** Used to detect overreaching core-js shims. */
1465     var coreJsData = context['__core-js_shared__'];
1466
1467     /** Used to resolve the decompiled source of functions. */
1468     var funcToString = funcProto.toString;
1469
1470     /** Used to check objects for own properties. */
1471     var hasOwnProperty = objectProto.hasOwnProperty;
1472
1473     /** Used to generate unique IDs. */
1474     var idCounter = 0;
1475
1476     /** Used to detect methods masquerading as native. */
1477     var maskSrcKey = (function() {
1478       var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
1479       return uid ? ('Symbol(src)_1.' + uid) : '';
1480     }());
1481
1482     /**
1483      * Used to resolve the
1484      * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
1485      * of values.
1486      */
1487     var nativeObjectToString = objectProto.toString;
1488
1489     /** Used to infer the `Object` constructor. */
1490     var objectCtorString = funcToString.call(Object);
1491
1492     /** Used to restore the original `_` reference in `_.noConflict`. */
1493     var oldDash = root._;
1494
1495     /** Used to detect if a method is native. */
1496     var reIsNative = RegExp('^' +
1497       funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
1498       .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
1499     );
1500
1501     /** Built-in value references. */
1502     var Buffer = moduleExports ? context.Buffer : undefined,
1503         Symbol = context.Symbol,
1504         Uint8Array = context.Uint8Array,
1505         allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
1506         getPrototype = overArg(Object.getPrototypeOf, Object),
1507         objectCreate = Object.create,
1508         propertyIsEnumerable = objectProto.propertyIsEnumerable,
1509         splice = arrayProto.splice,
1510         spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
1511         symIterator = Symbol ? Symbol.iterator : undefined,
1512         symToStringTag = Symbol ? Symbol.toStringTag : undefined;
1513
1514     var defineProperty = (function() {
1515       try {
1516         var func = getNative(Object, 'defineProperty');
1517         func({}, '', {});
1518         return func;
1519       } catch (e) {}
1520     }());
1521
1522     /** Mocked built-ins. */
1523     var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
1524         ctxNow = Date && Date.now !== root.Date.now && Date.now,
1525         ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;
1526
1527     /* Built-in method references for those with the same name as other `lodash` methods. */
1528     var nativeCeil = Math.ceil,
1529         nativeFloor = Math.floor,
1530         nativeGetSymbols = Object.getOwnPropertySymbols,
1531         nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
1532         nativeIsFinite = context.isFinite,
1533         nativeJoin = arrayProto.join,
1534         nativeKeys = overArg(Object.keys, Object),
1535         nativeMax = Math.max,
1536         nativeMin = Math.min,
1537         nativeNow = Date.now,
1538         nativeParseInt = context.parseInt,
1539         nativeRandom = Math.random,
1540         nativeReverse = arrayProto.reverse;
1541
1542     /* Built-in method references that are verified to be native. */
1543     var DataView = getNative(context, 'DataView'),
1544         Map = getNative(context, 'Map'),
1545         Promise = getNative(context, 'Promise'),
1546         Set = getNative(context, 'Set'),
1547         WeakMap = getNative(context, 'WeakMap'),
1548         nativeCreate = getNative(Object, 'create');
1549
1550     /** Used to store function metadata. */
1551     var metaMap = WeakMap && new WeakMap;
1552
1553     /** Used to lookup unminified function names. */
1554     var realNames = {};
1555
1556     /** Used to detect maps, sets, and weakmaps. */
1557     var dataViewCtorString = toSource(DataView),
1558         mapCtorString = toSource(Map),
1559         promiseCtorString = toSource(Promise),
1560         setCtorString = toSource(Set),
1561         weakMapCtorString = toSource(WeakMap);
1562
1563     /** Used to convert symbols to primitives and strings. */
1564     var symbolProto = Symbol ? Symbol.prototype : undefined,
1565         symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
1566         symbolToString = symbolProto ? symbolProto.toString : undefined;
1567
1568     /*------------------------------------------------------------------------*/
1569
1570     /**
1571      * Creates a `lodash` object which wraps `value` to enable implicit method
1572      * chain sequences. Methods that operate on and return arrays, collections,
1573      * and functions can be chained together. Methods that retrieve a single value
1574      * or may return a primitive value will automatically end the chain sequence
1575      * and return the unwrapped value. Otherwise, the value must be unwrapped
1576      * with `_#value`.
1577      *
1578      * Explicit chain sequences, which must be unwrapped with `_#value`, may be
1579      * enabled using `_.chain`.
1580      *
1581      * The execution of chained methods is lazy, that is, it's deferred until
1582      * `_#value` is implicitly or explicitly called.
1583      *
1584      * Lazy evaluation allows several methods to support shortcut fusion.
1585      * Shortcut fusion is an optimization to merge iteratee calls; this avoids
1586      * the creation of intermediate arrays and can greatly reduce the number of
1587      * iteratee executions. Sections of a chain sequence qualify for shortcut
1588      * fusion if the section is applied to an array and iteratees accept only
1589      * one argument. The heuristic for whether a section qualifies for shortcut
1590      * fusion is subject to change.
1591      *
1592      * Chaining is supported in custom builds as long as the `_#value` method is
1593      * directly or indirectly included in the build.
1594      *
1595      * In addition to lodash methods, wrappers have `Array` and `String` methods.
1596      *
1597      * The wrapper `Array` methods are:
1598      * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
1599      *
1600      * The wrapper `String` methods are:
1601      * `replace` and `split`
1602      *
1603      * The wrapper methods that support shortcut fusion are:
1604      * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
1605      * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
1606      * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
1607      *
1608      * The chainable wrapper methods are:
1609      * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
1610      * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
1611      * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
1612      * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
1613      * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
1614      * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
1615      * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
1616      * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
1617      * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
1618      * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
1619      * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
1620      * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
1621      * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
1622      * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
1623      * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
1624      * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
1625      * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
1626      * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
1627      * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
1628      * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
1629      * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
1630      * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
1631      * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
1632      * `zipObject`, `zipObjectDeep`, and `zipWith`
1633      *
1634      * The wrapper methods that are **not** chainable by default are:
1635      * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
1636      * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
1637      * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
1638      * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
1639      * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
1640      * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
1641      * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
1642      * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
1643      * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
1644      * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
1645      * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
1646      * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
1647      * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
1648      * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
1649      * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
1650      * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
1651      * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
1652      * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
1653      * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
1654      * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
1655      * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
1656      * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
1657      * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
1658      * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
1659      * `upperFirst`, `value`, and `words`
1660      *
1661      * @name _
1662      * @constructor
1663      * @category Seq
1664      * @param {*} value The value to wrap in a `lodash` instance.
1665      * @returns {Object} Returns the new `lodash` wrapper instance.
1666      * @example
1667      *
1668      * function square(n) {
1669      *   return n * n;
1670      * }
1671      *
1672      * var wrapped = _([1, 2, 3]);
1673      *
1674      * // Returns an unwrapped value.
1675      * wrapped.reduce(_.add);
1676      * // => 6
1677      *
1678      * // Returns a wrapped value.
1679      * var squares = wrapped.map(square);
1680      *
1681      * _.isArray(squares);
1682      * // => false
1683      *
1684      * _.isArray(squares.value());
1685      * // => true
1686      */
1687     function lodash(value) {
1688       if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
1689         if (value instanceof LodashWrapper) {
1690           return value;
1691         }
1692         if (hasOwnProperty.call(value, '__wrapped__')) {
1693           return wrapperClone(value);
1694         }
1695       }
1696       return new LodashWrapper(value);
1697     }
1698
1699     /**
1700      * The base implementation of `_.create` without support for assigning
1701      * properties to the created object.
1702      *
1703      * @private
1704      * @param {Object} proto The object to inherit from.
1705      * @returns {Object} Returns the new object.
1706      */
1707     var baseCreate = (function() {
1708       function object() {}
1709       return function(proto) {
1710         if (!isObject(proto)) {
1711           return {};
1712         }
1713         if (objectCreate) {
1714           return objectCreate(proto);
1715         }
1716         object.prototype = proto;
1717         var result = new object;
1718         object.prototype = undefined;
1719         return result;
1720       };
1721     }());
1722
1723     /**
1724      * The function whose prototype chain sequence wrappers inherit from.
1725      *
1726      * @private
1727      */
1728     function baseLodash() {
1729       // No operation performed.
1730     }
1731
1732     /**
1733      * The base constructor for creating `lodash` wrapper objects.
1734      *
1735      * @private
1736      * @param {*} value The value to wrap.
1737      * @param {boolean} [chainAll] Enable explicit method chain sequences.
1738      */
1739     function LodashWrapper(value, chainAll) {
1740       this.__wrapped__ = value;
1741       this.__actions__ = [];
1742       this.__chain__ = !!chainAll;
1743       this.__index__ = 0;
1744       this.__values__ = undefined;
1745     }
1746
1747     /**
1748      * By default, the template delimiters used by lodash are like those in
1749      * embedded Ruby (ERB) as well as ES2015 template strings. Change the
1750      * following template settings to use alternative delimiters.
1751      *
1752      * @static
1753      * @memberOf _
1754      * @type {Object}
1755      */
1756     lodash.templateSettings = {
1757
1758       /**
1759        * Used to detect `data` property values to be HTML-escaped.
1760        *
1761        * @memberOf _.templateSettings
1762        * @type {RegExp}
1763        */
1764       'escape': reEscape,
1765
1766       /**
1767        * Used to detect code to be evaluated.
1768        *
1769        * @memberOf _.templateSettings
1770        * @type {RegExp}
1771        */
1772       'evaluate': reEvaluate,
1773
1774       /**
1775        * Used to detect `data` property values to inject.
1776        *
1777        * @memberOf _.templateSettings
1778        * @type {RegExp}
1779        */
1780       'interpolate': reInterpolate,
1781
1782       /**
1783        * Used to reference the data object in the template text.
1784        *
1785        * @memberOf _.templateSettings
1786        * @type {string}
1787        */
1788       'variable': '',
1789
1790       /**
1791        * Used to import variables into the compiled template.
1792        *
1793        * @memberOf _.templateSettings
1794        * @type {Object}
1795        */
1796       'imports': {
1797
1798         /**
1799          * A reference to the `lodash` function.
1800          *
1801          * @memberOf _.templateSettings.imports
1802          * @type {Function}
1803          */
1804         '_': lodash
1805       }
1806     };
1807
1808     // Ensure wrappers are instances of `baseLodash`.
1809     lodash.prototype = baseLodash.prototype;
1810     lodash.prototype.constructor = lodash;
1811
1812     LodashWrapper.prototype = baseCreate(baseLodash.prototype);
1813     LodashWrapper.prototype.constructor = LodashWrapper;
1814
1815     /*------------------------------------------------------------------------*/
1816
1817     /**
1818      * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
1819      *
1820      * @private
1821      * @constructor
1822      * @param {*} value The value to wrap.
1823      */
1824     function LazyWrapper(value) {
1825       this.__wrapped__ = value;
1826       this.__actions__ = [];
1827       this.__dir__ = 1;
1828       this.__filtered__ = false;
1829       this.__iteratees__ = [];
1830       this.__takeCount__ = MAX_ARRAY_LENGTH;
1831       this.__views__ = [];
1832     }
1833
1834     /**
1835      * Creates a clone of the lazy wrapper object.
1836      *
1837      * @private
1838      * @name clone
1839      * @memberOf LazyWrapper
1840      * @returns {Object} Returns the cloned `LazyWrapper` object.
1841      */
1842     function lazyClone() {
1843       var result = new LazyWrapper(this.__wrapped__);
1844       result.__actions__ = copyArray(this.__actions__);
1845       result.__dir__ = this.__dir__;
1846       result.__filtered__ = this.__filtered__;
1847       result.__iteratees__ = copyArray(this.__iteratees__);
1848       result.__takeCount__ = this.__takeCount__;
1849       result.__views__ = copyArray(this.__views__);
1850       return result;
1851     }
1852
1853     /**
1854      * Reverses the direction of lazy iteration.
1855      *
1856      * @private
1857      * @name reverse
1858      * @memberOf LazyWrapper
1859      * @returns {Object} Returns the new reversed `LazyWrapper` object.
1860      */
1861     function lazyReverse() {
1862       if (this.__filtered__) {
1863         var result = new LazyWrapper(this);
1864         result.__dir__ = -1;
1865         result.__filtered__ = true;
1866       } else {
1867         result = this.clone();
1868         result.__dir__ *= -1;
1869       }
1870       return result;
1871     }
1872
1873     /**
1874      * Extracts the unwrapped value from its lazy wrapper.
1875      *
1876      * @private
1877      * @name value
1878      * @memberOf LazyWrapper
1879      * @returns {*} Returns the unwrapped value.
1880      */
1881     function lazyValue() {
1882       var array = this.__wrapped__.value(),
1883           dir = this.__dir__,
1884           isArr = isArray(array),
1885           isRight = dir < 0,
1886           arrLength = isArr ? array.length : 0,
1887           view = getView(0, arrLength, this.__views__),
1888           start = view.start,
1889           end = view.end,
1890           length = end - start,
1891           index = isRight ? end : (start - 1),
1892           iteratees = this.__iteratees__,
1893           iterLength = iteratees.length,
1894           resIndex = 0,
1895           takeCount = nativeMin(length, this.__takeCount__);
1896
1897       if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
1898         return baseWrapperValue(array, this.__actions__);
1899       }
1900       var result = [];
1901
1902       outer:
1903       while (length-- && resIndex < takeCount) {
1904         index += dir;
1905
1906         var iterIndex = -1,
1907             value = array[index];
1908
1909         while (++iterIndex < iterLength) {
1910           var data = iteratees[iterIndex],
1911               iteratee = data.iteratee,
1912               type = data.type,
1913               computed = iteratee(value);
1914
1915           if (type == LAZY_MAP_FLAG) {
1916             value = computed;
1917           } else if (!computed) {
1918             if (type == LAZY_FILTER_FLAG) {
1919               continue outer;
1920             } else {
1921               break outer;
1922             }
1923           }
1924         }
1925         result[resIndex++] = value;
1926       }
1927       return result;
1928     }
1929
1930     // Ensure `LazyWrapper` is an instance of `baseLodash`.
1931     LazyWrapper.prototype = baseCreate(baseLodash.prototype);
1932     LazyWrapper.prototype.constructor = LazyWrapper;
1933
1934     /*------------------------------------------------------------------------*/
1935
1936     /**
1937      * Creates a hash object.
1938      *
1939      * @private
1940      * @constructor
1941      * @param {Array} [entries] The key-value pairs to cache.
1942      */
1943     function Hash(entries) {
1944       var index = -1,
1945           length = entries == null ? 0 : entries.length;
1946
1947       this.clear();
1948       while (++index < length) {
1949         var entry = entries[index];
1950         this.set(entry[0], entry[1]);
1951       }
1952     }
1953
1954     /**
1955      * Removes all key-value entries from the hash.
1956      *
1957      * @private
1958      * @name clear
1959      * @memberOf Hash
1960      */
1961     function hashClear() {
1962       this.__data__ = nativeCreate ? nativeCreate(null) : {};
1963       this.size = 0;
1964     }
1965
1966     /**
1967      * Removes `key` and its value from the hash.
1968      *
1969      * @private
1970      * @name delete
1971      * @memberOf Hash
1972      * @param {Object} hash The hash to modify.
1973      * @param {string} key The key of the value to remove.
1974      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
1975      */
1976     function hashDelete(key) {
1977       var result = this.has(key) && delete this.__data__[key];
1978       this.size -= result ? 1 : 0;
1979       return result;
1980     }
1981
1982     /**
1983      * Gets the hash value for `key`.
1984      *
1985      * @private
1986      * @name get
1987      * @memberOf Hash
1988      * @param {string} key The key of the value to get.
1989      * @returns {*} Returns the entry value.
1990      */
1991     function hashGet(key) {
1992       var data = this.__data__;
1993       if (nativeCreate) {
1994         var result = data[key];
1995         return result === HASH_UNDEFINED ? undefined : result;
1996       }
1997       return hasOwnProperty.call(data, key) ? data[key] : undefined;
1998     }
1999
2000     /**
2001      * Checks if a hash value for `key` exists.
2002      *
2003      * @private
2004      * @name has
2005      * @memberOf Hash
2006      * @param {string} key The key of the entry to check.
2007      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2008      */
2009     function hashHas(key) {
2010       var data = this.__data__;
2011       return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
2012     }
2013
2014     /**
2015      * Sets the hash `key` to `value`.
2016      *
2017      * @private
2018      * @name set
2019      * @memberOf Hash
2020      * @param {string} key The key of the value to set.
2021      * @param {*} value The value to set.
2022      * @returns {Object} Returns the hash instance.
2023      */
2024     function hashSet(key, value) {
2025       var data = this.__data__;
2026       this.size += this.has(key) ? 0 : 1;
2027       data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
2028       return this;
2029     }
2030
2031     // Add methods to `Hash`.
2032     Hash.prototype.clear = hashClear;
2033     Hash.prototype['delete'] = hashDelete;
2034     Hash.prototype.get = hashGet;
2035     Hash.prototype.has = hashHas;
2036     Hash.prototype.set = hashSet;
2037
2038     /*------------------------------------------------------------------------*/
2039
2040     /**
2041      * Creates an list cache object.
2042      *
2043      * @private
2044      * @constructor
2045      * @param {Array} [entries] The key-value pairs to cache.
2046      */
2047     function ListCache(entries) {
2048       var index = -1,
2049           length = entries == null ? 0 : entries.length;
2050
2051       this.clear();
2052       while (++index < length) {
2053         var entry = entries[index];
2054         this.set(entry[0], entry[1]);
2055       }
2056     }
2057
2058     /**
2059      * Removes all key-value entries from the list cache.
2060      *
2061      * @private
2062      * @name clear
2063      * @memberOf ListCache
2064      */
2065     function listCacheClear() {
2066       this.__data__ = [];
2067       this.size = 0;
2068     }
2069
2070     /**
2071      * Removes `key` and its value from the list cache.
2072      *
2073      * @private
2074      * @name delete
2075      * @memberOf ListCache
2076      * @param {string} key The key of the value to remove.
2077      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2078      */
2079     function listCacheDelete(key) {
2080       var data = this.__data__,
2081           index = assocIndexOf(data, key);
2082
2083       if (index < 0) {
2084         return false;
2085       }
2086       var lastIndex = data.length - 1;
2087       if (index == lastIndex) {
2088         data.pop();
2089       } else {
2090         splice.call(data, index, 1);
2091       }
2092       --this.size;
2093       return true;
2094     }
2095
2096     /**
2097      * Gets the list cache value for `key`.
2098      *
2099      * @private
2100      * @name get
2101      * @memberOf ListCache
2102      * @param {string} key The key of the value to get.
2103      * @returns {*} Returns the entry value.
2104      */
2105     function listCacheGet(key) {
2106       var data = this.__data__,
2107           index = assocIndexOf(data, key);
2108
2109       return index < 0 ? undefined : data[index][1];
2110     }
2111
2112     /**
2113      * Checks if a list cache value for `key` exists.
2114      *
2115      * @private
2116      * @name has
2117      * @memberOf ListCache
2118      * @param {string} key The key of the entry to check.
2119      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2120      */
2121     function listCacheHas(key) {
2122       return assocIndexOf(this.__data__, key) > -1;
2123     }
2124
2125     /**
2126      * Sets the list cache `key` to `value`.
2127      *
2128      * @private
2129      * @name set
2130      * @memberOf ListCache
2131      * @param {string} key The key of the value to set.
2132      * @param {*} value The value to set.
2133      * @returns {Object} Returns the list cache instance.
2134      */
2135     function listCacheSet(key, value) {
2136       var data = this.__data__,
2137           index = assocIndexOf(data, key);
2138
2139       if (index < 0) {
2140         ++this.size;
2141         data.push([key, value]);
2142       } else {
2143         data[index][1] = value;
2144       }
2145       return this;
2146     }
2147
2148     // Add methods to `ListCache`.
2149     ListCache.prototype.clear = listCacheClear;
2150     ListCache.prototype['delete'] = listCacheDelete;
2151     ListCache.prototype.get = listCacheGet;
2152     ListCache.prototype.has = listCacheHas;
2153     ListCache.prototype.set = listCacheSet;
2154
2155     /*------------------------------------------------------------------------*/
2156
2157     /**
2158      * Creates a map cache object to store key-value pairs.
2159      *
2160      * @private
2161      * @constructor
2162      * @param {Array} [entries] The key-value pairs to cache.
2163      */
2164     function MapCache(entries) {
2165       var index = -1,
2166           length = entries == null ? 0 : entries.length;
2167
2168       this.clear();
2169       while (++index < length) {
2170         var entry = entries[index];
2171         this.set(entry[0], entry[1]);
2172       }
2173     }
2174
2175     /**
2176      * Removes all key-value entries from the map.
2177      *
2178      * @private
2179      * @name clear
2180      * @memberOf MapCache
2181      */
2182     function mapCacheClear() {
2183       this.size = 0;
2184       this.__data__ = {
2185         'hash': new Hash,
2186         'map': new (Map || ListCache),
2187         'string': new Hash
2188       };
2189     }
2190
2191     /**
2192      * Removes `key` and its value from the map.
2193      *
2194      * @private
2195      * @name delete
2196      * @memberOf MapCache
2197      * @param {string} key The key of the value to remove.
2198      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2199      */
2200     function mapCacheDelete(key) {
2201       var result = getMapData(this, key)['delete'](key);
2202       this.size -= result ? 1 : 0;
2203       return result;
2204     }
2205
2206     /**
2207      * Gets the map value for `key`.
2208      *
2209      * @private
2210      * @name get
2211      * @memberOf MapCache
2212      * @param {string} key The key of the value to get.
2213      * @returns {*} Returns the entry value.
2214      */
2215     function mapCacheGet(key) {
2216       return getMapData(this, key).get(key);
2217     }
2218
2219     /**
2220      * Checks if a map value for `key` exists.
2221      *
2222      * @private
2223      * @name has
2224      * @memberOf MapCache
2225      * @param {string} key The key of the entry to check.
2226      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2227      */
2228     function mapCacheHas(key) {
2229       return getMapData(this, key).has(key);
2230     }
2231
2232     /**
2233      * Sets the map `key` to `value`.
2234      *
2235      * @private
2236      * @name set
2237      * @memberOf MapCache
2238      * @param {string} key The key of the value to set.
2239      * @param {*} value The value to set.
2240      * @returns {Object} Returns the map cache instance.
2241      */
2242     function mapCacheSet(key, value) {
2243       var data = getMapData(this, key),
2244           size = data.size;
2245
2246       data.set(key, value);
2247       this.size += data.size == size ? 0 : 1;
2248       return this;
2249     }
2250
2251     // Add methods to `MapCache`.
2252     MapCache.prototype.clear = mapCacheClear;
2253     MapCache.prototype['delete'] = mapCacheDelete;
2254     MapCache.prototype.get = mapCacheGet;
2255     MapCache.prototype.has = mapCacheHas;
2256     MapCache.prototype.set = mapCacheSet;
2257
2258     /*------------------------------------------------------------------------*/
2259
2260     /**
2261      *
2262      * Creates an array cache object to store unique values.
2263      *
2264      * @private
2265      * @constructor
2266      * @param {Array} [values] The values to cache.
2267      */
2268     function SetCache(values) {
2269       var index = -1,
2270           length = values == null ? 0 : values.length;
2271
2272       this.__data__ = new MapCache;
2273       while (++index < length) {
2274         this.add(values[index]);
2275       }
2276     }
2277
2278     /**
2279      * Adds `value` to the array cache.
2280      *
2281      * @private
2282      * @name add
2283      * @memberOf SetCache
2284      * @alias push
2285      * @param {*} value The value to cache.
2286      * @returns {Object} Returns the cache instance.
2287      */
2288     function setCacheAdd(value) {
2289       this.__data__.set(value, HASH_UNDEFINED);
2290       return this;
2291     }
2292
2293     /**
2294      * Checks if `value` is in the array cache.
2295      *
2296      * @private
2297      * @name has
2298      * @memberOf SetCache
2299      * @param {*} value The value to search for.
2300      * @returns {number} Returns `true` if `value` is found, else `false`.
2301      */
2302     function setCacheHas(value) {
2303       return this.__data__.has(value);
2304     }
2305
2306     // Add methods to `SetCache`.
2307     SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
2308     SetCache.prototype.has = setCacheHas;
2309
2310     /*------------------------------------------------------------------------*/
2311
2312     /**
2313      * Creates a stack cache object to store key-value pairs.
2314      *
2315      * @private
2316      * @constructor
2317      * @param {Array} [entries] The key-value pairs to cache.
2318      */
2319     function Stack(entries) {
2320       var data = this.__data__ = new ListCache(entries);
2321       this.size = data.size;
2322     }
2323
2324     /**
2325      * Removes all key-value entries from the stack.
2326      *
2327      * @private
2328      * @name clear
2329      * @memberOf Stack
2330      */
2331     function stackClear() {
2332       this.__data__ = new ListCache;
2333       this.size = 0;
2334     }
2335
2336     /**
2337      * Removes `key` and its value from the stack.
2338      *
2339      * @private
2340      * @name delete
2341      * @memberOf Stack
2342      * @param {string} key The key of the value to remove.
2343      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2344      */
2345     function stackDelete(key) {
2346       var data = this.__data__,
2347           result = data['delete'](key);
2348
2349       this.size = data.size;
2350       return result;
2351     }
2352
2353     /**
2354      * Gets the stack value for `key`.
2355      *
2356      * @private
2357      * @name get
2358      * @memberOf Stack
2359      * @param {string} key The key of the value to get.
2360      * @returns {*} Returns the entry value.
2361      */
2362     function stackGet(key) {
2363       return this.__data__.get(key);
2364     }
2365
2366     /**
2367      * Checks if a stack value for `key` exists.
2368      *
2369      * @private
2370      * @name has
2371      * @memberOf Stack
2372      * @param {string} key The key of the entry to check.
2373      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2374      */
2375     function stackHas(key) {
2376       return this.__data__.has(key);
2377     }
2378
2379     /**
2380      * Sets the stack `key` to `value`.
2381      *
2382      * @private
2383      * @name set
2384      * @memberOf Stack
2385      * @param {string} key The key of the value to set.
2386      * @param {*} value The value to set.
2387      * @returns {Object} Returns the stack cache instance.
2388      */
2389     function stackSet(key, value) {
2390       var data = this.__data__;
2391       if (data instanceof ListCache) {
2392         var pairs = data.__data__;
2393         if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
2394           pairs.push([key, value]);
2395           this.size = ++data.size;
2396           return this;
2397         }
2398         data = this.__data__ = new MapCache(pairs);
2399       }
2400       data.set(key, value);
2401       this.size = data.size;
2402       return this;
2403     }
2404
2405     // Add methods to `Stack`.
2406     Stack.prototype.clear = stackClear;
2407     Stack.prototype['delete'] = stackDelete;
2408     Stack.prototype.get = stackGet;
2409     Stack.prototype.has = stackHas;
2410     Stack.prototype.set = stackSet;
2411
2412     /*------------------------------------------------------------------------*/
2413
2414     /**
2415      * Creates an array of the enumerable property names of the array-like `value`.
2416      *
2417      * @private
2418      * @param {*} value The value to query.
2419      * @param {boolean} inherited Specify returning inherited property names.
2420      * @returns {Array} Returns the array of property names.
2421      */
2422     function arrayLikeKeys(value, inherited) {
2423       var isArr = isArray(value),
2424           isArg = !isArr && isArguments(value),
2425           isBuff = !isArr && !isArg && isBuffer(value),
2426           isType = !isArr && !isArg && !isBuff && isTypedArray(value),
2427           skipIndexes = isArr || isArg || isBuff || isType,
2428           result = skipIndexes ? baseTimes(value.length, String) : [],
2429           length = result.length;
2430
2431       for (var key in value) {
2432         if ((inherited || hasOwnProperty.call(value, key)) &&
2433             !(skipIndexes && (
2434                // Safari 9 has enumerable `arguments.length` in strict mode.
2435                key == 'length' ||
2436                // Node.js 0.10 has enumerable non-index properties on buffers.
2437                (isBuff && (key == 'offset' || key == 'parent')) ||
2438                // PhantomJS 2 has enumerable non-index properties on typed arrays.
2439                (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
2440                // Skip index properties.
2441                isIndex(key, length)
2442             ))) {
2443           result.push(key);
2444         }
2445       }
2446       return result;
2447     }
2448
2449     /**
2450      * A specialized version of `_.sample` for arrays.
2451      *
2452      * @private
2453      * @param {Array} array The array to sample.
2454      * @returns {*} Returns the random element.
2455      */
2456     function arraySample(array) {
2457       var length = array.length;
2458       return length ? array[baseRandom(0, length - 1)] : undefined;
2459     }
2460
2461     /**
2462      * A specialized version of `_.sampleSize` for arrays.
2463      *
2464      * @private
2465      * @param {Array} array The array to sample.
2466      * @param {number} n The number of elements to sample.
2467      * @returns {Array} Returns the random elements.
2468      */
2469     function arraySampleSize(array, n) {
2470       return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
2471     }
2472
2473     /**
2474      * A specialized version of `_.shuffle` for arrays.
2475      *
2476      * @private
2477      * @param {Array} array The array to shuffle.
2478      * @returns {Array} Returns the new shuffled array.
2479      */
2480     function arrayShuffle(array) {
2481       return shuffleSelf(copyArray(array));
2482     }
2483
2484     /**
2485      * This function is like `assignValue` except that it doesn't assign
2486      * `undefined` values.
2487      *
2488      * @private
2489      * @param {Object} object The object to modify.
2490      * @param {string} key The key of the property to assign.
2491      * @param {*} value The value to assign.
2492      */
2493     function assignMergeValue(object, key, value) {
2494       if ((value !== undefined && !eq(object[key], value)) ||
2495           (value === undefined && !(key in object))) {
2496         baseAssignValue(object, key, value);
2497       }
2498     }
2499
2500     /**
2501      * Assigns `value` to `key` of `object` if the existing value is not equivalent
2502      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
2503      * for equality comparisons.
2504      *
2505      * @private
2506      * @param {Object} object The object to modify.
2507      * @param {string} key The key of the property to assign.
2508      * @param {*} value The value to assign.
2509      */
2510     function assignValue(object, key, value) {
2511       var objValue = object[key];
2512       if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
2513           (value === undefined && !(key in object))) {
2514         baseAssignValue(object, key, value);
2515       }
2516     }
2517
2518     /**
2519      * Gets the index at which the `key` is found in `array` of key-value pairs.
2520      *
2521      * @private
2522      * @param {Array} array The array to inspect.
2523      * @param {*} key The key to search for.
2524      * @returns {number} Returns the index of the matched value, else `-1`.
2525      */
2526     function assocIndexOf(array, key) {
2527       var length = array.length;
2528       while (length--) {
2529         if (eq(array[length][0], key)) {
2530           return length;
2531         }
2532       }
2533       return -1;
2534     }
2535
2536     /**
2537      * Aggregates elements of `collection` on `accumulator` with keys transformed
2538      * by `iteratee` and values set by `setter`.
2539      *
2540      * @private
2541      * @param {Array|Object} collection The collection to iterate over.
2542      * @param {Function} setter The function to set `accumulator` values.
2543      * @param {Function} iteratee The iteratee to transform keys.
2544      * @param {Object} accumulator The initial aggregated object.
2545      * @returns {Function} Returns `accumulator`.
2546      */
2547     function baseAggregator(collection, setter, iteratee, accumulator) {
2548       baseEach(collection, function(value, key, collection) {
2549         setter(accumulator, value, iteratee(value), collection);
2550       });
2551       return accumulator;
2552     }
2553
2554     /**
2555      * The base implementation of `_.assign` without support for multiple sources
2556      * or `customizer` functions.
2557      *
2558      * @private
2559      * @param {Object} object The destination object.
2560      * @param {Object} source The source object.
2561      * @returns {Object} Returns `object`.
2562      */
2563     function baseAssign(object, source) {
2564       return object && copyObject(source, keys(source), object);
2565     }
2566
2567     /**
2568      * The base implementation of `_.assignIn` without support for multiple sources
2569      * or `customizer` functions.
2570      *
2571      * @private
2572      * @param {Object} object The destination object.
2573      * @param {Object} source The source object.
2574      * @returns {Object} Returns `object`.
2575      */
2576     function baseAssignIn(object, source) {
2577       return object && copyObject(source, keysIn(source), object);
2578     }
2579
2580     /**
2581      * The base implementation of `assignValue` and `assignMergeValue` without
2582      * value checks.
2583      *
2584      * @private
2585      * @param {Object} object The object to modify.
2586      * @param {string} key The key of the property to assign.
2587      * @param {*} value The value to assign.
2588      */
2589     function baseAssignValue(object, key, value) {
2590       if (key == '__proto__' && defineProperty) {
2591         defineProperty(object, key, {
2592           'configurable': true,
2593           'enumerable': true,
2594           'value': value,
2595           'writable': true
2596         });
2597       } else {
2598         object[key] = value;
2599       }
2600     }
2601
2602     /**
2603      * The base implementation of `_.at` without support for individual paths.
2604      *
2605      * @private
2606      * @param {Object} object The object to iterate over.
2607      * @param {string[]} paths The property paths to pick.
2608      * @returns {Array} Returns the picked elements.
2609      */
2610     function baseAt(object, paths) {
2611       var index = -1,
2612           length = paths.length,
2613           result = Array(length),
2614           skip = object == null;
2615
2616       while (++index < length) {
2617         result[index] = skip ? undefined : get(object, paths[index]);
2618       }
2619       return result;
2620     }
2621
2622     /**
2623      * The base implementation of `_.clamp` which doesn't coerce arguments.
2624      *
2625      * @private
2626      * @param {number} number The number to clamp.
2627      * @param {number} [lower] The lower bound.
2628      * @param {number} upper The upper bound.
2629      * @returns {number} Returns the clamped number.
2630      */
2631     function baseClamp(number, lower, upper) {
2632       if (number === number) {
2633         if (upper !== undefined) {
2634           number = number <= upper ? number : upper;
2635         }
2636         if (lower !== undefined) {
2637           number = number >= lower ? number : lower;
2638         }
2639       }
2640       return number;
2641     }
2642
2643     /**
2644      * The base implementation of `_.clone` and `_.cloneDeep` which tracks
2645      * traversed objects.
2646      *
2647      * @private
2648      * @param {*} value The value to clone.
2649      * @param {boolean} bitmask The bitmask flags.
2650      *  1 - Deep clone
2651      *  2 - Flatten inherited properties
2652      *  4 - Clone symbols
2653      * @param {Function} [customizer] The function to customize cloning.
2654      * @param {string} [key] The key of `value`.
2655      * @param {Object} [object] The parent object of `value`.
2656      * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
2657      * @returns {*} Returns the cloned value.
2658      */
2659     function baseClone(value, bitmask, customizer, key, object, stack) {
2660       var result,
2661           isDeep = bitmask & CLONE_DEEP_FLAG,
2662           isFlat = bitmask & CLONE_FLAT_FLAG,
2663           isFull = bitmask & CLONE_SYMBOLS_FLAG;
2664
2665       if (customizer) {
2666         result = object ? customizer(value, key, object, stack) : customizer(value);
2667       }
2668       if (result !== undefined) {
2669         return result;
2670       }
2671       if (!isObject(value)) {
2672         return value;
2673       }
2674       var isArr = isArray(value);
2675       if (isArr) {
2676         result = initCloneArray(value);
2677         if (!isDeep) {
2678           return copyArray(value, result);
2679         }
2680       } else {
2681         var tag = getTag(value),
2682             isFunc = tag == funcTag || tag == genTag;
2683
2684         if (isBuffer(value)) {
2685           return cloneBuffer(value, isDeep);
2686         }
2687         if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
2688           result = (isFlat || isFunc) ? {} : initCloneObject(value);
2689           if (!isDeep) {
2690             return isFlat
2691               ? copySymbolsIn(value, baseAssignIn(result, value))
2692               : copySymbols(value, baseAssign(result, value));
2693           }
2694         } else {
2695           if (!cloneableTags[tag]) {
2696             return object ? value : {};
2697           }
2698           result = initCloneByTag(value, tag, baseClone, isDeep);
2699         }
2700       }
2701       // Check for circular references and return its corresponding clone.
2702       stack || (stack = new Stack);
2703       var stacked = stack.get(value);
2704       if (stacked) {
2705         return stacked;
2706       }
2707       stack.set(value, result);
2708
2709       var keysFunc = isFull
2710         ? (isFlat ? getAllKeysIn : getAllKeys)
2711         : (isFlat ? keysIn : keys);
2712
2713       var props = isArr ? undefined : keysFunc(value);
2714       arrayEach(props || value, function(subValue, key) {
2715         if (props) {
2716           key = subValue;
2717           subValue = value[key];
2718         }
2719         // Recursively populate clone (susceptible to call stack limits).
2720         assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
2721       });
2722       return result;
2723     }
2724
2725     /**
2726      * The base implementation of `_.conforms` which doesn't clone `source`.
2727      *
2728      * @private
2729      * @param {Object} source The object of property predicates to conform to.
2730      * @returns {Function} Returns the new spec function.
2731      */
2732     function baseConforms(source) {
2733       var props = keys(source);
2734       return function(object) {
2735         return baseConformsTo(object, source, props);
2736       };
2737     }
2738
2739     /**
2740      * The base implementation of `_.conformsTo` which accepts `props` to check.
2741      *
2742      * @private
2743      * @param {Object} object The object to inspect.
2744      * @param {Object} source The object of property predicates to conform to.
2745      * @returns {boolean} Returns `true` if `object` conforms, else `false`.
2746      */
2747     function baseConformsTo(object, source, props) {
2748       var length = props.length;
2749       if (object == null) {
2750         return !length;
2751       }
2752       object = Object(object);
2753       while (length--) {
2754         var key = props[length],
2755             predicate = source[key],
2756             value = object[key];
2757
2758         if ((value === undefined && !(key in object)) || !predicate(value)) {
2759           return false;
2760         }
2761       }
2762       return true;
2763     }
2764
2765     /**
2766      * The base implementation of `_.delay` and `_.defer` which accepts `args`
2767      * to provide to `func`.
2768      *
2769      * @private
2770      * @param {Function} func The function to delay.
2771      * @param {number} wait The number of milliseconds to delay invocation.
2772      * @param {Array} args The arguments to provide to `func`.
2773      * @returns {number|Object} Returns the timer id or timeout object.
2774      */
2775     function baseDelay(func, wait, args) {
2776       if (typeof func != 'function') {
2777         throw new TypeError(FUNC_ERROR_TEXT);
2778       }
2779       return setTimeout(function() { func.apply(undefined, args); }, wait);
2780     }
2781
2782     /**
2783      * The base implementation of methods like `_.difference` without support
2784      * for excluding multiple arrays or iteratee shorthands.
2785      *
2786      * @private
2787      * @param {Array} array The array to inspect.
2788      * @param {Array} values The values to exclude.
2789      * @param {Function} [iteratee] The iteratee invoked per element.
2790      * @param {Function} [comparator] The comparator invoked per element.
2791      * @returns {Array} Returns the new array of filtered values.
2792      */
2793     function baseDifference(array, values, iteratee, comparator) {
2794       var index = -1,
2795           includes = arrayIncludes,
2796           isCommon = true,
2797           length = array.length,
2798           result = [],
2799           valuesLength = values.length;
2800
2801       if (!length) {
2802         return result;
2803       }
2804       if (iteratee) {
2805         values = arrayMap(values, baseUnary(iteratee));
2806       }
2807       if (comparator) {
2808         includes = arrayIncludesWith;
2809         isCommon = false;
2810       }
2811       else if (values.length >= LARGE_ARRAY_SIZE) {
2812         includes = cacheHas;
2813         isCommon = false;
2814         values = new SetCache(values);
2815       }
2816       outer:
2817       while (++index < length) {
2818         var value = array[index],
2819             computed = iteratee == null ? value : iteratee(value);
2820
2821         value = (comparator || value !== 0) ? value : 0;
2822         if (isCommon && computed === computed) {
2823           var valuesIndex = valuesLength;
2824           while (valuesIndex--) {
2825             if (values[valuesIndex] === computed) {
2826               continue outer;
2827             }
2828           }
2829           result.push(value);
2830         }
2831         else if (!includes(values, computed, comparator)) {
2832           result.push(value);
2833         }
2834       }
2835       return result;
2836     }
2837
2838     /**
2839      * The base implementation of `_.forEach` without support for iteratee shorthands.
2840      *
2841      * @private
2842      * @param {Array|Object} collection The collection to iterate over.
2843      * @param {Function} iteratee The function invoked per iteration.
2844      * @returns {Array|Object} Returns `collection`.
2845      */
2846     var baseEach = createBaseEach(baseForOwn);
2847
2848     /**
2849      * The base implementation of `_.forEachRight` without support for iteratee shorthands.
2850      *
2851      * @private
2852      * @param {Array|Object} collection The collection to iterate over.
2853      * @param {Function} iteratee The function invoked per iteration.
2854      * @returns {Array|Object} Returns `collection`.
2855      */
2856     var baseEachRight = createBaseEach(baseForOwnRight, true);
2857
2858     /**
2859      * The base implementation of `_.every` without support for iteratee shorthands.
2860      *
2861      * @private
2862      * @param {Array|Object} collection The collection to iterate over.
2863      * @param {Function} predicate The function invoked per iteration.
2864      * @returns {boolean} Returns `true` if all elements pass the predicate check,
2865      *  else `false`
2866      */
2867     function baseEvery(collection, predicate) {
2868       var result = true;
2869       baseEach(collection, function(value, index, collection) {
2870         result = !!predicate(value, index, collection);
2871         return result;
2872       });
2873       return result;
2874     }
2875
2876     /**
2877      * The base implementation of methods like `_.max` and `_.min` which accepts a
2878      * `comparator` to determine the extremum value.
2879      *
2880      * @private
2881      * @param {Array} array The array to iterate over.
2882      * @param {Function} iteratee The iteratee invoked per iteration.
2883      * @param {Function} comparator The comparator used to compare values.
2884      * @returns {*} Returns the extremum value.
2885      */
2886     function baseExtremum(array, iteratee, comparator) {
2887       var index = -1,
2888           length = array.length;
2889
2890       while (++index < length) {
2891         var value = array[index],
2892             current = iteratee(value);
2893
2894         if (current != null && (computed === undefined
2895               ? (current === current && !isSymbol(current))
2896               : comparator(current, computed)
2897             )) {
2898           var computed = current,
2899               result = value;
2900         }
2901       }
2902       return result;
2903     }
2904
2905     /**
2906      * The base implementation of `_.fill` without an iteratee call guard.
2907      *
2908      * @private
2909      * @param {Array} array The array to fill.
2910      * @param {*} value The value to fill `array` with.
2911      * @param {number} [start=0] The start position.
2912      * @param {number} [end=array.length] The end position.
2913      * @returns {Array} Returns `array`.
2914      */
2915     function baseFill(array, value, start, end) {
2916       var length = array.length;
2917
2918       start = toInteger(start);
2919       if (start < 0) {
2920         start = -start > length ? 0 : (length + start);
2921       }
2922       end = (end === undefined || end > length) ? length : toInteger(end);
2923       if (end < 0) {
2924         end += length;
2925       }
2926       end = start > end ? 0 : toLength(end);
2927       while (start < end) {
2928         array[start++] = value;
2929       }
2930       return array;
2931     }
2932
2933     /**
2934      * The base implementation of `_.filter` without support for iteratee shorthands.
2935      *
2936      * @private
2937      * @param {Array|Object} collection The collection to iterate over.
2938      * @param {Function} predicate The function invoked per iteration.
2939      * @returns {Array} Returns the new filtered array.
2940      */
2941     function baseFilter(collection, predicate) {
2942       var result = [];
2943       baseEach(collection, function(value, index, collection) {
2944         if (predicate(value, index, collection)) {
2945           result.push(value);
2946         }
2947       });
2948       return result;
2949     }
2950
2951     /**
2952      * The base implementation of `_.flatten` with support for restricting flattening.
2953      *
2954      * @private
2955      * @param {Array} array The array to flatten.
2956      * @param {number} depth The maximum recursion depth.
2957      * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
2958      * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
2959      * @param {Array} [result=[]] The initial result value.
2960      * @returns {Array} Returns the new flattened array.
2961      */
2962     function baseFlatten(array, depth, predicate, isStrict, result) {
2963       var index = -1,
2964           length = array.length;
2965
2966       predicate || (predicate = isFlattenable);
2967       result || (result = []);
2968
2969       while (++index < length) {
2970         var value = array[index];
2971         if (depth > 0 && predicate(value)) {
2972           if (depth > 1) {
2973             // Recursively flatten arrays (susceptible to call stack limits).
2974             baseFlatten(value, depth - 1, predicate, isStrict, result);
2975           } else {
2976             arrayPush(result, value);
2977           }
2978         } else if (!isStrict) {
2979           result[result.length] = value;
2980         }
2981       }
2982       return result;
2983     }
2984
2985     /**
2986      * The base implementation of `baseForOwn` which iterates over `object`
2987      * properties returned by `keysFunc` and invokes `iteratee` for each property.
2988      * Iteratee functions may exit iteration early by explicitly returning `false`.
2989      *
2990      * @private
2991      * @param {Object} object The object to iterate over.
2992      * @param {Function} iteratee The function invoked per iteration.
2993      * @param {Function} keysFunc The function to get the keys of `object`.
2994      * @returns {Object} Returns `object`.
2995      */
2996     var baseFor = createBaseFor();
2997
2998     /**
2999      * This function is like `baseFor` except that it iterates over properties
3000      * in the opposite order.
3001      *
3002      * @private
3003      * @param {Object} object The object to iterate over.
3004      * @param {Function} iteratee The function invoked per iteration.
3005      * @param {Function} keysFunc The function to get the keys of `object`.
3006      * @returns {Object} Returns `object`.
3007      */
3008     var baseForRight = createBaseFor(true);
3009
3010     /**
3011      * The base implementation of `_.forOwn` without support for iteratee shorthands.
3012      *
3013      * @private
3014      * @param {Object} object The object to iterate over.
3015      * @param {Function} iteratee The function invoked per iteration.
3016      * @returns {Object} Returns `object`.
3017      */
3018     function baseForOwn(object, iteratee) {
3019       return object && baseFor(object, iteratee, keys);
3020     }
3021
3022     /**
3023      * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
3024      *
3025      * @private
3026      * @param {Object} object The object to iterate over.
3027      * @param {Function} iteratee The function invoked per iteration.
3028      * @returns {Object} Returns `object`.
3029      */
3030     function baseForOwnRight(object, iteratee) {
3031       return object && baseForRight(object, iteratee, keys);
3032     }
3033
3034     /**
3035      * The base implementation of `_.functions` which creates an array of
3036      * `object` function property names filtered from `props`.
3037      *
3038      * @private
3039      * @param {Object} object The object to inspect.
3040      * @param {Array} props The property names to filter.
3041      * @returns {Array} Returns the function names.
3042      */
3043     function baseFunctions(object, props) {
3044       return arrayFilter(props, function(key) {
3045         return isFunction(object[key]);
3046       });
3047     }
3048
3049     /**
3050      * The base implementation of `_.get` without support for default values.
3051      *
3052      * @private
3053      * @param {Object} object The object to query.
3054      * @param {Array|string} path The path of the property to get.
3055      * @returns {*} Returns the resolved value.
3056      */
3057     function baseGet(object, path) {
3058       path = castPath(path, object);
3059
3060       var index = 0,
3061           length = path.length;
3062
3063       while (object != null && index < length) {
3064         object = object[toKey(path[index++])];
3065       }
3066       return (index && index == length) ? object : undefined;
3067     }
3068
3069     /**
3070      * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
3071      * `keysFunc` and `symbolsFunc` to get the enumerable property names and
3072      * symbols of `object`.
3073      *
3074      * @private
3075      * @param {Object} object The object to query.
3076      * @param {Function} keysFunc The function to get the keys of `object`.
3077      * @param {Function} symbolsFunc The function to get the symbols of `object`.
3078      * @returns {Array} Returns the array of property names and symbols.
3079      */
3080     function baseGetAllKeys(object, keysFunc, symbolsFunc) {
3081       var result = keysFunc(object);
3082       return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
3083     }
3084
3085     /**
3086      * The base implementation of `getTag` without fallbacks for buggy environments.
3087      *
3088      * @private
3089      * @param {*} value The value to query.
3090      * @returns {string} Returns the `toStringTag`.
3091      */
3092     function baseGetTag(value) {
3093       if (value == null) {
3094         return value === undefined ? undefinedTag : nullTag;
3095       }
3096       return (symToStringTag && symToStringTag in Object(value))
3097         ? getRawTag(value)
3098         : objectToString(value);
3099     }
3100
3101     /**
3102      * The base implementation of `_.gt` which doesn't coerce arguments.
3103      *
3104      * @private
3105      * @param {*} value The value to compare.
3106      * @param {*} other The other value to compare.
3107      * @returns {boolean} Returns `true` if `value` is greater than `other`,
3108      *  else `false`.
3109      */
3110     function baseGt(value, other) {
3111       return value > other;
3112     }
3113
3114     /**
3115      * The base implementation of `_.has` without support for deep paths.
3116      *
3117      * @private
3118      * @param {Object} [object] The object to query.
3119      * @param {Array|string} key The key to check.
3120      * @returns {boolean} Returns `true` if `key` exists, else `false`.
3121      */
3122     function baseHas(object, key) {
3123       return object != null && hasOwnProperty.call(object, key);
3124     }
3125
3126     /**
3127      * The base implementation of `_.hasIn` without support for deep paths.
3128      *
3129      * @private
3130      * @param {Object} [object] The object to query.
3131      * @param {Array|string} key The key to check.
3132      * @returns {boolean} Returns `true` if `key` exists, else `false`.
3133      */
3134     function baseHasIn(object, key) {
3135       return object != null && key in Object(object);
3136     }
3137
3138     /**
3139      * The base implementation of `_.inRange` which doesn't coerce arguments.
3140      *
3141      * @private
3142      * @param {number} number The number to check.
3143      * @param {number} start The start of the range.
3144      * @param {number} end The end of the range.
3145      * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
3146      */
3147     function baseInRange(number, start, end) {
3148       return number >= nativeMin(start, end) && number < nativeMax(start, end);
3149     }
3150
3151     /**
3152      * The base implementation of methods like `_.intersection`, without support
3153      * for iteratee shorthands, that accepts an array of arrays to inspect.
3154      *
3155      * @private
3156      * @param {Array} arrays The arrays to inspect.
3157      * @param {Function} [iteratee] The iteratee invoked per element.
3158      * @param {Function} [comparator] The comparator invoked per element.
3159      * @returns {Array} Returns the new array of shared values.
3160      */
3161     function baseIntersection(arrays, iteratee, comparator) {
3162       var includes = comparator ? arrayIncludesWith : arrayIncludes,
3163           length = arrays[0].length,
3164           othLength = arrays.length,
3165           othIndex = othLength,
3166           caches = Array(othLength),
3167           maxLength = Infinity,
3168           result = [];
3169
3170       while (othIndex--) {
3171         var array = arrays[othIndex];
3172         if (othIndex && iteratee) {
3173           array = arrayMap(array, baseUnary(iteratee));
3174         }
3175         maxLength = nativeMin(array.length, maxLength);
3176         caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
3177           ? new SetCache(othIndex && array)
3178           : undefined;
3179       }
3180       array = arrays[0];
3181
3182       var index = -1,
3183           seen = caches[0];
3184
3185       outer:
3186       while (++index < length && result.length < maxLength) {
3187         var value = array[index],
3188             computed = iteratee ? iteratee(value) : value;
3189
3190         value = (comparator || value !== 0) ? value : 0;
3191         if (!(seen
3192               ? cacheHas(seen, computed)
3193               : includes(result, computed, comparator)
3194             )) {
3195           othIndex = othLength;
3196           while (--othIndex) {
3197             var cache = caches[othIndex];
3198             if (!(cache
3199                   ? cacheHas(cache, computed)
3200                   : includes(arrays[othIndex], computed, comparator))
3201                 ) {
3202               continue outer;
3203             }
3204           }
3205           if (seen) {
3206             seen.push(computed);
3207           }
3208           result.push(value);
3209         }
3210       }
3211       return result;
3212     }
3213
3214     /**
3215      * The base implementation of `_.invert` and `_.invertBy` which inverts
3216      * `object` with values transformed by `iteratee` and set by `setter`.
3217      *
3218      * @private
3219      * @param {Object} object The object to iterate over.
3220      * @param {Function} setter The function to set `accumulator` values.
3221      * @param {Function} iteratee The iteratee to transform values.
3222      * @param {Object} accumulator The initial inverted object.
3223      * @returns {Function} Returns `accumulator`.
3224      */
3225     function baseInverter(object, setter, iteratee, accumulator) {
3226       baseForOwn(object, function(value, key, object) {
3227         setter(accumulator, iteratee(value), key, object);
3228       });
3229       return accumulator;
3230     }
3231
3232     /**
3233      * The base implementation of `_.invoke` without support for individual
3234      * method arguments.
3235      *
3236      * @private
3237      * @param {Object} object The object to query.
3238      * @param {Array|string} path The path of the method to invoke.
3239      * @param {Array} args The arguments to invoke the method with.
3240      * @returns {*} Returns the result of the invoked method.
3241      */
3242     function baseInvoke(object, path, args) {
3243       path = castPath(path, object);
3244       object = parent(object, path);
3245       var func = object == null ? object : object[toKey(last(path))];
3246       return func == null ? undefined : apply(func, object, args);
3247     }
3248
3249     /**
3250      * The base implementation of `_.isArguments`.
3251      *
3252      * @private
3253      * @param {*} value The value to check.
3254      * @returns {boolean} Returns `true` if `value` is an `arguments` object,
3255      */
3256     function baseIsArguments(value) {
3257       return isObjectLike(value) && baseGetTag(value) == argsTag;
3258     }
3259
3260     /**
3261      * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
3262      *
3263      * @private
3264      * @param {*} value The value to check.
3265      * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
3266      */
3267     function baseIsArrayBuffer(value) {
3268       return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
3269     }
3270
3271     /**
3272      * The base implementation of `_.isDate` without Node.js optimizations.
3273      *
3274      * @private
3275      * @param {*} value The value to check.
3276      * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
3277      */
3278     function baseIsDate(value) {
3279       return isObjectLike(value) && baseGetTag(value) == dateTag;
3280     }
3281
3282     /**
3283      * The base implementation of `_.isEqual` which supports partial comparisons
3284      * and tracks traversed objects.
3285      *
3286      * @private
3287      * @param {*} value The value to compare.
3288      * @param {*} other The other value to compare.
3289      * @param {boolean} bitmask The bitmask flags.
3290      *  1 - Unordered comparison
3291      *  2 - Partial comparison
3292      * @param {Function} [customizer] The function to customize comparisons.
3293      * @param {Object} [stack] Tracks traversed `value` and `other` objects.
3294      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
3295      */
3296     function baseIsEqual(value, other, bitmask, customizer, stack) {
3297       if (value === other) {
3298         return true;
3299       }
3300       if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
3301         return value !== value && other !== other;
3302       }
3303       return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
3304     }
3305
3306     /**
3307      * A specialized version of `baseIsEqual` for arrays and objects which performs
3308      * deep comparisons and tracks traversed objects enabling objects with circular
3309      * references to be compared.
3310      *
3311      * @private
3312      * @param {Object} object The object to compare.
3313      * @param {Object} other The other object to compare.
3314      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
3315      * @param {Function} customizer The function to customize comparisons.
3316      * @param {Function} equalFunc The function to determine equivalents of values.
3317      * @param {Object} [stack] Tracks traversed `object` and `other` objects.
3318      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
3319      */
3320     function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
3321       var objIsArr = isArray(object),
3322           othIsArr = isArray(other),
3323           objTag = objIsArr ? arrayTag : getTag(object),
3324           othTag = othIsArr ? arrayTag : getTag(other);
3325
3326       objTag = objTag == argsTag ? objectTag : objTag;
3327       othTag = othTag == argsTag ? objectTag : othTag;
3328
3329       var objIsObj = objTag == objectTag,
3330           othIsObj = othTag == objectTag,
3331           isSameTag = objTag == othTag;
3332
3333       if (isSameTag && isBuffer(object)) {
3334         if (!isBuffer(other)) {
3335           return false;
3336         }
3337         objIsArr = true;
3338         objIsObj = false;
3339       }
3340       if (isSameTag && !objIsObj) {
3341         stack || (stack = new Stack);
3342         return (objIsArr || isTypedArray(object))
3343           ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
3344           : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
3345       }
3346       if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
3347         var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
3348             othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
3349
3350         if (objIsWrapped || othIsWrapped) {
3351           var objUnwrapped = objIsWrapped ? object.value() : object,
3352               othUnwrapped = othIsWrapped ? other.value() : other;
3353
3354           stack || (stack = new Stack);
3355           return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
3356         }
3357       }
3358       if (!isSameTag) {
3359         return false;
3360       }
3361       stack || (stack = new Stack);
3362       return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
3363     }
3364
3365     /**
3366      * The base implementation of `_.isMap` without Node.js optimizations.
3367      *
3368      * @private
3369      * @param {*} value The value to check.
3370      * @returns {boolean} Returns `true` if `value` is a map, else `false`.
3371      */
3372     function baseIsMap(value) {
3373       return isObjectLike(value) && getTag(value) == mapTag;
3374     }
3375
3376     /**
3377      * The base implementation of `_.isMatch` without support for iteratee shorthands.
3378      *
3379      * @private
3380      * @param {Object} object The object to inspect.
3381      * @param {Object} source The object of property values to match.
3382      * @param {Array} matchData The property names, values, and compare flags to match.
3383      * @param {Function} [customizer] The function to customize comparisons.
3384      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
3385      */
3386     function baseIsMatch(object, source, matchData, customizer) {
3387       var index = matchData.length,
3388           length = index,
3389           noCustomizer = !customizer;
3390
3391       if (object == null) {
3392         return !length;
3393       }
3394       object = Object(object);
3395       while (index--) {
3396         var data = matchData[index];
3397         if ((noCustomizer && data[2])
3398               ? data[1] !== object[data[0]]
3399               : !(data[0] in object)
3400             ) {
3401           return false;
3402         }
3403       }
3404       while (++index < length) {
3405         data = matchData[index];
3406         var key = data[0],
3407             objValue = object[key],
3408             srcValue = data[1];
3409
3410         if (noCustomizer && data[2]) {
3411           if (objValue === undefined && !(key in object)) {
3412             return false;
3413           }
3414         } else {
3415           var stack = new Stack;
3416           if (customizer) {
3417             var result = customizer(objValue, srcValue, key, object, source, stack);
3418           }
3419           if (!(result === undefined
3420                 ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
3421                 : result
3422               )) {
3423             return false;
3424           }
3425         }
3426       }
3427       return true;
3428     }
3429
3430     /**
3431      * The base implementation of `_.isNative` without bad shim checks.
3432      *
3433      * @private
3434      * @param {*} value The value to check.
3435      * @returns {boolean} Returns `true` if `value` is a native function,
3436      *  else `false`.
3437      */
3438     function baseIsNative(value) {
3439       if (!isObject(value) || isMasked(value)) {
3440         return false;
3441       }
3442       var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
3443       return pattern.test(toSource(value));
3444     }
3445
3446     /**
3447      * The base implementation of `_.isRegExp` without Node.js optimizations.
3448      *
3449      * @private
3450      * @param {*} value The value to check.
3451      * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
3452      */
3453     function baseIsRegExp(value) {
3454       return isObjectLike(value) && baseGetTag(value) == regexpTag;
3455     }
3456
3457     /**
3458      * The base implementation of `_.isSet` without Node.js optimizations.
3459      *
3460      * @private
3461      * @param {*} value The value to check.
3462      * @returns {boolean} Returns `true` if `value` is a set, else `false`.
3463      */
3464     function baseIsSet(value) {
3465       return isObjectLike(value) && getTag(value) == setTag;
3466     }
3467
3468     /**
3469      * The base implementation of `_.isTypedArray` without Node.js optimizations.
3470      *
3471      * @private
3472      * @param {*} value The value to check.
3473      * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
3474      */
3475     function baseIsTypedArray(value) {
3476       return isObjectLike(value) &&
3477         isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
3478     }
3479
3480     /**
3481      * The base implementation of `_.iteratee`.
3482      *
3483      * @private
3484      * @param {*} [value=_.identity] The value to convert to an iteratee.
3485      * @returns {Function} Returns the iteratee.
3486      */
3487     function baseIteratee(value) {
3488       // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
3489       // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
3490       if (typeof value == 'function') {
3491         return value;
3492       }
3493       if (value == null) {
3494         return identity;
3495       }
3496       if (typeof value == 'object') {
3497         return isArray(value)
3498           ? baseMatchesProperty(value[0], value[1])
3499           : baseMatches(value);
3500       }
3501       return property(value);
3502     }
3503
3504     /**
3505      * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
3506      *
3507      * @private
3508      * @param {Object} object The object to query.
3509      * @returns {Array} Returns the array of property names.
3510      */
3511     function baseKeys(object) {
3512       if (!isPrototype(object)) {
3513         return nativeKeys(object);
3514       }
3515       var result = [];
3516       for (var key in Object(object)) {
3517         if (hasOwnProperty.call(object, key) && key != 'constructor') {
3518           result.push(key);
3519         }
3520       }
3521       return result;
3522     }
3523
3524     /**
3525      * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
3526      *
3527      * @private
3528      * @param {Object} object The object to query.
3529      * @returns {Array} Returns the array of property names.
3530      */
3531     function baseKeysIn(object) {
3532       if (!isObject(object)) {
3533         return nativeKeysIn(object);
3534       }
3535       var isProto = isPrototype(object),
3536           result = [];
3537
3538       for (var key in object) {
3539         if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
3540           result.push(key);
3541         }
3542       }
3543       return result;
3544     }
3545
3546     /**
3547      * The base implementation of `_.lt` which doesn't coerce arguments.
3548      *
3549      * @private
3550      * @param {*} value The value to compare.
3551      * @param {*} other The other value to compare.
3552      * @returns {boolean} Returns `true` if `value` is less than `other`,
3553      *  else `false`.
3554      */
3555     function baseLt(value, other) {
3556       return value < other;
3557     }
3558
3559     /**
3560      * The base implementation of `_.map` without support for iteratee shorthands.
3561      *
3562      * @private
3563      * @param {Array|Object} collection The collection to iterate over.
3564      * @param {Function} iteratee The function invoked per iteration.
3565      * @returns {Array} Returns the new mapped array.
3566      */
3567     function baseMap(collection, iteratee) {
3568       var index = -1,
3569           result = isArrayLike(collection) ? Array(collection.length) : [];
3570
3571       baseEach(collection, function(value, key, collection) {
3572         result[++index] = iteratee(value, key, collection);
3573       });
3574       return result;
3575     }
3576
3577     /**
3578      * The base implementation of `_.matches` which doesn't clone `source`.
3579      *
3580      * @private
3581      * @param {Object} source The object of property values to match.
3582      * @returns {Function} Returns the new spec function.
3583      */
3584     function baseMatches(source) {
3585       var matchData = getMatchData(source);
3586       if (matchData.length == 1 && matchData[0][2]) {
3587         return matchesStrictComparable(matchData[0][0], matchData[0][1]);
3588       }
3589       return function(object) {
3590         return object === source || baseIsMatch(object, source, matchData);
3591       };
3592     }
3593
3594     /**
3595      * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
3596      *
3597      * @private
3598      * @param {string} path The path of the property to get.
3599      * @param {*} srcValue The value to match.
3600      * @returns {Function} Returns the new spec function.
3601      */
3602     function baseMatchesProperty(path, srcValue) {
3603       if (isKey(path) && isStrictComparable(srcValue)) {
3604         return matchesStrictComparable(toKey(path), srcValue);
3605       }
3606       return function(object) {
3607         var objValue = get(object, path);
3608         return (objValue === undefined && objValue === srcValue)
3609           ? hasIn(object, path)
3610           : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
3611       };
3612     }
3613
3614     /**
3615      * The base implementation of `_.merge` without support for multiple sources.
3616      *
3617      * @private
3618      * @param {Object} object The destination object.
3619      * @param {Object} source The source object.
3620      * @param {number} srcIndex The index of `source`.
3621      * @param {Function} [customizer] The function to customize merged values.
3622      * @param {Object} [stack] Tracks traversed source values and their merged
3623      *  counterparts.
3624      */
3625     function baseMerge(object, source, srcIndex, customizer, stack) {
3626       if (object === source) {
3627         return;
3628       }
3629       baseFor(source, function(srcValue, key) {
3630         if (isObject(srcValue)) {
3631           stack || (stack = new Stack);
3632           baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
3633         }
3634         else {
3635           var newValue = customizer
3636             ? customizer(object[key], srcValue, (key + ''), object, source, stack)
3637             : undefined;
3638
3639           if (newValue === undefined) {
3640             newValue = srcValue;
3641           }
3642           assignMergeValue(object, key, newValue);
3643         }
3644       }, keysIn);
3645     }
3646
3647     /**
3648      * A specialized version of `baseMerge` for arrays and objects which performs
3649      * deep merges and tracks traversed objects enabling objects with circular
3650      * references to be merged.
3651      *
3652      * @private
3653      * @param {Object} object The destination object.
3654      * @param {Object} source The source object.
3655      * @param {string} key The key of the value to merge.
3656      * @param {number} srcIndex The index of `source`.
3657      * @param {Function} mergeFunc The function to merge values.
3658      * @param {Function} [customizer] The function to customize assigned values.
3659      * @param {Object} [stack] Tracks traversed source values and their merged
3660      *  counterparts.
3661      */
3662     function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
3663       var objValue = object[key],
3664           srcValue = source[key],
3665           stacked = stack.get(srcValue);
3666
3667       if (stacked) {
3668         assignMergeValue(object, key, stacked);
3669         return;
3670       }
3671       var newValue = customizer
3672         ? customizer(objValue, srcValue, (key + ''), object, source, stack)
3673         : undefined;
3674
3675       var isCommon = newValue === undefined;
3676
3677       if (isCommon) {
3678         var isArr = isArray(srcValue),
3679             isBuff = !isArr && isBuffer(srcValue),
3680             isTyped = !isArr && !isBuff && isTypedArray(srcValue);
3681
3682         newValue = srcValue;
3683         if (isArr || isBuff || isTyped) {
3684           if (isArray(objValue)) {
3685             newValue = objValue;
3686           }
3687           else if (isArrayLikeObject(objValue)) {
3688             newValue = copyArray(objValue);
3689           }
3690           else if (isBuff) {
3691             isCommon = false;
3692             newValue = cloneBuffer(srcValue, true);
3693           }
3694           else if (isTyped) {
3695             isCommon = false;
3696             newValue = cloneTypedArray(srcValue, true);
3697           }
3698           else {
3699             newValue = [];
3700           }
3701         }
3702         else if (isPlainObject(srcValue) || isArguments(srcValue)) {
3703           newValue = objValue;
3704           if (isArguments(objValue)) {
3705             newValue = toPlainObject(objValue);
3706           }
3707           else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
3708             newValue = initCloneObject(srcValue);
3709           }
3710         }
3711         else {
3712           isCommon = false;
3713         }
3714       }
3715       if (isCommon) {
3716         // Recursively merge objects and arrays (susceptible to call stack limits).
3717         stack.set(srcValue, newValue);
3718         mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
3719         stack['delete'](srcValue);
3720       }
3721       assignMergeValue(object, key, newValue);
3722     }
3723
3724     /**
3725      * The base implementation of `_.nth` which doesn't coerce arguments.
3726      *
3727      * @private
3728      * @param {Array} array The array to query.
3729      * @param {number} n The index of the element to return.
3730      * @returns {*} Returns the nth element of `array`.
3731      */
3732     function baseNth(array, n) {
3733       var length = array.length;
3734       if (!length) {
3735         return;
3736       }
3737       n += n < 0 ? length : 0;
3738       return isIndex(n, length) ? array[n] : undefined;
3739     }
3740
3741     /**
3742      * The base implementation of `_.orderBy` without param guards.
3743      *
3744      * @private
3745      * @param {Array|Object} collection The collection to iterate over.
3746      * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
3747      * @param {string[]} orders The sort orders of `iteratees`.
3748      * @returns {Array} Returns the new sorted array.
3749      */
3750     function baseOrderBy(collection, iteratees, orders) {
3751       var index = -1;
3752       iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee()));
3753
3754       var result = baseMap(collection, function(value, key, collection) {
3755         var criteria = arrayMap(iteratees, function(iteratee) {
3756           return iteratee(value);
3757         });
3758         return { 'criteria': criteria, 'index': ++index, 'value': value };
3759       });
3760
3761       return baseSortBy(result, function(object, other) {
3762         return compareMultiple(object, other, orders);
3763       });
3764     }
3765
3766     /**
3767      * The base implementation of `_.pick` without support for individual
3768      * property identifiers.
3769      *
3770      * @private
3771      * @param {Object} object The source object.
3772      * @param {string[]} paths The property paths to pick.
3773      * @returns {Object} Returns the new object.
3774      */
3775     function basePick(object, paths) {
3776       return basePickBy(object, paths, function(value, path) {
3777         return hasIn(object, path);
3778       });
3779     }
3780
3781     /**
3782      * The base implementation of  `_.pickBy` without support for iteratee shorthands.
3783      *
3784      * @private
3785      * @param {Object} object The source object.
3786      * @param {string[]} paths The property paths to pick.
3787      * @param {Function} predicate The function invoked per property.
3788      * @returns {Object} Returns the new object.
3789      */
3790     function basePickBy(object, paths, predicate) {
3791       var index = -1,
3792           length = paths.length,
3793           result = {};
3794
3795       while (++index < length) {
3796         var path = paths[index],
3797             value = baseGet(object, path);
3798
3799         if (predicate(value, path)) {
3800           baseSet(result, castPath(path, object), value);
3801         }
3802       }
3803       return result;
3804     }
3805
3806     /**
3807      * A specialized version of `baseProperty` which supports deep paths.
3808      *
3809      * @private
3810      * @param {Array|string} path The path of the property to get.
3811      * @returns {Function} Returns the new accessor function.
3812      */
3813     function basePropertyDeep(path) {
3814       return function(object) {
3815         return baseGet(object, path);
3816       };
3817     }
3818
3819     /**
3820      * The base implementation of `_.pullAllBy` without support for iteratee
3821      * shorthands.
3822      *
3823      * @private
3824      * @param {Array} array The array to modify.
3825      * @param {Array} values The values to remove.
3826      * @param {Function} [iteratee] The iteratee invoked per element.
3827      * @param {Function} [comparator] The comparator invoked per element.
3828      * @returns {Array} Returns `array`.
3829      */
3830     function basePullAll(array, values, iteratee, comparator) {
3831       var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
3832           index = -1,
3833           length = values.length,
3834           seen = array;
3835
3836       if (array === values) {
3837         values = copyArray(values);
3838       }
3839       if (iteratee) {
3840         seen = arrayMap(array, baseUnary(iteratee));
3841       }
3842       while (++index < length) {
3843         var fromIndex = 0,
3844             value = values[index],
3845             computed = iteratee ? iteratee(value) : value;
3846
3847         while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
3848           if (seen !== array) {
3849             splice.call(seen, fromIndex, 1);
3850           }
3851           splice.call(array, fromIndex, 1);
3852         }
3853       }
3854       return array;
3855     }
3856
3857     /**
3858      * The base implementation of `_.pullAt` without support for individual
3859      * indexes or capturing the removed elements.
3860      *
3861      * @private
3862      * @param {Array} array The array to modify.
3863      * @param {number[]} indexes The indexes of elements to remove.
3864      * @returns {Array} Returns `array`.
3865      */
3866     function basePullAt(array, indexes) {
3867       var length = array ? indexes.length : 0,
3868           lastIndex = length - 1;
3869
3870       while (length--) {
3871         var index = indexes[length];
3872         if (length == lastIndex || index !== previous) {
3873           var previous = index;
3874           if (isIndex(index)) {
3875             splice.call(array, index, 1);
3876           } else {
3877             baseUnset(array, index);
3878           }
3879         }
3880       }
3881       return array;
3882     }
3883
3884     /**
3885      * The base implementation of `_.random` without support for returning
3886      * floating-point numbers.
3887      *
3888      * @private
3889      * @param {number} lower The lower bound.
3890      * @param {number} upper The upper bound.
3891      * @returns {number} Returns the random number.
3892      */
3893     function baseRandom(lower, upper) {
3894       return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
3895     }
3896
3897     /**
3898      * The base implementation of `_.range` and `_.rangeRight` which doesn't
3899      * coerce arguments.
3900      *
3901      * @private
3902      * @param {number} start The start of the range.
3903      * @param {number} end The end of the range.
3904      * @param {number} step The value to increment or decrement by.
3905      * @param {boolean} [fromRight] Specify iterating from right to left.
3906      * @returns {Array} Returns the range of numbers.
3907      */
3908     function baseRange(start, end, step, fromRight) {
3909       var index = -1,
3910           length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
3911           result = Array(length);
3912
3913       while (length--) {
3914         result[fromRight ? length : ++index] = start;
3915         start += step;
3916       }
3917       return result;
3918     }
3919
3920     /**
3921      * The base implementation of `_.repeat` which doesn't coerce arguments.
3922      *
3923      * @private
3924      * @param {string} string The string to repeat.
3925      * @param {number} n The number of times to repeat the string.
3926      * @returns {string} Returns the repeated string.
3927      */
3928     function baseRepeat(string, n) {
3929       var result = '';
3930       if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
3931         return result;
3932       }
3933       // Leverage the exponentiation by squaring algorithm for a faster repeat.
3934       // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
3935       do {
3936         if (n % 2) {
3937           result += string;
3938         }
3939         n = nativeFloor(n / 2);
3940         if (n) {
3941           string += string;
3942         }
3943       } while (n);
3944
3945       return result;
3946     }
3947
3948     /**
3949      * The base implementation of `_.rest` which doesn't validate or coerce arguments.
3950      *
3951      * @private
3952      * @param {Function} func The function to apply a rest parameter to.
3953      * @param {number} [start=func.length-1] The start position of the rest parameter.
3954      * @returns {Function} Returns the new function.
3955      */
3956     function baseRest(func, start) {
3957       return setToString(overRest(func, start, identity), func + '');
3958     }
3959
3960     /**
3961      * The base implementation of `_.sample`.
3962      *
3963      * @private
3964      * @param {Array|Object} collection The collection to sample.
3965      * @returns {*} Returns the random element.
3966      */
3967     function baseSample(collection) {
3968       return arraySample(values(collection));
3969     }
3970
3971     /**
3972      * The base implementation of `_.sampleSize` without param guards.
3973      *
3974      * @private
3975      * @param {Array|Object} collection The collection to sample.
3976      * @param {number} n The number of elements to sample.
3977      * @returns {Array} Returns the random elements.
3978      */
3979     function baseSampleSize(collection, n) {
3980       var array = values(collection);
3981       return shuffleSelf(array, baseClamp(n, 0, array.length));
3982     }
3983
3984     /**
3985      * The base implementation of `_.set`.
3986      *
3987      * @private
3988      * @param {Object} object The object to modify.
3989      * @param {Array|string} path The path of the property to set.
3990      * @param {*} value The value to set.
3991      * @param {Function} [customizer] The function to customize path creation.
3992      * @returns {Object} Returns `object`.
3993      */
3994     function baseSet(object, path, value, customizer) {
3995       if (!isObject(object)) {
3996         return object;
3997       }
3998       path = castPath(path, object);
3999
4000       var index = -1,
4001           length = path.length,
4002           lastIndex = length - 1,
4003           nested = object;
4004
4005       while (nested != null && ++index < length) {
4006         var key = toKey(path[index]),
4007             newValue = value;
4008
4009         if (index != lastIndex) {
4010           var objValue = nested[key];
4011           newValue = customizer ? customizer(objValue, key, nested) : undefined;
4012           if (newValue === undefined) {
4013             newValue = isObject(objValue)
4014               ? objValue
4015               : (isIndex(path[index + 1]) ? [] : {});
4016           }
4017         }
4018         assignValue(nested, key, newValue);
4019         nested = nested[key];
4020       }
4021       return object;
4022     }
4023
4024     /**
4025      * The base implementation of `setData` without support for hot loop shorting.
4026      *
4027      * @private
4028      * @param {Function} func The function to associate metadata with.
4029      * @param {*} data The metadata.
4030      * @returns {Function} Returns `func`.
4031      */
4032     var baseSetData = !metaMap ? identity : function(func, data) {
4033       metaMap.set(func, data);
4034       return func;
4035     };
4036
4037     /**
4038      * The base implementation of `setToString` without support for hot loop shorting.
4039      *
4040      * @private
4041      * @param {Function} func The function to modify.
4042      * @param {Function} string The `toString` result.
4043      * @returns {Function} Returns `func`.
4044      */
4045     var baseSetToString = !defineProperty ? identity : function(func, string) {
4046       return defineProperty(func, 'toString', {
4047         'configurable': true,
4048         'enumerable': false,
4049         'value': constant(string),
4050         'writable': true
4051       });
4052     };
4053
4054     /**
4055      * The base implementation of `_.shuffle`.
4056      *
4057      * @private
4058      * @param {Array|Object} collection The collection to shuffle.
4059      * @returns {Array} Returns the new shuffled array.
4060      */
4061     function baseShuffle(collection) {
4062       return shuffleSelf(values(collection));
4063     }
4064
4065     /**
4066      * The base implementation of `_.slice` without an iteratee call guard.
4067      *
4068      * @private
4069      * @param {Array} array The array to slice.
4070      * @param {number} [start=0] The start position.
4071      * @param {number} [end=array.length] The end position.
4072      * @returns {Array} Returns the slice of `array`.
4073      */
4074     function baseSlice(array, start, end) {
4075       var index = -1,
4076           length = array.length;
4077
4078       if (start < 0) {
4079         start = -start > length ? 0 : (length + start);
4080       }
4081       end = end > length ? length : end;
4082       if (end < 0) {
4083         end += length;
4084       }
4085       length = start > end ? 0 : ((end - start) >>> 0);
4086       start >>>= 0;
4087
4088       var result = Array(length);
4089       while (++index < length) {
4090         result[index] = array[index + start];
4091       }
4092       return result;
4093     }
4094
4095     /**
4096      * The base implementation of `_.some` without support for iteratee shorthands.
4097      *
4098      * @private
4099      * @param {Array|Object} collection The collection to iterate over.
4100      * @param {Function} predicate The function invoked per iteration.
4101      * @returns {boolean} Returns `true` if any element passes the predicate check,
4102      *  else `false`.
4103      */
4104     function baseSome(collection, predicate) {
4105       var result;
4106
4107       baseEach(collection, function(value, index, collection) {
4108         result = predicate(value, index, collection);
4109         return !result;
4110       });
4111       return !!result;
4112     }
4113
4114     /**
4115      * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
4116      * performs a binary search of `array` to determine the index at which `value`
4117      * should be inserted into `array` in order to maintain its sort order.
4118      *
4119      * @private
4120      * @param {Array} array The sorted array to inspect.
4121      * @param {*} value The value to evaluate.
4122      * @param {boolean} [retHighest] Specify returning the highest qualified index.
4123      * @returns {number} Returns the index at which `value` should be inserted
4124      *  into `array`.
4125      */
4126     function baseSortedIndex(array, value, retHighest) {
4127       var low = 0,
4128           high = array == null ? low : array.length;
4129
4130       if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
4131         while (low < high) {
4132           var mid = (low + high) >>> 1,
4133               computed = array[mid];
4134
4135           if (computed !== null && !isSymbol(computed) &&
4136               (retHighest ? (computed <= value) : (computed < value))) {
4137             low = mid + 1;
4138           } else {
4139             high = mid;
4140           }
4141         }
4142         return high;
4143       }
4144       return baseSortedIndexBy(array, value, identity, retHighest);
4145     }
4146
4147     /**
4148      * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
4149      * which invokes `iteratee` for `value` and each element of `array` to compute
4150      * their sort ranking. The iteratee is invoked with one argument; (value).
4151      *
4152      * @private
4153      * @param {Array} array The sorted array to inspect.
4154      * @param {*} value The value to evaluate.
4155      * @param {Function} iteratee The iteratee invoked per element.
4156      * @param {boolean} [retHighest] Specify returning the highest qualified index.
4157      * @returns {number} Returns the index at which `value` should be inserted
4158      *  into `array`.
4159      */
4160     function baseSortedIndexBy(array, value, iteratee, retHighest) {
4161       value = iteratee(value);
4162
4163       var low = 0,
4164           high = array == null ? 0 : array.length,
4165           valIsNaN = value !== value,
4166           valIsNull = value === null,
4167           valIsSymbol = isSymbol(value),
4168           valIsUndefined = value === undefined;
4169
4170       while (low < high) {
4171         var mid = nativeFloor((low + high) / 2),
4172             computed = iteratee(array[mid]),
4173             othIsDefined = computed !== undefined,
4174             othIsNull = computed === null,
4175             othIsReflexive = computed === computed,
4176             othIsSymbol = isSymbol(computed);
4177
4178         if (valIsNaN) {
4179           var setLow = retHighest || othIsReflexive;
4180         } else if (valIsUndefined) {
4181           setLow = othIsReflexive && (retHighest || othIsDefined);
4182         } else if (valIsNull) {
4183           setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
4184         } else if (valIsSymbol) {
4185           setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
4186         } else if (othIsNull || othIsSymbol) {
4187           setLow = false;
4188         } else {
4189           setLow = retHighest ? (computed <= value) : (computed < value);
4190         }
4191         if (setLow) {
4192           low = mid + 1;
4193         } else {
4194           high = mid;
4195         }
4196       }
4197       return nativeMin(high, MAX_ARRAY_INDEX);
4198     }
4199
4200     /**
4201      * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
4202      * support for iteratee shorthands.
4203      *
4204      * @private
4205      * @param {Array} array The array to inspect.
4206      * @param {Function} [iteratee] The iteratee invoked per element.
4207      * @returns {Array} Returns the new duplicate free array.
4208      */
4209     function baseSortedUniq(array, iteratee) {
4210       var index = -1,
4211           length = array.length,
4212           resIndex = 0,
4213           result = [];
4214
4215       while (++index < length) {
4216         var value = array[index],
4217             computed = iteratee ? iteratee(value) : value;
4218
4219         if (!index || !eq(computed, seen)) {
4220           var seen = computed;
4221           result[resIndex++] = value === 0 ? 0 : value;
4222         }
4223       }
4224       return result;
4225     }
4226
4227     /**
4228      * The base implementation of `_.toNumber` which doesn't ensure correct
4229      * conversions of binary, hexadecimal, or octal string values.
4230      *
4231      * @private
4232      * @param {*} value The value to process.
4233      * @returns {number} Returns the number.
4234      */
4235     function baseToNumber(value) {
4236       if (typeof value == 'number') {
4237         return value;
4238       }
4239       if (isSymbol(value)) {
4240         return NAN;
4241       }
4242       return +value;
4243     }
4244
4245     /**
4246      * The base implementation of `_.toString` which doesn't convert nullish
4247      * values to empty strings.
4248      *
4249      * @private
4250      * @param {*} value The value to process.
4251      * @returns {string} Returns the string.
4252      */
4253     function baseToString(value) {
4254       // Exit early for strings to avoid a performance hit in some environments.
4255       if (typeof value == 'string') {
4256         return value;
4257       }
4258       if (isArray(value)) {
4259         // Recursively convert values (susceptible to call stack limits).
4260         return arrayMap(value, baseToString) + '';
4261       }
4262       if (isSymbol(value)) {
4263         return symbolToString ? symbolToString.call(value) : '';
4264       }
4265       var result = (value + '');
4266       return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
4267     }
4268
4269     /**
4270      * The base implementation of `_.uniqBy` without support for iteratee shorthands.
4271      *
4272      * @private
4273      * @param {Array} array The array to inspect.
4274      * @param {Function} [iteratee] The iteratee invoked per element.
4275      * @param {Function} [comparator] The comparator invoked per element.
4276      * @returns {Array} Returns the new duplicate free array.
4277      */
4278     function baseUniq(array, iteratee, comparator) {
4279       var index = -1,
4280           includes = arrayIncludes,
4281           length = array.length,
4282           isCommon = true,
4283           result = [],
4284           seen = result;
4285
4286       if (comparator) {
4287         isCommon = false;
4288         includes = arrayIncludesWith;
4289       }
4290       else if (length >= LARGE_ARRAY_SIZE) {
4291         var set = iteratee ? null : createSet(array);
4292         if (set) {
4293           return setToArray(set);
4294         }
4295         isCommon = false;
4296         includes = cacheHas;
4297         seen = new SetCache;
4298       }
4299       else {
4300         seen = iteratee ? [] : result;
4301       }
4302       outer:
4303       while (++index < length) {
4304         var value = array[index],
4305             computed = iteratee ? iteratee(value) : value;
4306
4307         value = (comparator || value !== 0) ? value : 0;
4308         if (isCommon && computed === computed) {
4309           var seenIndex = seen.length;
4310           while (seenIndex--) {
4311             if (seen[seenIndex] === computed) {
4312               continue outer;
4313             }
4314           }
4315           if (iteratee) {
4316             seen.push(computed);
4317           }
4318           result.push(value);
4319         }
4320         else if (!includes(seen, computed, comparator)) {
4321           if (seen !== result) {
4322             seen.push(computed);
4323           }
4324           result.push(value);
4325         }
4326       }
4327       return result;
4328     }
4329
4330     /**
4331      * The base implementation of `_.unset`.
4332      *
4333      * @private
4334      * @param {Object} object The object to modify.
4335      * @param {Array|string} path The property path to unset.
4336      * @returns {boolean} Returns `true` if the property is deleted, else `false`.
4337      */
4338     function baseUnset(object, path) {
4339       path = castPath(path, object);
4340       object = parent(object, path);
4341       return object == null || delete object[toKey(last(path))];
4342     }
4343
4344     /**
4345      * The base implementation of `_.update`.
4346      *
4347      * @private
4348      * @param {Object} object The object to modify.
4349      * @param {Array|string} path The path of the property to update.
4350      * @param {Function} updater The function to produce the updated value.
4351      * @param {Function} [customizer] The function to customize path creation.
4352      * @returns {Object} Returns `object`.
4353      */
4354     function baseUpdate(object, path, updater, customizer) {
4355       return baseSet(object, path, updater(baseGet(object, path)), customizer);
4356     }
4357
4358     /**
4359      * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
4360      * without support for iteratee shorthands.
4361      *
4362      * @private
4363      * @param {Array} array The array to query.
4364      * @param {Function} predicate The function invoked per iteration.
4365      * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
4366      * @param {boolean} [fromRight] Specify iterating from right to left.
4367      * @returns {Array} Returns the slice of `array`.
4368      */
4369     function baseWhile(array, predicate, isDrop, fromRight) {
4370       var length = array.length,
4371           index = fromRight ? length : -1;
4372
4373       while ((fromRight ? index-- : ++index < length) &&
4374         predicate(array[index], index, array)) {}
4375
4376       return isDrop
4377         ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
4378         : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
4379     }
4380
4381     /**
4382      * The base implementation of `wrapperValue` which returns the result of
4383      * performing a sequence of actions on the unwrapped `value`, where each
4384      * successive action is supplied the return value of the previous.
4385      *
4386      * @private
4387      * @param {*} value The unwrapped value.
4388      * @param {Array} actions Actions to perform to resolve the unwrapped value.
4389      * @returns {*} Returns the resolved value.
4390      */
4391     function baseWrapperValue(value, actions) {
4392       var result = value;
4393       if (result instanceof LazyWrapper) {
4394         result = result.value();
4395       }
4396       return arrayReduce(actions, function(result, action) {
4397         return action.func.apply(action.thisArg, arrayPush([result], action.args));
4398       }, result);
4399     }
4400
4401     /**
4402      * The base implementation of methods like `_.xor`, without support for
4403      * iteratee shorthands, that accepts an array of arrays to inspect.
4404      *
4405      * @private
4406      * @param {Array} arrays The arrays to inspect.
4407      * @param {Function} [iteratee] The iteratee invoked per element.
4408      * @param {Function} [comparator] The comparator invoked per element.
4409      * @returns {Array} Returns the new array of values.
4410      */
4411     function baseXor(arrays, iteratee, comparator) {
4412       var length = arrays.length;
4413       if (length < 2) {
4414         return length ? baseUniq(arrays[0]) : [];
4415       }
4416       var index = -1,
4417           result = Array(length);
4418
4419       while (++index < length) {
4420         var array = arrays[index],
4421             othIndex = -1;
4422
4423         while (++othIndex < length) {
4424           if (othIndex != index) {
4425             result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
4426           }
4427         }
4428       }
4429       return baseUniq(baseFlatten(result, 1), iteratee, comparator);
4430     }
4431
4432     /**
4433      * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
4434      *
4435      * @private
4436      * @param {Array} props The property identifiers.
4437      * @param {Array} values The property values.
4438      * @param {Function} assignFunc The function to assign values.
4439      * @returns {Object} Returns the new object.
4440      */
4441     function baseZipObject(props, values, assignFunc) {
4442       var index = -1,
4443           length = props.length,
4444           valsLength = values.length,
4445           result = {};
4446
4447       while (++index < length) {
4448         var value = index < valsLength ? values[index] : undefined;
4449         assignFunc(result, props[index], value);
4450       }
4451       return result;
4452     }
4453
4454     /**
4455      * Casts `value` to an empty array if it's not an array like object.
4456      *
4457      * @private
4458      * @param {*} value The value to inspect.
4459      * @returns {Array|Object} Returns the cast array-like object.
4460      */
4461     function castArrayLikeObject(value) {
4462       return isArrayLikeObject(value) ? value : [];
4463     }
4464
4465     /**
4466      * Casts `value` to `identity` if it's not a function.
4467      *
4468      * @private
4469      * @param {*} value The value to inspect.
4470      * @returns {Function} Returns cast function.
4471      */
4472     function castFunction(value) {
4473       return typeof value == 'function' ? value : identity;
4474     }
4475
4476     /**
4477      * Casts `value` to a path array if it's not one.
4478      *
4479      * @private
4480      * @param {*} value The value to inspect.
4481      * @param {Object} [object] The object to query keys on.
4482      * @returns {Array} Returns the cast property path array.
4483      */
4484     function castPath(value, object) {
4485       if (isArray(value)) {
4486         return value;
4487       }
4488       return isKey(value, object) ? [value] : stringToPath(toString(value));
4489     }
4490
4491     /**
4492      * A `baseRest` alias which can be replaced with `identity` by module
4493      * replacement plugins.
4494      *
4495      * @private
4496      * @type {Function}
4497      * @param {Function} func The function to apply a rest parameter to.
4498      * @returns {Function} Returns the new function.
4499      */
4500     var castRest = baseRest;
4501
4502     /**
4503      * Casts `array` to a slice if it's needed.
4504      *
4505      * @private
4506      * @param {Array} array The array to inspect.
4507      * @param {number} start The start position.
4508      * @param {number} [end=array.length] The end position.
4509      * @returns {Array} Returns the cast slice.
4510      */
4511     function castSlice(array, start, end) {
4512       var length = array.length;
4513       end = end === undefined ? length : end;
4514       return (!start && end >= length) ? array : baseSlice(array, start, end);
4515     }
4516
4517     /**
4518      * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
4519      *
4520      * @private
4521      * @param {number|Object} id The timer id or timeout object of the timer to clear.
4522      */
4523     var clearTimeout = ctxClearTimeout || function(id) {
4524       return root.clearTimeout(id);
4525     };
4526
4527     /**
4528      * Creates a clone of  `buffer`.
4529      *
4530      * @private
4531      * @param {Buffer} buffer The buffer to clone.
4532      * @param {boolean} [isDeep] Specify a deep clone.
4533      * @returns {Buffer} Returns the cloned buffer.
4534      */
4535     function cloneBuffer(buffer, isDeep) {
4536       if (isDeep) {
4537         return buffer.slice();
4538       }
4539       var length = buffer.length,
4540           result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
4541
4542       buffer.copy(result);
4543       return result;
4544     }
4545
4546     /**
4547      * Creates a clone of `arrayBuffer`.
4548      *
4549      * @private
4550      * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
4551      * @returns {ArrayBuffer} Returns the cloned array buffer.
4552      */
4553     function cloneArrayBuffer(arrayBuffer) {
4554       var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
4555       new Uint8Array(result).set(new Uint8Array(arrayBuffer));
4556       return result;
4557     }
4558
4559     /**
4560      * Creates a clone of `dataView`.
4561      *
4562      * @private
4563      * @param {Object} dataView The data view to clone.
4564      * @param {boolean} [isDeep] Specify a deep clone.
4565      * @returns {Object} Returns the cloned data view.
4566      */
4567     function cloneDataView(dataView, isDeep) {
4568       var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
4569       return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
4570     }
4571
4572     /**
4573      * Creates a clone of `map`.
4574      *
4575      * @private
4576      * @param {Object} map The map to clone.
4577      * @param {Function} cloneFunc The function to clone values.
4578      * @param {boolean} [isDeep] Specify a deep clone.
4579      * @returns {Object} Returns the cloned map.
4580      */
4581     function cloneMap(map, isDeep, cloneFunc) {
4582       var array = isDeep ? cloneFunc(mapToArray(map), CLONE_DEEP_FLAG) : mapToArray(map);
4583       return arrayReduce(array, addMapEntry, new map.constructor);
4584     }
4585
4586     /**
4587      * Creates a clone of `regexp`.
4588      *
4589      * @private
4590      * @param {Object} regexp The regexp to clone.
4591      * @returns {Object} Returns the cloned regexp.
4592      */
4593     function cloneRegExp(regexp) {
4594       var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
4595       result.lastIndex = regexp.lastIndex;
4596       return result;
4597     }
4598
4599     /**
4600      * Creates a clone of `set`.
4601      *
4602      * @private
4603      * @param {Object} set The set to clone.
4604      * @param {Function} cloneFunc The function to clone values.
4605      * @param {boolean} [isDeep] Specify a deep clone.
4606      * @returns {Object} Returns the cloned set.
4607      */
4608     function cloneSet(set, isDeep, cloneFunc) {
4609       var array = isDeep ? cloneFunc(setToArray(set), CLONE_DEEP_FLAG) : setToArray(set);
4610       return arrayReduce(array, addSetEntry, new set.constructor);
4611     }
4612
4613     /**
4614      * Creates a clone of the `symbol` object.
4615      *
4616      * @private
4617      * @param {Object} symbol The symbol object to clone.
4618      * @returns {Object} Returns the cloned symbol object.
4619      */
4620     function cloneSymbol(symbol) {
4621       return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
4622     }
4623
4624     /**
4625      * Creates a clone of `typedArray`.
4626      *
4627      * @private
4628      * @param {Object} typedArray The typed array to clone.
4629      * @param {boolean} [isDeep] Specify a deep clone.
4630      * @returns {Object} Returns the cloned typed array.
4631      */
4632     function cloneTypedArray(typedArray, isDeep) {
4633       var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
4634       return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
4635     }
4636
4637     /**
4638      * Compares values to sort them in ascending order.
4639      *
4640      * @private
4641      * @param {*} value The value to compare.
4642      * @param {*} other The other value to compare.
4643      * @returns {number} Returns the sort order indicator for `value`.
4644      */
4645     function compareAscending(value, other) {
4646       if (value !== other) {
4647         var valIsDefined = value !== undefined,
4648             valIsNull = value === null,
4649             valIsReflexive = value === value,
4650             valIsSymbol = isSymbol(value);
4651
4652         var othIsDefined = other !== undefined,
4653             othIsNull = other === null,
4654             othIsReflexive = other === other,
4655             othIsSymbol = isSymbol(other);
4656
4657         if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
4658             (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
4659             (valIsNull && othIsDefined && othIsReflexive) ||
4660             (!valIsDefined && othIsReflexive) ||
4661             !valIsReflexive) {
4662           return 1;
4663         }
4664         if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
4665             (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
4666             (othIsNull && valIsDefined && valIsReflexive) ||
4667             (!othIsDefined && valIsReflexive) ||
4668             !othIsReflexive) {
4669           return -1;
4670         }
4671       }
4672       return 0;
4673     }
4674
4675     /**
4676      * Used by `_.orderBy` to compare multiple properties of a value to another
4677      * and stable sort them.
4678      *
4679      * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
4680      * specify an order of "desc" for descending or "asc" for ascending sort order
4681      * of corresponding values.
4682      *
4683      * @private
4684      * @param {Object} object The object to compare.
4685      * @param {Object} other The other object to compare.
4686      * @param {boolean[]|string[]} orders The order to sort by for each property.
4687      * @returns {number} Returns the sort order indicator for `object`.
4688      */
4689     function compareMultiple(object, other, orders) {
4690       var index = -1,
4691           objCriteria = object.criteria,
4692           othCriteria = other.criteria,
4693           length = objCriteria.length,
4694           ordersLength = orders.length;
4695
4696       while (++index < length) {
4697         var result = compareAscending(objCriteria[index], othCriteria[index]);
4698         if (result) {
4699           if (index >= ordersLength) {
4700             return result;
4701           }
4702           var order = orders[index];
4703           return result * (order == 'desc' ? -1 : 1);
4704         }
4705       }
4706       // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
4707       // that causes it, under certain circumstances, to provide the same value for
4708       // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
4709       // for more details.
4710       //
4711       // This also ensures a stable sort in V8 and other engines.
4712       // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
4713       return object.index - other.index;
4714     }
4715
4716     /**
4717      * Creates an array that is the composition of partially applied arguments,
4718      * placeholders, and provided arguments into a single array of arguments.
4719      *
4720      * @private
4721      * @param {Array} args The provided arguments.
4722      * @param {Array} partials The arguments to prepend to those provided.
4723      * @param {Array} holders The `partials` placeholder indexes.
4724      * @params {boolean} [isCurried] Specify composing for a curried function.
4725      * @returns {Array} Returns the new array of composed arguments.
4726      */
4727     function composeArgs(args, partials, holders, isCurried) {
4728       var argsIndex = -1,
4729           argsLength = args.length,
4730           holdersLength = holders.length,
4731           leftIndex = -1,
4732           leftLength = partials.length,
4733           rangeLength = nativeMax(argsLength - holdersLength, 0),
4734           result = Array(leftLength + rangeLength),
4735           isUncurried = !isCurried;
4736
4737       while (++leftIndex < leftLength) {
4738         result[leftIndex] = partials[leftIndex];
4739       }
4740       while (++argsIndex < holdersLength) {
4741         if (isUncurried || argsIndex < argsLength) {
4742           result[holders[argsIndex]] = args[argsIndex];
4743         }
4744       }
4745       while (rangeLength--) {
4746         result[leftIndex++] = args[argsIndex++];
4747       }
4748       return result;
4749     }
4750
4751     /**
4752      * This function is like `composeArgs` except that the arguments composition
4753      * is tailored for `_.partialRight`.
4754      *
4755      * @private
4756      * @param {Array} args The provided arguments.
4757      * @param {Array} partials The arguments to append to those provided.
4758      * @param {Array} holders The `partials` placeholder indexes.
4759      * @params {boolean} [isCurried] Specify composing for a curried function.
4760      * @returns {Array} Returns the new array of composed arguments.
4761      */
4762     function composeArgsRight(args, partials, holders, isCurried) {
4763       var argsIndex = -1,
4764           argsLength = args.length,
4765           holdersIndex = -1,
4766           holdersLength = holders.length,
4767           rightIndex = -1,
4768           rightLength = partials.length,
4769           rangeLength = nativeMax(argsLength - holdersLength, 0),
4770           result = Array(rangeLength + rightLength),
4771           isUncurried = !isCurried;
4772
4773       while (++argsIndex < rangeLength) {
4774         result[argsIndex] = args[argsIndex];
4775       }
4776       var offset = argsIndex;
4777       while (++rightIndex < rightLength) {
4778         result[offset + rightIndex] = partials[rightIndex];
4779       }
4780       while (++holdersIndex < holdersLength) {
4781         if (isUncurried || argsIndex < argsLength) {
4782           result[offset + holders[holdersIndex]] = args[argsIndex++];
4783         }
4784       }
4785       return result;
4786     }
4787
4788     /**
4789      * Copies the values of `source` to `array`.
4790      *
4791      * @private
4792      * @param {Array} source The array to copy values from.
4793      * @param {Array} [array=[]] The array to copy values to.
4794      * @returns {Array} Returns `array`.
4795      */
4796     function copyArray(source, array) {
4797       var index = -1,
4798           length = source.length;
4799
4800       array || (array = Array(length));
4801       while (++index < length) {
4802         array[index] = source[index];
4803       }
4804       return array;
4805     }
4806
4807     /**
4808      * Copies properties of `source` to `object`.
4809      *
4810      * @private
4811      * @param {Object} source The object to copy properties from.
4812      * @param {Array} props The property identifiers to copy.
4813      * @param {Object} [object={}] The object to copy properties to.
4814      * @param {Function} [customizer] The function to customize copied values.
4815      * @returns {Object} Returns `object`.
4816      */
4817     function copyObject(source, props, object, customizer) {
4818       var isNew = !object;
4819       object || (object = {});
4820
4821       var index = -1,
4822           length = props.length;
4823
4824       while (++index < length) {
4825         var key = props[index];
4826
4827         var newValue = customizer
4828           ? customizer(object[key], source[key], key, object, source)
4829           : undefined;
4830
4831         if (newValue === undefined) {
4832           newValue = source[key];
4833         }
4834         if (isNew) {
4835           baseAssignValue(object, key, newValue);
4836         } else {
4837           assignValue(object, key, newValue);
4838         }
4839       }
4840       return object;
4841     }
4842
4843     /**
4844      * Copies own symbols of `source` to `object`.
4845      *
4846      * @private
4847      * @param {Object} source The object to copy symbols from.
4848      * @param {Object} [object={}] The object to copy symbols to.
4849      * @returns {Object} Returns `object`.
4850      */
4851     function copySymbols(source, object) {
4852       return copyObject(source, getSymbols(source), object);
4853     }
4854
4855     /**
4856      * Copies own and inherited symbols of `source` to `object`.
4857      *
4858      * @private
4859      * @param {Object} source The object to copy symbols from.
4860      * @param {Object} [object={}] The object to copy symbols to.
4861      * @returns {Object} Returns `object`.
4862      */
4863     function copySymbolsIn(source, object) {
4864       return copyObject(source, getSymbolsIn(source), object);
4865     }
4866
4867     /**
4868      * Creates a function like `_.groupBy`.
4869      *
4870      * @private
4871      * @param {Function} setter The function to set accumulator values.
4872      * @param {Function} [initializer] The accumulator object initializer.
4873      * @returns {Function} Returns the new aggregator function.
4874      */
4875     function createAggregator(setter, initializer) {
4876       return function(collection, iteratee) {
4877         var func = isArray(collection) ? arrayAggregator : baseAggregator,
4878             accumulator = initializer ? initializer() : {};
4879
4880         return func(collection, setter, getIteratee(iteratee, 2), accumulator);
4881       };
4882     }
4883
4884     /**
4885      * Creates a function like `_.assign`.
4886      *
4887      * @private
4888      * @param {Function} assigner The function to assign values.
4889      * @returns {Function} Returns the new assigner function.
4890      */
4891     function createAssigner(assigner) {
4892       return baseRest(function(object, sources) {
4893         var index = -1,
4894             length = sources.length,
4895             customizer = length > 1 ? sources[length - 1] : undefined,
4896             guard = length > 2 ? sources[2] : undefined;
4897
4898         customizer = (assigner.length > 3 && typeof customizer == 'function')
4899           ? (length--, customizer)
4900           : undefined;
4901
4902         if (guard && isIterateeCall(sources[0], sources[1], guard)) {
4903           customizer = length < 3 ? undefined : customizer;
4904           length = 1;
4905         }
4906         object = Object(object);
4907         while (++index < length) {
4908           var source = sources[index];
4909           if (source) {
4910             assigner(object, source, index, customizer);
4911           }
4912         }
4913         return object;
4914       });
4915     }
4916
4917     /**
4918      * Creates a `baseEach` or `baseEachRight` function.
4919      *
4920      * @private
4921      * @param {Function} eachFunc The function to iterate over a collection.
4922      * @param {boolean} [fromRight] Specify iterating from right to left.
4923      * @returns {Function} Returns the new base function.
4924      */
4925     function createBaseEach(eachFunc, fromRight) {
4926       return function(collection, iteratee) {
4927         if (collection == null) {
4928           return collection;
4929         }
4930         if (!isArrayLike(collection)) {
4931           return eachFunc(collection, iteratee);
4932         }
4933         var length = collection.length,
4934             index = fromRight ? length : -1,
4935             iterable = Object(collection);
4936
4937         while ((fromRight ? index-- : ++index < length)) {
4938           if (iteratee(iterable[index], index, iterable) === false) {
4939             break;
4940           }
4941         }
4942         return collection;
4943       };
4944     }
4945
4946     /**
4947      * Creates a base function for methods like `_.forIn` and `_.forOwn`.
4948      *
4949      * @private
4950      * @param {boolean} [fromRight] Specify iterating from right to left.
4951      * @returns {Function} Returns the new base function.
4952      */
4953     function createBaseFor(fromRight) {
4954       return function(object, iteratee, keysFunc) {
4955         var index = -1,
4956             iterable = Object(object),
4957             props = keysFunc(object),
4958             length = props.length;
4959
4960         while (length--) {
4961           var key = props[fromRight ? length : ++index];
4962           if (iteratee(iterable[key], key, iterable) === false) {
4963             break;
4964           }
4965         }
4966         return object;
4967       };
4968     }
4969
4970     /**
4971      * Creates a function that wraps `func` to invoke it with the optional `this`
4972      * binding of `thisArg`.
4973      *
4974      * @private
4975      * @param {Function} func The function to wrap.
4976      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
4977      * @param {*} [thisArg] The `this` binding of `func`.
4978      * @returns {Function} Returns the new wrapped function.
4979      */
4980     function createBind(func, bitmask, thisArg) {
4981       var isBind = bitmask & WRAP_BIND_FLAG,
4982           Ctor = createCtor(func);
4983
4984       function wrapper() {
4985         var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
4986         return fn.apply(isBind ? thisArg : this, arguments);
4987       }
4988       return wrapper;
4989     }
4990
4991     /**
4992      * Creates a function like `_.lowerFirst`.
4993      *
4994      * @private
4995      * @param {string} methodName The name of the `String` case method to use.
4996      * @returns {Function} Returns the new case function.
4997      */
4998     function createCaseFirst(methodName) {
4999       return function(string) {
5000         string = toString(string);
5001
5002         var strSymbols = hasUnicode(string)
5003           ? stringToArray(string)
5004           : undefined;
5005
5006         var chr = strSymbols
5007           ? strSymbols[0]
5008           : string.charAt(0);
5009
5010         var trailing = strSymbols
5011           ? castSlice(strSymbols, 1).join('')
5012           : string.slice(1);
5013
5014         return chr[methodName]() + trailing;
5015       };
5016     }
5017
5018     /**
5019      * Creates a function like `_.camelCase`.
5020      *
5021      * @private
5022      * @param {Function} callback The function to combine each word.
5023      * @returns {Function} Returns the new compounder function.
5024      */
5025     function createCompounder(callback) {
5026       return function(string) {
5027         return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
5028       };
5029     }
5030
5031     /**
5032      * Creates a function that produces an instance of `Ctor` regardless of
5033      * whether it was invoked as part of a `new` expression or by `call` or `apply`.
5034      *
5035      * @private
5036      * @param {Function} Ctor The constructor to wrap.
5037      * @returns {Function} Returns the new wrapped function.
5038      */
5039     function createCtor(Ctor) {
5040       return function() {
5041         // Use a `switch` statement to work with class constructors. See
5042         // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
5043         // for more details.
5044         var args = arguments;
5045         switch (args.length) {
5046           case 0: return new Ctor;
5047           case 1: return new Ctor(args[0]);
5048           case 2: return new Ctor(args[0], args[1]);
5049           case 3: return new Ctor(args[0], args[1], args[2]);
5050           case 4: return new Ctor(args[0], args[1], args[2], args[3]);
5051           case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
5052           case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
5053           case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
5054         }
5055         var thisBinding = baseCreate(Ctor.prototype),
5056             result = Ctor.apply(thisBinding, args);
5057
5058         // Mimic the constructor's `return` behavior.
5059         // See https://es5.github.io/#x13.2.2 for more details.
5060         return isObject(result) ? result : thisBinding;
5061       };
5062     }
5063
5064     /**
5065      * Creates a function that wraps `func` to enable currying.
5066      *
5067      * @private
5068      * @param {Function} func The function to wrap.
5069      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5070      * @param {number} arity The arity of `func`.
5071      * @returns {Function} Returns the new wrapped function.
5072      */
5073     function createCurry(func, bitmask, arity) {
5074       var Ctor = createCtor(func);
5075
5076       function wrapper() {
5077         var length = arguments.length,
5078             args = Array(length),
5079             index = length,
5080             placeholder = getHolder(wrapper);
5081
5082         while (index--) {
5083           args[index] = arguments[index];
5084         }
5085         var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
5086           ? []
5087           : replaceHolders(args, placeholder);
5088
5089         length -= holders.length;
5090         if (length < arity) {
5091           return createRecurry(
5092             func, bitmask, createHybrid, wrapper.placeholder, undefined,
5093             args, holders, undefined, undefined, arity - length);
5094         }
5095         var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
5096         return apply(fn, this, args);
5097       }
5098       return wrapper;
5099     }
5100
5101     /**
5102      * Creates a `_.find` or `_.findLast` function.
5103      *
5104      * @private
5105      * @param {Function} findIndexFunc The function to find the collection index.
5106      * @returns {Function} Returns the new find function.
5107      */
5108     function createFind(findIndexFunc) {
5109       return function(collection, predicate, fromIndex) {
5110         var iterable = Object(collection);
5111         if (!isArrayLike(collection)) {
5112           var iteratee = getIteratee(predicate, 3);
5113           collection = keys(collection);
5114           predicate = function(key) { return iteratee(iterable[key], key, iterable); };
5115         }
5116         var index = findIndexFunc(collection, predicate, fromIndex);
5117         return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
5118       };
5119     }
5120
5121     /**
5122      * Creates a `_.flow` or `_.flowRight` function.
5123      *
5124      * @private
5125      * @param {boolean} [fromRight] Specify iterating from right to left.
5126      * @returns {Function} Returns the new flow function.
5127      */
5128     function createFlow(fromRight) {
5129       return flatRest(function(funcs) {
5130         var length = funcs.length,
5131             index = length,
5132             prereq = LodashWrapper.prototype.thru;
5133
5134         if (fromRight) {
5135           funcs.reverse();
5136         }
5137         while (index--) {
5138           var func = funcs[index];
5139           if (typeof func != 'function') {
5140             throw new TypeError(FUNC_ERROR_TEXT);
5141           }
5142           if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
5143             var wrapper = new LodashWrapper([], true);
5144           }
5145         }
5146         index = wrapper ? index : length;
5147         while (++index < length) {
5148           func = funcs[index];
5149
5150           var funcName = getFuncName(func),
5151               data = funcName == 'wrapper' ? getData(func) : undefined;
5152
5153           if (data && isLaziable(data[0]) &&
5154                 data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
5155                 !data[4].length && data[9] == 1
5156               ) {
5157             wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
5158           } else {
5159             wrapper = (func.length == 1 && isLaziable(func))
5160               ? wrapper[funcName]()
5161               : wrapper.thru(func);
5162           }
5163         }
5164         return function() {
5165           var args = arguments,
5166               value = args[0];
5167
5168           if (wrapper && args.length == 1 && isArray(value)) {
5169             return wrapper.plant(value).value();
5170           }
5171           var index = 0,
5172               result = length ? funcs[index].apply(this, args) : value;
5173
5174           while (++index < length) {
5175             result = funcs[index].call(this, result);
5176           }
5177           return result;
5178         };
5179       });
5180     }
5181
5182     /**
5183      * Creates a function that wraps `func` to invoke it with optional `this`
5184      * binding of `thisArg`, partial application, and currying.
5185      *
5186      * @private
5187      * @param {Function|string} func The function or method name to wrap.
5188      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5189      * @param {*} [thisArg] The `this` binding of `func`.
5190      * @param {Array} [partials] The arguments to prepend to those provided to
5191      *  the new function.
5192      * @param {Array} [holders] The `partials` placeholder indexes.
5193      * @param {Array} [partialsRight] The arguments to append to those provided
5194      *  to the new function.
5195      * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
5196      * @param {Array} [argPos] The argument positions of the new function.
5197      * @param {number} [ary] The arity cap of `func`.
5198      * @param {number} [arity] The arity of `func`.
5199      * @returns {Function} Returns the new wrapped function.
5200      */
5201     function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
5202       var isAry = bitmask & WRAP_ARY_FLAG,
5203           isBind = bitmask & WRAP_BIND_FLAG,
5204           isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
5205           isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
5206           isFlip = bitmask & WRAP_FLIP_FLAG,
5207           Ctor = isBindKey ? undefined : createCtor(func);
5208
5209       function wrapper() {
5210         var length = arguments.length,
5211             args = Array(length),
5212             index = length;
5213
5214         while (index--) {
5215           args[index] = arguments[index];
5216         }
5217         if (isCurried) {
5218           var placeholder = getHolder(wrapper),
5219               holdersCount = countHolders(args, placeholder);
5220         }
5221         if (partials) {
5222           args = composeArgs(args, partials, holders, isCurried);
5223         }
5224         if (partialsRight) {
5225           args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
5226         }
5227         length -= holdersCount;
5228         if (isCurried && length < arity) {
5229           var newHolders = replaceHolders(args, placeholder);
5230           return createRecurry(
5231             func, bitmask, createHybrid, wrapper.placeholder, thisArg,
5232             args, newHolders, argPos, ary, arity - length
5233           );
5234         }
5235         var thisBinding = isBind ? thisArg : this,
5236             fn = isBindKey ? thisBinding[func] : func;
5237
5238         length = args.length;
5239         if (argPos) {
5240           args = reorder(args, argPos);
5241         } else if (isFlip && length > 1) {
5242           args.reverse();
5243         }
5244         if (isAry && ary < length) {
5245           args.length = ary;
5246         }
5247         if (this && this !== root && this instanceof wrapper) {
5248           fn = Ctor || createCtor(fn);
5249         }
5250         return fn.apply(thisBinding, args);
5251       }
5252       return wrapper;
5253     }
5254
5255     /**
5256      * Creates a function like `_.invertBy`.
5257      *
5258      * @private
5259      * @param {Function} setter The function to set accumulator values.
5260      * @param {Function} toIteratee The function to resolve iteratees.
5261      * @returns {Function} Returns the new inverter function.
5262      */
5263     function createInverter(setter, toIteratee) {
5264       return function(object, iteratee) {
5265         return baseInverter(object, setter, toIteratee(iteratee), {});
5266       };
5267     }
5268
5269     /**
5270      * Creates a function that performs a mathematical operation on two values.
5271      *
5272      * @private
5273      * @param {Function} operator The function to perform the operation.
5274      * @param {number} [defaultValue] The value used for `undefined` arguments.
5275      * @returns {Function} Returns the new mathematical operation function.
5276      */
5277     function createMathOperation(operator, defaultValue) {
5278       return function(value, other) {
5279         var result;
5280         if (value === undefined && other === undefined) {
5281           return defaultValue;
5282         }
5283         if (value !== undefined) {
5284           result = value;
5285         }
5286         if (other !== undefined) {
5287           if (result === undefined) {
5288             return other;
5289           }
5290           if (typeof value == 'string' || typeof other == 'string') {
5291             value = baseToString(value);
5292             other = baseToString(other);
5293           } else {
5294             value = baseToNumber(value);
5295             other = baseToNumber(other);
5296           }
5297           result = operator(value, other);
5298         }
5299         return result;
5300       };
5301     }
5302
5303     /**
5304      * Creates a function like `_.over`.
5305      *
5306      * @private
5307      * @param {Function} arrayFunc The function to iterate over iteratees.
5308      * @returns {Function} Returns the new over function.
5309      */
5310     function createOver(arrayFunc) {
5311       return flatRest(function(iteratees) {
5312         iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
5313         return baseRest(function(args) {
5314           var thisArg = this;
5315           return arrayFunc(iteratees, function(iteratee) {
5316             return apply(iteratee, thisArg, args);
5317           });
5318         });
5319       });
5320     }
5321
5322     /**
5323      * Creates the padding for `string` based on `length`. The `chars` string
5324      * is truncated if the number of characters exceeds `length`.
5325      *
5326      * @private
5327      * @param {number} length The padding length.
5328      * @param {string} [chars=' '] The string used as padding.
5329      * @returns {string} Returns the padding for `string`.
5330      */
5331     function createPadding(length, chars) {
5332       chars = chars === undefined ? ' ' : baseToString(chars);
5333
5334       var charsLength = chars.length;
5335       if (charsLength < 2) {
5336         return charsLength ? baseRepeat(chars, length) : chars;
5337       }
5338       var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
5339       return hasUnicode(chars)
5340         ? castSlice(stringToArray(result), 0, length).join('')
5341         : result.slice(0, length);
5342     }
5343
5344     /**
5345      * Creates a function that wraps `func` to invoke it with the `this` binding
5346      * of `thisArg` and `partials` prepended to the arguments it receives.
5347      *
5348      * @private
5349      * @param {Function} func The function to wrap.
5350      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5351      * @param {*} thisArg The `this` binding of `func`.
5352      * @param {Array} partials The arguments to prepend to those provided to
5353      *  the new function.
5354      * @returns {Function} Returns the new wrapped function.
5355      */
5356     function createPartial(func, bitmask, thisArg, partials) {
5357       var isBind = bitmask & WRAP_BIND_FLAG,
5358           Ctor = createCtor(func);
5359
5360       function wrapper() {
5361         var argsIndex = -1,
5362             argsLength = arguments.length,
5363             leftIndex = -1,
5364             leftLength = partials.length,
5365             args = Array(leftLength + argsLength),
5366             fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
5367
5368         while (++leftIndex < leftLength) {
5369           args[leftIndex] = partials[leftIndex];
5370         }
5371         while (argsLength--) {
5372           args[leftIndex++] = arguments[++argsIndex];
5373         }
5374         return apply(fn, isBind ? thisArg : this, args);
5375       }
5376       return wrapper;
5377     }
5378
5379     /**
5380      * Creates a `_.range` or `_.rangeRight` function.
5381      *
5382      * @private
5383      * @param {boolean} [fromRight] Specify iterating from right to left.
5384      * @returns {Function} Returns the new range function.
5385      */
5386     function createRange(fromRight) {
5387       return function(start, end, step) {
5388         if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
5389           end = step = undefined;
5390         }
5391         // Ensure the sign of `-0` is preserved.
5392         start = toFinite(start);
5393         if (end === undefined) {
5394           end = start;
5395           start = 0;
5396         } else {
5397           end = toFinite(end);
5398         }
5399         step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
5400         return baseRange(start, end, step, fromRight);
5401       };
5402     }
5403
5404     /**
5405      * Creates a function that performs a relational operation on two values.
5406      *
5407      * @private
5408      * @param {Function} operator The function to perform the operation.
5409      * @returns {Function} Returns the new relational operation function.
5410      */
5411     function createRelationalOperation(operator) {
5412       return function(value, other) {
5413         if (!(typeof value == 'string' && typeof other == 'string')) {
5414           value = toNumber(value);
5415           other = toNumber(other);
5416         }
5417         return operator(value, other);
5418       };
5419     }
5420
5421     /**
5422      * Creates a function that wraps `func` to continue currying.
5423      *
5424      * @private
5425      * @param {Function} func The function to wrap.
5426      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5427      * @param {Function} wrapFunc The function to create the `func` wrapper.
5428      * @param {*} placeholder The placeholder value.
5429      * @param {*} [thisArg] The `this` binding of `func`.
5430      * @param {Array} [partials] The arguments to prepend to those provided to
5431      *  the new function.
5432      * @param {Array} [holders] The `partials` placeholder indexes.
5433      * @param {Array} [argPos] The argument positions of the new function.
5434      * @param {number} [ary] The arity cap of `func`.
5435      * @param {number} [arity] The arity of `func`.
5436      * @returns {Function} Returns the new wrapped function.
5437      */
5438     function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
5439       var isCurry = bitmask & WRAP_CURRY_FLAG,
5440           newHolders = isCurry ? holders : undefined,
5441           newHoldersRight = isCurry ? undefined : holders,
5442           newPartials = isCurry ? partials : undefined,
5443           newPartialsRight = isCurry ? undefined : partials;
5444
5445       bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
5446       bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);
5447
5448       if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
5449         bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
5450       }
5451       var newData = [
5452         func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
5453         newHoldersRight, argPos, ary, arity
5454       ];
5455
5456       var result = wrapFunc.apply(undefined, newData);
5457       if (isLaziable(func)) {
5458         setData(result, newData);
5459       }
5460       result.placeholder = placeholder;
5461       return setWrapToString(result, func, bitmask);
5462     }
5463
5464     /**
5465      * Creates a function like `_.round`.
5466      *
5467      * @private
5468      * @param {string} methodName The name of the `Math` method to use when rounding.
5469      * @returns {Function} Returns the new round function.
5470      */
5471     function createRound(methodName) {
5472       var func = Math[methodName];
5473       return function(number, precision) {
5474         number = toNumber(number);
5475         precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
5476         if (precision) {
5477           // Shift with exponential notation to avoid floating-point issues.
5478           // See [MDN](https://mdn.io/round#Examples) for more details.
5479           var pair = (toString(number) + 'e').split('e'),
5480               value = func(pair[0] + 'e' + (+pair[1] + precision));
5481
5482           pair = (toString(value) + 'e').split('e');
5483           return +(pair[0] + 'e' + (+pair[1] - precision));
5484         }
5485         return func(number);
5486       };
5487     }
5488
5489     /**
5490      * Creates a set object of `values`.
5491      *
5492      * @private
5493      * @param {Array} values The values to add to the set.
5494      * @returns {Object} Returns the new set.
5495      */
5496     var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
5497       return new Set(values);
5498     };
5499
5500     /**
5501      * Creates a `_.toPairs` or `_.toPairsIn` function.
5502      *
5503      * @private
5504      * @param {Function} keysFunc The function to get the keys of a given object.
5505      * @returns {Function} Returns the new pairs function.
5506      */
5507     function createToPairs(keysFunc) {
5508       return function(object) {
5509         var tag = getTag(object);
5510         if (tag == mapTag) {
5511           return mapToArray(object);
5512         }
5513         if (tag == setTag) {
5514           return setToPairs(object);
5515         }
5516         return baseToPairs(object, keysFunc(object));
5517       };
5518     }
5519
5520     /**
5521      * Creates a function that either curries or invokes `func` with optional
5522      * `this` binding and partially applied arguments.
5523      *
5524      * @private
5525      * @param {Function|string} func The function or method name to wrap.
5526      * @param {number} bitmask The bitmask flags.
5527      *    1 - `_.bind`
5528      *    2 - `_.bindKey`
5529      *    4 - `_.curry` or `_.curryRight` of a bound function
5530      *    8 - `_.curry`
5531      *   16 - `_.curryRight`
5532      *   32 - `_.partial`
5533      *   64 - `_.partialRight`
5534      *  128 - `_.rearg`
5535      *  256 - `_.ary`
5536      *  512 - `_.flip`
5537      * @param {*} [thisArg] The `this` binding of `func`.
5538      * @param {Array} [partials] The arguments to be partially applied.
5539      * @param {Array} [holders] The `partials` placeholder indexes.
5540      * @param {Array} [argPos] The argument positions of the new function.
5541      * @param {number} [ary] The arity cap of `func`.
5542      * @param {number} [arity] The arity of `func`.
5543      * @returns {Function} Returns the new wrapped function.
5544      */
5545     function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
5546       var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
5547       if (!isBindKey && typeof func != 'function') {
5548         throw new TypeError(FUNC_ERROR_TEXT);
5549       }
5550       var length = partials ? partials.length : 0;
5551       if (!length) {
5552         bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
5553         partials = holders = undefined;
5554       }
5555       ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
5556       arity = arity === undefined ? arity : toInteger(arity);
5557       length -= holders ? holders.length : 0;
5558
5559       if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
5560         var partialsRight = partials,
5561             holdersRight = holders;
5562
5563         partials = holders = undefined;
5564       }
5565       var data = isBindKey ? undefined : getData(func);
5566
5567       var newData = [
5568         func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
5569         argPos, ary, arity
5570       ];
5571
5572       if (data) {
5573         mergeData(newData, data);
5574       }
5575       func = newData[0];
5576       bitmask = newData[1];
5577       thisArg = newData[2];
5578       partials = newData[3];
5579       holders = newData[4];
5580       arity = newData[9] = newData[9] === undefined
5581         ? (isBindKey ? 0 : func.length)
5582         : nativeMax(newData[9] - length, 0);
5583
5584       if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
5585         bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
5586       }
5587       if (!bitmask || bitmask == WRAP_BIND_FLAG) {
5588         var result = createBind(func, bitmask, thisArg);
5589       } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
5590         result = createCurry(func, bitmask, arity);
5591       } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) {
5592         result = createPartial(func, bitmask, thisArg, partials);
5593       } else {
5594         result = createHybrid.apply(undefined, newData);
5595       }
5596       var setter = data ? baseSetData : setData;
5597       return setWrapToString(setter(result, newData), func, bitmask);
5598     }
5599
5600     /**
5601      * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
5602      * of source objects to the destination object for all destination properties
5603      * that resolve to `undefined`.
5604      *
5605      * @private
5606      * @param {*} objValue The destination value.
5607      * @param {*} srcValue The source value.
5608      * @param {string} key The key of the property to assign.
5609      * @param {Object} object The parent object of `objValue`.
5610      * @returns {*} Returns the value to assign.
5611      */
5612     function customDefaultsAssignIn(objValue, srcValue, key, object) {
5613       if (objValue === undefined ||
5614           (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
5615         return srcValue;
5616       }
5617       return objValue;
5618     }
5619
5620     /**
5621      * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
5622      * objects into destination objects that are passed thru.
5623      *
5624      * @private
5625      * @param {*} objValue The destination value.
5626      * @param {*} srcValue The source value.
5627      * @param {string} key The key of the property to merge.
5628      * @param {Object} object The parent object of `objValue`.
5629      * @param {Object} source The parent object of `srcValue`.
5630      * @param {Object} [stack] Tracks traversed source values and their merged
5631      *  counterparts.
5632      * @returns {*} Returns the value to assign.
5633      */
5634     function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
5635       if (isObject(objValue) && isObject(srcValue)) {
5636         // Recursively merge objects and arrays (susceptible to call stack limits).
5637         stack.set(srcValue, objValue);
5638         baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
5639         stack['delete'](srcValue);
5640       }
5641       return objValue;
5642     }
5643
5644     /**
5645      * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
5646      * objects.
5647      *
5648      * @private
5649      * @param {*} value The value to inspect.
5650      * @param {string} key The key of the property to inspect.
5651      * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
5652      */
5653     function customOmitClone(value) {
5654       return isPlainObject(value) ? undefined : value;
5655     }
5656
5657     /**
5658      * A specialized version of `baseIsEqualDeep` for arrays with support for
5659      * partial deep comparisons.
5660      *
5661      * @private
5662      * @param {Array} array The array to compare.
5663      * @param {Array} other The other array to compare.
5664      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5665      * @param {Function} customizer The function to customize comparisons.
5666      * @param {Function} equalFunc The function to determine equivalents of values.
5667      * @param {Object} stack Tracks traversed `array` and `other` objects.
5668      * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
5669      */
5670     function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
5671       var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
5672           arrLength = array.length,
5673           othLength = other.length;
5674
5675       if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
5676         return false;
5677       }
5678       // Assume cyclic values are equal.
5679       var stacked = stack.get(array);
5680       if (stacked && stack.get(other)) {
5681         return stacked == other;
5682       }
5683       var index = -1,
5684           result = true,
5685           seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;
5686
5687       stack.set(array, other);
5688       stack.set(other, array);
5689
5690       // Ignore non-index properties.
5691       while (++index < arrLength) {
5692         var arrValue = array[index],
5693             othValue = other[index];
5694
5695         if (customizer) {
5696           var compared = isPartial
5697             ? customizer(othValue, arrValue, index, other, array, stack)
5698             : customizer(arrValue, othValue, index, array, other, stack);
5699         }
5700         if (compared !== undefined) {
5701           if (compared) {
5702             continue;
5703           }
5704           result = false;
5705           break;
5706         }
5707         // Recursively compare arrays (susceptible to call stack limits).
5708         if (seen) {
5709           if (!arraySome(other, function(othValue, othIndex) {
5710                 if (!cacheHas(seen, othIndex) &&
5711                     (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
5712                   return seen.push(othIndex);
5713                 }
5714               })) {
5715             result = false;
5716             break;
5717           }
5718         } else if (!(
5719               arrValue === othValue ||
5720                 equalFunc(arrValue, othValue, bitmask, customizer, stack)
5721             )) {
5722           result = false;
5723           break;
5724         }
5725       }
5726       stack['delete'](array);
5727       stack['delete'](other);
5728       return result;
5729     }
5730
5731     /**
5732      * A specialized version of `baseIsEqualDeep` for comparing objects of
5733      * the same `toStringTag`.
5734      *
5735      * **Note:** This function only supports comparing values with tags of
5736      * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
5737      *
5738      * @private
5739      * @param {Object} object The object to compare.
5740      * @param {Object} other The other object to compare.
5741      * @param {string} tag The `toStringTag` of the objects to compare.
5742      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5743      * @param {Function} customizer The function to customize comparisons.
5744      * @param {Function} equalFunc The function to determine equivalents of values.
5745      * @param {Object} stack Tracks traversed `object` and `other` objects.
5746      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
5747      */
5748     function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
5749       switch (tag) {
5750         case dataViewTag:
5751           if ((object.byteLength != other.byteLength) ||
5752               (object.byteOffset != other.byteOffset)) {
5753             return false;
5754           }
5755           object = object.buffer;
5756           other = other.buffer;
5757
5758         case arrayBufferTag:
5759           if ((object.byteLength != other.byteLength) ||
5760               !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
5761             return false;
5762           }
5763           return true;
5764
5765         case boolTag:
5766         case dateTag:
5767         case numberTag:
5768           // Coerce booleans to `1` or `0` and dates to milliseconds.
5769           // Invalid dates are coerced to `NaN`.
5770           return eq(+object, +other);
5771
5772         case errorTag:
5773           return object.name == other.name && object.message == other.message;
5774
5775         case regexpTag:
5776         case stringTag:
5777           // Coerce regexes to strings and treat strings, primitives and objects,
5778           // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
5779           // for more details.
5780           return object == (other + '');
5781
5782         case mapTag:
5783           var convert = mapToArray;
5784
5785         case setTag:
5786           var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
5787           convert || (convert = setToArray);
5788
5789           if (object.size != other.size && !isPartial) {
5790             return false;
5791           }
5792           // Assume cyclic values are equal.
5793           var stacked = stack.get(object);
5794           if (stacked) {
5795             return stacked == other;
5796           }
5797           bitmask |= COMPARE_UNORDERED_FLAG;
5798
5799           // Recursively compare objects (susceptible to call stack limits).
5800           stack.set(object, other);
5801           var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
5802           stack['delete'](object);
5803           return result;
5804
5805         case symbolTag:
5806           if (symbolValueOf) {
5807             return symbolValueOf.call(object) == symbolValueOf.call(other);
5808           }
5809       }
5810       return false;
5811     }
5812
5813     /**
5814      * A specialized version of `baseIsEqualDeep` for objects with support for
5815      * partial deep comparisons.
5816      *
5817      * @private
5818      * @param {Object} object The object to compare.
5819      * @param {Object} other The other object to compare.
5820      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5821      * @param {Function} customizer The function to customize comparisons.
5822      * @param {Function} equalFunc The function to determine equivalents of values.
5823      * @param {Object} stack Tracks traversed `object` and `other` objects.
5824      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
5825      */
5826     function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
5827       var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
5828           objProps = getAllKeys(object),
5829           objLength = objProps.length,
5830           othProps = getAllKeys(other),
5831           othLength = othProps.length;
5832
5833       if (objLength != othLength && !isPartial) {
5834         return false;
5835       }
5836       var index = objLength;
5837       while (index--) {
5838         var key = objProps[index];
5839         if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
5840           return false;
5841         }
5842       }
5843       // Assume cyclic values are equal.
5844       var stacked = stack.get(object);
5845       if (stacked && stack.get(other)) {
5846         return stacked == other;
5847       }
5848       var result = true;
5849       stack.set(object, other);
5850       stack.set(other, object);
5851
5852       var skipCtor = isPartial;
5853       while (++index < objLength) {
5854         key = objProps[index];
5855         var objValue = object[key],
5856             othValue = other[key];
5857
5858         if (customizer) {
5859           var compared = isPartial
5860             ? customizer(othValue, objValue, key, other, object, stack)
5861             : customizer(objValue, othValue, key, object, other, stack);
5862         }
5863         // Recursively compare objects (susceptible to call stack limits).
5864         if (!(compared === undefined
5865               ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
5866               : compared
5867             )) {
5868           result = false;
5869           break;
5870         }
5871         skipCtor || (skipCtor = key == 'constructor');
5872       }
5873       if (result && !skipCtor) {
5874         var objCtor = object.constructor,
5875             othCtor = other.constructor;
5876
5877         // Non `Object` object instances with different constructors are not equal.
5878         if (objCtor != othCtor &&
5879             ('constructor' in object && 'constructor' in other) &&
5880             !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
5881               typeof othCtor == 'function' && othCtor instanceof othCtor)) {
5882           result = false;
5883         }
5884       }
5885       stack['delete'](object);
5886       stack['delete'](other);
5887       return result;
5888     }
5889
5890     /**
5891      * A specialized version of `baseRest` which flattens the rest array.
5892      *
5893      * @private
5894      * @param {Function} func The function to apply a rest parameter to.
5895      * @returns {Function} Returns the new function.
5896      */
5897     function flatRest(func) {
5898       return setToString(overRest(func, undefined, flatten), func + '');
5899     }
5900
5901     /**
5902      * Creates an array of own enumerable property names and symbols of `object`.
5903      *
5904      * @private
5905      * @param {Object} object The object to query.
5906      * @returns {Array} Returns the array of property names and symbols.
5907      */
5908     function getAllKeys(object) {
5909       return baseGetAllKeys(object, keys, getSymbols);
5910     }
5911
5912     /**
5913      * Creates an array of own and inherited enumerable property names and
5914      * symbols of `object`.
5915      *
5916      * @private
5917      * @param {Object} object The object to query.
5918      * @returns {Array} Returns the array of property names and symbols.
5919      */
5920     function getAllKeysIn(object) {
5921       return baseGetAllKeys(object, keysIn, getSymbolsIn);
5922     }
5923
5924     /**
5925      * Gets metadata for `func`.
5926      *
5927      * @private
5928      * @param {Function} func The function to query.
5929      * @returns {*} Returns the metadata for `func`.
5930      */
5931     var getData = !metaMap ? noop : function(func) {
5932       return metaMap.get(func);
5933     };
5934
5935     /**
5936      * Gets the name of `func`.
5937      *
5938      * @private
5939      * @param {Function} func The function to query.
5940      * @returns {string} Returns the function name.
5941      */
5942     function getFuncName(func) {
5943       var result = (func.name + ''),
5944           array = realNames[result],
5945           length = hasOwnProperty.call(realNames, result) ? array.length : 0;
5946
5947       while (length--) {
5948         var data = array[length],
5949             otherFunc = data.func;
5950         if (otherFunc == null || otherFunc == func) {
5951           return data.name;
5952         }
5953       }
5954       return result;
5955     }
5956
5957     /**
5958      * Gets the argument placeholder value for `func`.
5959      *
5960      * @private
5961      * @param {Function} func The function to inspect.
5962      * @returns {*} Returns the placeholder value.
5963      */
5964     function getHolder(func) {
5965       var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
5966       return object.placeholder;
5967     }
5968
5969     /**
5970      * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
5971      * this function returns the custom method, otherwise it returns `baseIteratee`.
5972      * If arguments are provided, the chosen function is invoked with them and
5973      * its result is returned.
5974      *
5975      * @private
5976      * @param {*} [value] The value to convert to an iteratee.
5977      * @param {number} [arity] The arity of the created iteratee.
5978      * @returns {Function} Returns the chosen function or its result.
5979      */
5980     function getIteratee() {
5981       var result = lodash.iteratee || iteratee;
5982       result = result === iteratee ? baseIteratee : result;
5983       return arguments.length ? result(arguments[0], arguments[1]) : result;
5984     }
5985
5986     /**
5987      * Gets the data for `map`.
5988      *
5989      * @private
5990      * @param {Object} map The map to query.
5991      * @param {string} key The reference key.
5992      * @returns {*} Returns the map data.
5993      */
5994     function getMapData(map, key) {
5995       var data = map.__data__;
5996       return isKeyable(key)
5997         ? data[typeof key == 'string' ? 'string' : 'hash']
5998         : data.map;
5999     }
6000
6001     /**
6002      * Gets the property names, values, and compare flags of `object`.
6003      *
6004      * @private
6005      * @param {Object} object The object to query.
6006      * @returns {Array} Returns the match data of `object`.
6007      */
6008     function getMatchData(object) {
6009       var result = keys(object),
6010           length = result.length;
6011
6012       while (length--) {
6013         var key = result[length],
6014             value = object[key];
6015
6016         result[length] = [key, value, isStrictComparable(value)];
6017       }
6018       return result;
6019     }
6020
6021     /**
6022      * Gets the native function at `key` of `object`.
6023      *
6024      * @private
6025      * @param {Object} object The object to query.
6026      * @param {string} key The key of the method to get.
6027      * @returns {*} Returns the function if it's native, else `undefined`.
6028      */
6029     function getNative(object, key) {
6030       var value = getValue(object, key);
6031       return baseIsNative(value) ? value : undefined;
6032     }
6033
6034     /**
6035      * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
6036      *
6037      * @private
6038      * @param {*} value The value to query.
6039      * @returns {string} Returns the raw `toStringTag`.
6040      */
6041     function getRawTag(value) {
6042       var isOwn = hasOwnProperty.call(value, symToStringTag),
6043           tag = value[symToStringTag];
6044
6045       try {
6046         value[symToStringTag] = undefined;
6047         var unmasked = true;
6048       } catch (e) {}
6049
6050       var result = nativeObjectToString.call(value);
6051       if (unmasked) {
6052         if (isOwn) {
6053           value[symToStringTag] = tag;
6054         } else {
6055           delete value[symToStringTag];
6056         }
6057       }
6058       return result;
6059     }
6060
6061     /**
6062      * Creates an array of the own enumerable symbols of `object`.
6063      *
6064      * @private
6065      * @param {Object} object The object to query.
6066      * @returns {Array} Returns the array of symbols.
6067      */
6068     var getSymbols = !nativeGetSymbols ? stubArray : function(object) {
6069       if (object == null) {
6070         return [];
6071       }
6072       object = Object(object);
6073       return arrayFilter(nativeGetSymbols(object), function(symbol) {
6074         return propertyIsEnumerable.call(object, symbol);
6075       });
6076     };
6077
6078     /**
6079      * Creates an array of the own and inherited enumerable symbols of `object`.
6080      *
6081      * @private
6082      * @param {Object} object The object to query.
6083      * @returns {Array} Returns the array of symbols.
6084      */
6085     var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {
6086       var result = [];
6087       while (object) {
6088         arrayPush(result, getSymbols(object));
6089         object = getPrototype(object);
6090       }
6091       return result;
6092     };
6093
6094     /**
6095      * Gets the `toStringTag` of `value`.
6096      *
6097      * @private
6098      * @param {*} value The value to query.
6099      * @returns {string} Returns the `toStringTag`.
6100      */
6101     var getTag = baseGetTag;
6102
6103     // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
6104     if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
6105         (Map && getTag(new Map) != mapTag) ||
6106         (Promise && getTag(Promise.resolve()) != promiseTag) ||
6107         (Set && getTag(new Set) != setTag) ||
6108         (WeakMap && getTag(new WeakMap) != weakMapTag)) {
6109       getTag = function(value) {
6110         var result = baseGetTag(value),
6111             Ctor = result == objectTag ? value.constructor : undefined,
6112             ctorString = Ctor ? toSource(Ctor) : '';
6113
6114         if (ctorString) {
6115           switch (ctorString) {
6116             case dataViewCtorString: return dataViewTag;
6117             case mapCtorString: return mapTag;
6118             case promiseCtorString: return promiseTag;
6119             case setCtorString: return setTag;
6120             case weakMapCtorString: return weakMapTag;
6121           }
6122         }
6123         return result;
6124       };
6125     }
6126
6127     /**
6128      * Gets the view, applying any `transforms` to the `start` and `end` positions.
6129      *
6130      * @private
6131      * @param {number} start The start of the view.
6132      * @param {number} end The end of the view.
6133      * @param {Array} transforms The transformations to apply to the view.
6134      * @returns {Object} Returns an object containing the `start` and `end`
6135      *  positions of the view.
6136      */
6137     function getView(start, end, transforms) {
6138       var index = -1,
6139           length = transforms.length;
6140
6141       while (++index < length) {
6142         var data = transforms[index],
6143             size = data.size;
6144
6145         switch (data.type) {
6146           case 'drop':      start += size; break;
6147           case 'dropRight': end -= size; break;
6148           case 'take':      end = nativeMin(end, start + size); break;
6149           case 'takeRight': start = nativeMax(start, end - size); break;
6150         }
6151       }
6152       return { 'start': start, 'end': end };
6153     }
6154
6155     /**
6156      * Extracts wrapper details from the `source` body comment.
6157      *
6158      * @private
6159      * @param {string} source The source to inspect.
6160      * @returns {Array} Returns the wrapper details.
6161      */
6162     function getWrapDetails(source) {
6163       var match = source.match(reWrapDetails);
6164       return match ? match[1].split(reSplitDetails) : [];
6165     }
6166
6167     /**
6168      * Checks if `path` exists on `object`.
6169      *
6170      * @private
6171      * @param {Object} object The object to query.
6172      * @param {Array|string} path The path to check.
6173      * @param {Function} hasFunc The function to check properties.
6174      * @returns {boolean} Returns `true` if `path` exists, else `false`.
6175      */
6176     function hasPath(object, path, hasFunc) {
6177       path = castPath(path, object);
6178
6179       var index = -1,
6180           length = path.length,
6181           result = false;
6182
6183       while (++index < length) {
6184         var key = toKey(path[index]);
6185         if (!(result = object != null && hasFunc(object, key))) {
6186           break;
6187         }
6188         object = object[key];
6189       }
6190       if (result || ++index != length) {
6191         return result;
6192       }
6193       length = object == null ? 0 : object.length;
6194       return !!length && isLength(length) && isIndex(key, length) &&
6195         (isArray(object) || isArguments(object));
6196     }
6197
6198     /**
6199      * Initializes an array clone.
6200      *
6201      * @private
6202      * @param {Array} array The array to clone.
6203      * @returns {Array} Returns the initialized clone.
6204      */
6205     function initCloneArray(array) {
6206       var length = array.length,
6207           result = array.constructor(length);
6208
6209       // Add properties assigned by `RegExp#exec`.
6210       if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
6211         result.index = array.index;
6212         result.input = array.input;
6213       }
6214       return result;
6215     }
6216
6217     /**
6218      * Initializes an object clone.
6219      *
6220      * @private
6221      * @param {Object} object The object to clone.
6222      * @returns {Object} Returns the initialized clone.
6223      */
6224     function initCloneObject(object) {
6225       return (typeof object.constructor == 'function' && !isPrototype(object))
6226         ? baseCreate(getPrototype(object))
6227         : {};
6228     }
6229
6230     /**
6231      * Initializes an object clone based on its `toStringTag`.
6232      *
6233      * **Note:** This function only supports cloning values with tags of
6234      * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
6235      *
6236      * @private
6237      * @param {Object} object The object to clone.
6238      * @param {string} tag The `toStringTag` of the object to clone.
6239      * @param {Function} cloneFunc The function to clone values.
6240      * @param {boolean} [isDeep] Specify a deep clone.
6241      * @returns {Object} Returns the initialized clone.
6242      */
6243     function initCloneByTag(object, tag, cloneFunc, isDeep) {
6244       var Ctor = object.constructor;
6245       switch (tag) {
6246         case arrayBufferTag:
6247           return cloneArrayBuffer(object);
6248
6249         case boolTag:
6250         case dateTag:
6251           return new Ctor(+object);
6252
6253         case dataViewTag:
6254           return cloneDataView(object, isDeep);
6255
6256         case float32Tag: case float64Tag:
6257         case int8Tag: case int16Tag: case int32Tag:
6258         case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
6259           return cloneTypedArray(object, isDeep);
6260
6261         case mapTag:
6262           return cloneMap(object, isDeep, cloneFunc);
6263
6264         case numberTag:
6265         case stringTag:
6266           return new Ctor(object);
6267
6268         case regexpTag:
6269           return cloneRegExp(object);
6270
6271         case setTag:
6272           return cloneSet(object, isDeep, cloneFunc);
6273
6274         case symbolTag:
6275           return cloneSymbol(object);
6276       }
6277     }
6278
6279     /**
6280      * Inserts wrapper `details` in a comment at the top of the `source` body.
6281      *
6282      * @private
6283      * @param {string} source The source to modify.
6284      * @returns {Array} details The details to insert.
6285      * @returns {string} Returns the modified source.
6286      */
6287     function insertWrapDetails(source, details) {
6288       var length = details.length;
6289       if (!length) {
6290         return source;
6291       }
6292       var lastIndex = length - 1;
6293       details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
6294       details = details.join(length > 2 ? ', ' : ' ');
6295       return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
6296     }
6297
6298     /**
6299      * Checks if `value` is a flattenable `arguments` object or array.
6300      *
6301      * @private
6302      * @param {*} value The value to check.
6303      * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
6304      */
6305     function isFlattenable(value) {
6306       return isArray(value) || isArguments(value) ||
6307         !!(spreadableSymbol && value && value[spreadableSymbol]);
6308     }
6309
6310     /**
6311      * Checks if `value` is a valid array-like index.
6312      *
6313      * @private
6314      * @param {*} value The value to check.
6315      * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
6316      * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
6317      */
6318     function isIndex(value, length) {
6319       length = length == null ? MAX_SAFE_INTEGER : length;
6320       return !!length &&
6321         (typeof value == 'number' || reIsUint.test(value)) &&
6322         (value > -1 && value % 1 == 0 && value < length);
6323     }
6324
6325     /**
6326      * Checks if the given arguments are from an iteratee call.
6327      *
6328      * @private
6329      * @param {*} value The potential iteratee value argument.
6330      * @param {*} index The potential iteratee index or key argument.
6331      * @param {*} object The potential iteratee object argument.
6332      * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
6333      *  else `false`.
6334      */
6335     function isIterateeCall(value, index, object) {
6336       if (!isObject(object)) {
6337         return false;
6338       }
6339       var type = typeof index;
6340       if (type == 'number'
6341             ? (isArrayLike(object) && isIndex(index, object.length))
6342             : (type == 'string' && index in object)
6343           ) {
6344         return eq(object[index], value);
6345       }
6346       return false;
6347     }
6348
6349     /**
6350      * Checks if `value` is a property name and not a property path.
6351      *
6352      * @private
6353      * @param {*} value The value to check.
6354      * @param {Object} [object] The object to query keys on.
6355      * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
6356      */
6357     function isKey(value, object) {
6358       if (isArray(value)) {
6359         return false;
6360       }
6361       var type = typeof value;
6362       if (type == 'number' || type == 'symbol' || type == 'boolean' ||
6363           value == null || isSymbol(value)) {
6364         return true;
6365       }
6366       return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
6367         (object != null && value in Object(object));
6368     }
6369
6370     /**
6371      * Checks if `value` is suitable for use as unique object key.
6372      *
6373      * @private
6374      * @param {*} value The value to check.
6375      * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
6376      */
6377     function isKeyable(value) {
6378       var type = typeof value;
6379       return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
6380         ? (value !== '__proto__')
6381         : (value === null);
6382     }
6383
6384     /**
6385      * Checks if `func` has a lazy counterpart.
6386      *
6387      * @private
6388      * @param {Function} func The function to check.
6389      * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
6390      *  else `false`.
6391      */
6392     function isLaziable(func) {
6393       var funcName = getFuncName(func),
6394           other = lodash[funcName];
6395
6396       if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
6397         return false;
6398       }
6399       if (func === other) {
6400         return true;
6401       }
6402       var data = getData(other);
6403       return !!data && func === data[0];
6404     }
6405
6406     /**
6407      * Checks if `func` has its source masked.
6408      *
6409      * @private
6410      * @param {Function} func The function to check.
6411      * @returns {boolean} Returns `true` if `func` is masked, else `false`.
6412      */
6413     function isMasked(func) {
6414       return !!maskSrcKey && (maskSrcKey in func);
6415     }
6416
6417     /**
6418      * Checks if `func` is capable of being masked.
6419      *
6420      * @private
6421      * @param {*} value The value to check.
6422      * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
6423      */
6424     var isMaskable = coreJsData ? isFunction : stubFalse;
6425
6426     /**
6427      * Checks if `value` is likely a prototype object.
6428      *
6429      * @private
6430      * @param {*} value The value to check.
6431      * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
6432      */
6433     function isPrototype(value) {
6434       var Ctor = value && value.constructor,
6435           proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
6436
6437       return value === proto;
6438     }
6439
6440     /**
6441      * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
6442      *
6443      * @private
6444      * @param {*} value The value to check.
6445      * @returns {boolean} Returns `true` if `value` if suitable for strict
6446      *  equality comparisons, else `false`.
6447      */
6448     function isStrictComparable(value) {
6449       return value === value && !isObject(value);
6450     }
6451
6452     /**
6453      * A specialized version of `matchesProperty` for source values suitable
6454      * for strict equality comparisons, i.e. `===`.
6455      *
6456      * @private
6457      * @param {string} key The key of the property to get.
6458      * @param {*} srcValue The value to match.
6459      * @returns {Function} Returns the new spec function.
6460      */
6461     function matchesStrictComparable(key, srcValue) {
6462       return function(object) {
6463         if (object == null) {
6464           return false;
6465         }
6466         return object[key] === srcValue &&
6467           (srcValue !== undefined || (key in Object(object)));
6468       };
6469     }
6470
6471     /**
6472      * A specialized version of `_.memoize` which clears the memoized function's
6473      * cache when it exceeds `MAX_MEMOIZE_SIZE`.
6474      *
6475      * @private
6476      * @param {Function} func The function to have its output memoized.
6477      * @returns {Function} Returns the new memoized function.
6478      */
6479     function memoizeCapped(func) {
6480       var result = memoize(func, function(key) {
6481         if (cache.size === MAX_MEMOIZE_SIZE) {
6482           cache.clear();
6483         }
6484         return key;
6485       });
6486
6487       var cache = result.cache;
6488       return result;
6489     }
6490
6491     /**
6492      * Merges the function metadata of `source` into `data`.
6493      *
6494      * Merging metadata reduces the number of wrappers used to invoke a function.
6495      * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
6496      * may be applied regardless of execution order. Methods like `_.ary` and
6497      * `_.rearg` modify function arguments, making the order in which they are
6498      * executed important, preventing the merging of metadata. However, we make
6499      * an exception for a safe combined case where curried functions have `_.ary`
6500      * and or `_.rearg` applied.
6501      *
6502      * @private
6503      * @param {Array} data The destination metadata.
6504      * @param {Array} source The source metadata.
6505      * @returns {Array} Returns `data`.
6506      */
6507     function mergeData(data, source) {
6508       var bitmask = data[1],
6509           srcBitmask = source[1],
6510           newBitmask = bitmask | srcBitmask,
6511           isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);
6512
6513       var isCombo =
6514         ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) ||
6515         ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) ||
6516         ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG));
6517
6518       // Exit early if metadata can't be merged.
6519       if (!(isCommon || isCombo)) {
6520         return data;
6521       }
6522       // Use source `thisArg` if available.
6523       if (srcBitmask & WRAP_BIND_FLAG) {
6524         data[2] = source[2];
6525         // Set when currying a bound function.
6526         newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
6527       }
6528       // Compose partial arguments.
6529       var value = source[3];
6530       if (value) {
6531         var partials = data[3];
6532         data[3] = partials ? composeArgs(partials, value, source[4]) : value;
6533         data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
6534       }
6535       // Compose partial right arguments.
6536       value = source[5];
6537       if (value) {
6538         partials = data[5];
6539         data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
6540         data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
6541       }
6542       // Use source `argPos` if available.
6543       value = source[7];
6544       if (value) {
6545         data[7] = value;
6546       }
6547       // Use source `ary` if it's smaller.
6548       if (srcBitmask & WRAP_ARY_FLAG) {
6549         data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
6550       }
6551       // Use source `arity` if one is not provided.
6552       if (data[9] == null) {
6553         data[9] = source[9];
6554       }
6555       // Use source `func` and merge bitmasks.
6556       data[0] = source[0];
6557       data[1] = newBitmask;
6558
6559       return data;
6560     }
6561
6562     /**
6563      * This function is like
6564      * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
6565      * except that it includes inherited enumerable properties.
6566      *
6567      * @private
6568      * @param {Object} object The object to query.
6569      * @returns {Array} Returns the array of property names.
6570      */
6571     function nativeKeysIn(object) {
6572       var result = [];
6573       if (object != null) {
6574         for (var key in Object(object)) {
6575           result.push(key);
6576         }
6577       }
6578       return result;
6579     }
6580
6581     /**
6582      * Converts `value` to a string using `Object.prototype.toString`.
6583      *
6584      * @private
6585      * @param {*} value The value to convert.
6586      * @returns {string} Returns the converted string.
6587      */
6588     function objectToString(value) {
6589       return nativeObjectToString.call(value);
6590     }
6591
6592     /**
6593      * A specialized version of `baseRest` which transforms the rest array.
6594      *
6595      * @private
6596      * @param {Function} func The function to apply a rest parameter to.
6597      * @param {number} [start=func.length-1] The start position of the rest parameter.
6598      * @param {Function} transform The rest array transform.
6599      * @returns {Function} Returns the new function.
6600      */
6601     function overRest(func, start, transform) {
6602       start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
6603       return function() {
6604         var args = arguments,
6605             index = -1,
6606             length = nativeMax(args.length - start, 0),
6607             array = Array(length);
6608
6609         while (++index < length) {
6610           array[index] = args[start + index];
6611         }
6612         index = -1;
6613         var otherArgs = Array(start + 1);
6614         while (++index < start) {
6615           otherArgs[index] = args[index];
6616         }
6617         otherArgs[start] = transform(array);
6618         return apply(func, this, otherArgs);
6619       };
6620     }
6621
6622     /**
6623      * Gets the parent value at `path` of `object`.
6624      *
6625      * @private
6626      * @param {Object} object The object to query.
6627      * @param {Array} path The path to get the parent value of.
6628      * @returns {*} Returns the parent value.
6629      */
6630     function parent(object, path) {
6631       return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
6632     }
6633
6634     /**
6635      * Reorder `array` according to the specified indexes where the element at
6636      * the first index is assigned as the first element, the element at
6637      * the second index is assigned as the second element, and so on.
6638      *
6639      * @private
6640      * @param {Array} array The array to reorder.
6641      * @param {Array} indexes The arranged array indexes.
6642      * @returns {Array} Returns `array`.
6643      */
6644     function reorder(array, indexes) {
6645       var arrLength = array.length,
6646           length = nativeMin(indexes.length, arrLength),
6647           oldArray = copyArray(array);
6648
6649       while (length--) {
6650         var index = indexes[length];
6651         array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
6652       }
6653       return array;
6654     }
6655
6656     /**
6657      * Sets metadata for `func`.
6658      *
6659      * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
6660      * period of time, it will trip its breaker and transition to an identity
6661      * function to avoid garbage collection pauses in V8. See
6662      * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
6663      * for more details.
6664      *
6665      * @private
6666      * @param {Function} func The function to associate metadata with.
6667      * @param {*} data The metadata.
6668      * @returns {Function} Returns `func`.
6669      */
6670     var setData = shortOut(baseSetData);
6671
6672     /**
6673      * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
6674      *
6675      * @private
6676      * @param {Function} func The function to delay.
6677      * @param {number} wait The number of milliseconds to delay invocation.
6678      * @returns {number|Object} Returns the timer id or timeout object.
6679      */
6680     var setTimeout = ctxSetTimeout || function(func, wait) {
6681       return root.setTimeout(func, wait);
6682     };
6683
6684     /**
6685      * Sets the `toString` method of `func` to return `string`.
6686      *
6687      * @private
6688      * @param {Function} func The function to modify.
6689      * @param {Function} string The `toString` result.
6690      * @returns {Function} Returns `func`.
6691      */
6692     var setToString = shortOut(baseSetToString);
6693
6694     /**
6695      * Sets the `toString` method of `wrapper` to mimic the source of `reference`
6696      * with wrapper details in a comment at the top of the source body.
6697      *
6698      * @private
6699      * @param {Function} wrapper The function to modify.
6700      * @param {Function} reference The reference function.
6701      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6702      * @returns {Function} Returns `wrapper`.
6703      */
6704     function setWrapToString(wrapper, reference, bitmask) {
6705       var source = (reference + '');
6706       return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)));
6707     }
6708
6709     /**
6710      * Creates a function that'll short out and invoke `identity` instead
6711      * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
6712      * milliseconds.
6713      *
6714      * @private
6715      * @param {Function} func The function to restrict.
6716      * @returns {Function} Returns the new shortable function.
6717      */
6718     function shortOut(func) {
6719       var count = 0,
6720           lastCalled = 0;
6721
6722       return function() {
6723         var stamp = nativeNow(),
6724             remaining = HOT_SPAN - (stamp - lastCalled);
6725
6726         lastCalled = stamp;
6727         if (remaining > 0) {
6728           if (++count >= HOT_COUNT) {
6729             return arguments[0];
6730           }
6731         } else {
6732           count = 0;
6733         }
6734         return func.apply(undefined, arguments);
6735       };
6736     }
6737
6738     /**
6739      * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
6740      *
6741      * @private
6742      * @param {Array} array The array to shuffle.
6743      * @param {number} [size=array.length] The size of `array`.
6744      * @returns {Array} Returns `array`.
6745      */
6746     function shuffleSelf(array, size) {
6747       var index = -1,
6748           length = array.length,
6749           lastIndex = length - 1;
6750
6751       size = size === undefined ? length : size;
6752       while (++index < size) {
6753         var rand = baseRandom(index, lastIndex),
6754             value = array[rand];
6755
6756         array[rand] = array[index];
6757         array[index] = value;
6758       }
6759       array.length = size;
6760       return array;
6761     }
6762
6763     /**
6764      * Converts `string` to a property path array.
6765      *
6766      * @private
6767      * @param {string} string The string to convert.
6768      * @returns {Array} Returns the property path array.
6769      */
6770     var stringToPath = memoizeCapped(function(string) {
6771       var result = [];
6772       if (reLeadingDot.test(string)) {
6773         result.push('');
6774       }
6775       string.replace(rePropName, function(match, number, quote, string) {
6776         result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
6777       });
6778       return result;
6779     });
6780
6781     /**
6782      * Converts `value` to a string key if it's not a string or symbol.
6783      *
6784      * @private
6785      * @param {*} value The value to inspect.
6786      * @returns {string|symbol} Returns the key.
6787      */
6788     function toKey(value) {
6789       if (typeof value == 'string' || isSymbol(value)) {
6790         return value;
6791       }
6792       var result = (value + '');
6793       return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
6794     }
6795
6796     /**
6797      * Converts `func` to its source code.
6798      *
6799      * @private
6800      * @param {Function} func The function to convert.
6801      * @returns {string} Returns the source code.
6802      */
6803     function toSource(func) {
6804       if (func != null) {
6805         try {
6806           return funcToString.call(func);
6807         } catch (e) {}
6808         try {
6809           return (func + '');
6810         } catch (e) {}
6811       }
6812       return '';
6813     }
6814
6815     /**
6816      * Updates wrapper `details` based on `bitmask` flags.
6817      *
6818      * @private
6819      * @returns {Array} details The details to modify.
6820      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6821      * @returns {Array} Returns `details`.
6822      */
6823     function updateWrapDetails(details, bitmask) {
6824       arrayEach(wrapFlags, function(pair) {
6825         var value = '_.' + pair[0];
6826         if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
6827           details.push(value);
6828         }
6829       });
6830       return details.sort();
6831     }
6832
6833     /**
6834      * Creates a clone of `wrapper`.
6835      *
6836      * @private
6837      * @param {Object} wrapper The wrapper to clone.
6838      * @returns {Object} Returns the cloned wrapper.
6839      */
6840     function wrapperClone(wrapper) {
6841       if (wrapper instanceof LazyWrapper) {
6842         return wrapper.clone();
6843       }
6844       var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
6845       result.__actions__ = copyArray(wrapper.__actions__);
6846       result.__index__  = wrapper.__index__;
6847       result.__values__ = wrapper.__values__;
6848       return result;
6849     }
6850
6851     /*------------------------------------------------------------------------*/
6852
6853     /**
6854      * Creates an array of elements split into groups the length of `size`.
6855      * If `array` can't be split evenly, the final chunk will be the remaining
6856      * elements.
6857      *
6858      * @static
6859      * @memberOf _
6860      * @since 3.0.0
6861      * @category Array
6862      * @param {Array} array The array to process.
6863      * @param {number} [size=1] The length of each chunk
6864      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
6865      * @returns {Array} Returns the new array of chunks.
6866      * @example
6867      *
6868      * _.chunk(['a', 'b', 'c', 'd'], 2);
6869      * // => [['a', 'b'], ['c', 'd']]
6870      *
6871      * _.chunk(['a', 'b', 'c', 'd'], 3);
6872      * // => [['a', 'b', 'c'], ['d']]
6873      */
6874     function chunk(array, size, guard) {
6875       if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
6876         size = 1;
6877       } else {
6878         size = nativeMax(toInteger(size), 0);
6879       }
6880       var length = array == null ? 0 : array.length;
6881       if (!length || size < 1) {
6882         return [];
6883       }
6884       var index = 0,
6885           resIndex = 0,
6886           result = Array(nativeCeil(length / size));
6887
6888       while (index < length) {
6889         result[resIndex++] = baseSlice(array, index, (index += size));
6890       }
6891       return result;
6892     }
6893
6894     /**
6895      * Creates an array with all falsey values removed. The values `false`, `null`,
6896      * `0`, `""`, `undefined`, and `NaN` are falsey.
6897      *
6898      * @static
6899      * @memberOf _
6900      * @since 0.1.0
6901      * @category Array
6902      * @param {Array} array The array to compact.
6903      * @returns {Array} Returns the new array of filtered values.
6904      * @example
6905      *
6906      * _.compact([0, 1, false, 2, '', 3]);
6907      * // => [1, 2, 3]
6908      */
6909     function compact(array) {
6910       var index = -1,
6911           length = array == null ? 0 : array.length,
6912           resIndex = 0,
6913           result = [];
6914
6915       while (++index < length) {
6916         var value = array[index];
6917         if (value) {
6918           result[resIndex++] = value;
6919         }
6920       }
6921       return result;
6922     }
6923
6924     /**
6925      * Creates a new array concatenating `array` with any additional arrays
6926      * and/or values.
6927      *
6928      * @static
6929      * @memberOf _
6930      * @since 4.0.0
6931      * @category Array
6932      * @param {Array} array The array to concatenate.
6933      * @param {...*} [values] The values to concatenate.
6934      * @returns {Array} Returns the new concatenated array.
6935      * @example
6936      *
6937      * var array = [1];
6938      * var other = _.concat(array, 2, [3], [[4]]);
6939      *
6940      * console.log(other);
6941      * // => [1, 2, 3, [4]]
6942      *
6943      * console.log(array);
6944      * // => [1]
6945      */
6946     function concat() {
6947       var length = arguments.length;
6948       if (!length) {
6949         return [];
6950       }
6951       var args = Array(length - 1),
6952           array = arguments[0],
6953           index = length;
6954
6955       while (index--) {
6956         args[index - 1] = arguments[index];
6957       }
6958       return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
6959     }
6960
6961     /**
6962      * Creates an array of `array` values not included in the other given arrays
6963      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
6964      * for equality comparisons. The order and references of result values are
6965      * determined by the first array.
6966      *
6967      * **Note:** Unlike `_.pullAll`, this method returns a new array.
6968      *
6969      * @static
6970      * @memberOf _
6971      * @since 0.1.0
6972      * @category Array
6973      * @param {Array} array The array to inspect.
6974      * @param {...Array} [values] The values to exclude.
6975      * @returns {Array} Returns the new array of filtered values.
6976      * @see _.without, _.xor
6977      * @example
6978      *
6979      * _.difference([2, 1], [2, 3]);
6980      * // => [1]
6981      */
6982     var difference = baseRest(function(array, values) {
6983       return isArrayLikeObject(array)
6984         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
6985         : [];
6986     });
6987
6988     /**
6989      * This method is like `_.difference` except that it accepts `iteratee` which
6990      * is invoked for each element of `array` and `values` to generate the criterion
6991      * by which they're compared. The order and references of result values are
6992      * determined by the first array. The iteratee is invoked with one argument:
6993      * (value).
6994      *
6995      * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
6996      *
6997      * @static
6998      * @memberOf _
6999      * @since 4.0.0
7000      * @category Array
7001      * @param {Array} array The array to inspect.
7002      * @param {...Array} [values] The values to exclude.
7003      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7004      * @returns {Array} Returns the new array of filtered values.
7005      * @example
7006      *
7007      * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
7008      * // => [1.2]
7009      *
7010      * // The `_.property` iteratee shorthand.
7011      * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
7012      * // => [{ 'x': 2 }]
7013      */
7014     var differenceBy = baseRest(function(array, values) {
7015       var iteratee = last(values);
7016       if (isArrayLikeObject(iteratee)) {
7017         iteratee = undefined;
7018       }
7019       return isArrayLikeObject(array)
7020         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2))
7021         : [];
7022     });
7023
7024     /**
7025      * This method is like `_.difference` except that it accepts `comparator`
7026      * which is invoked to compare elements of `array` to `values`. The order and
7027      * references of result values are determined by the first array. The comparator
7028      * is invoked with two arguments: (arrVal, othVal).
7029      *
7030      * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
7031      *
7032      * @static
7033      * @memberOf _
7034      * @since 4.0.0
7035      * @category Array
7036      * @param {Array} array The array to inspect.
7037      * @param {...Array} [values] The values to exclude.
7038      * @param {Function} [comparator] The comparator invoked per element.
7039      * @returns {Array} Returns the new array of filtered values.
7040      * @example
7041      *
7042      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
7043      *
7044      * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
7045      * // => [{ 'x': 2, 'y': 1 }]
7046      */
7047     var differenceWith = baseRest(function(array, values) {
7048       var comparator = last(values);
7049       if (isArrayLikeObject(comparator)) {
7050         comparator = undefined;
7051       }
7052       return isArrayLikeObject(array)
7053         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
7054         : [];
7055     });
7056
7057     /**
7058      * Creates a slice of `array` with `n` elements dropped from the beginning.
7059      *
7060      * @static
7061      * @memberOf _
7062      * @since 0.5.0
7063      * @category Array
7064      * @param {Array} array The array to query.
7065      * @param {number} [n=1] The number of elements to drop.
7066      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
7067      * @returns {Array} Returns the slice of `array`.
7068      * @example
7069      *
7070      * _.drop([1, 2, 3]);
7071      * // => [2, 3]
7072      *
7073      * _.drop([1, 2, 3], 2);
7074      * // => [3]
7075      *
7076      * _.drop([1, 2, 3], 5);
7077      * // => []
7078      *
7079      * _.drop([1, 2, 3], 0);
7080      * // => [1, 2, 3]
7081      */
7082     function drop(array, n, guard) {
7083       var length = array == null ? 0 : array.length;
7084       if (!length) {
7085         return [];
7086       }
7087       n = (guard || n === undefined) ? 1 : toInteger(n);
7088       return baseSlice(array, n < 0 ? 0 : n, length);
7089     }
7090
7091     /**
7092      * Creates a slice of `array` with `n` elements dropped from the end.
7093      *
7094      * @static
7095      * @memberOf _
7096      * @since 3.0.0
7097      * @category Array
7098      * @param {Array} array The array to query.
7099      * @param {number} [n=1] The number of elements to drop.
7100      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
7101      * @returns {Array} Returns the slice of `array`.
7102      * @example
7103      *
7104      * _.dropRight([1, 2, 3]);
7105      * // => [1, 2]
7106      *
7107      * _.dropRight([1, 2, 3], 2);
7108      * // => [1]
7109      *
7110      * _.dropRight([1, 2, 3], 5);
7111      * // => []
7112      *
7113      * _.dropRight([1, 2, 3], 0);
7114      * // => [1, 2, 3]
7115      */
7116     function dropRight(array, n, guard) {
7117       var length = array == null ? 0 : array.length;
7118       if (!length) {
7119         return [];
7120       }
7121       n = (guard || n === undefined) ? 1 : toInteger(n);
7122       n = length - n;
7123       return baseSlice(array, 0, n < 0 ? 0 : n);
7124     }
7125
7126     /**
7127      * Creates a slice of `array` excluding elements dropped from the end.
7128      * Elements are dropped until `predicate` returns falsey. The predicate is
7129      * invoked with three arguments: (value, index, array).
7130      *
7131      * @static
7132      * @memberOf _
7133      * @since 3.0.0
7134      * @category Array
7135      * @param {Array} array The array to query.
7136      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7137      * @returns {Array} Returns the slice of `array`.
7138      * @example
7139      *
7140      * var users = [
7141      *   { 'user': 'barney',  'active': true },
7142      *   { 'user': 'fred',    'active': false },
7143      *   { 'user': 'pebbles', 'active': false }
7144      * ];
7145      *
7146      * _.dropRightWhile(users, function(o) { return !o.active; });
7147      * // => objects for ['barney']
7148      *
7149      * // The `_.matches` iteratee shorthand.
7150      * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
7151      * // => objects for ['barney', 'fred']
7152      *
7153      * // The `_.matchesProperty` iteratee shorthand.
7154      * _.dropRightWhile(users, ['active', false]);
7155      * // => objects for ['barney']
7156      *
7157      * // The `_.property` iteratee shorthand.
7158      * _.dropRightWhile(users, 'active');
7159      * // => objects for ['barney', 'fred', 'pebbles']
7160      */
7161     function dropRightWhile(array, predicate) {
7162       return (array && array.length)
7163         ? baseWhile(array, getIteratee(predicate, 3), true, true)
7164         : [];
7165     }
7166
7167     /**
7168      * Creates a slice of `array` excluding elements dropped from the beginning.
7169      * Elements are dropped until `predicate` returns falsey. The predicate is
7170      * invoked with three arguments: (value, index, array).
7171      *
7172      * @static
7173      * @memberOf _
7174      * @since 3.0.0
7175      * @category Array
7176      * @param {Array} array The array to query.
7177      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7178      * @returns {Array} Returns the slice of `array`.
7179      * @example
7180      *
7181      * var users = [
7182      *   { 'user': 'barney',  'active': false },
7183      *   { 'user': 'fred',    'active': false },
7184      *   { 'user': 'pebbles', 'active': true }
7185      * ];
7186      *
7187      * _.dropWhile(users, function(o) { return !o.active; });
7188      * // => objects for ['pebbles']
7189      *
7190      * // The `_.matches` iteratee shorthand.
7191      * _.dropWhile(users, { 'user': 'barney', 'active': false });
7192      * // => objects for ['fred', 'pebbles']
7193      *
7194      * // The `_.matchesProperty` iteratee shorthand.
7195      * _.dropWhile(users, ['active', false]);
7196      * // => objects for ['pebbles']
7197      *
7198      * // The `_.property` iteratee shorthand.
7199      * _.dropWhile(users, 'active');
7200      * // => objects for ['barney', 'fred', 'pebbles']
7201      */
7202     function dropWhile(array, predicate) {
7203       return (array && array.length)
7204         ? baseWhile(array, getIteratee(predicate, 3), true)
7205         : [];
7206     }
7207
7208     /**
7209      * Fills elements of `array` with `value` from `start` up to, but not
7210      * including, `end`.
7211      *
7212      * **Note:** This method mutates `array`.
7213      *
7214      * @static
7215      * @memberOf _
7216      * @since 3.2.0
7217      * @category Array
7218      * @param {Array} array The array to fill.
7219      * @param {*} value The value to fill `array` with.
7220      * @param {number} [start=0] The start position.
7221      * @param {number} [end=array.length] The end position.
7222      * @returns {Array} Returns `array`.
7223      * @example
7224      *
7225      * var array = [1, 2, 3];
7226      *
7227      * _.fill(array, 'a');
7228      * console.log(array);
7229      * // => ['a', 'a', 'a']
7230      *
7231      * _.fill(Array(3), 2);
7232      * // => [2, 2, 2]
7233      *
7234      * _.fill([4, 6, 8, 10], '*', 1, 3);
7235      * // => [4, '*', '*', 10]
7236      */
7237     function fill(array, value, start, end) {
7238       var length = array == null ? 0 : array.length;
7239       if (!length) {
7240         return [];
7241       }
7242       if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
7243         start = 0;
7244         end = length;
7245       }
7246       return baseFill(array, value, start, end);
7247     }
7248
7249     /**
7250      * This method is like `_.find` except that it returns the index of the first
7251      * element `predicate` returns truthy for instead of the element itself.
7252      *
7253      * @static
7254      * @memberOf _
7255      * @since 1.1.0
7256      * @category Array
7257      * @param {Array} array The array to inspect.
7258      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7259      * @param {number} [fromIndex=0] The index to search from.
7260      * @returns {number} Returns the index of the found element, else `-1`.
7261      * @example
7262      *
7263      * var users = [
7264      *   { 'user': 'barney',  'active': false },
7265      *   { 'user': 'fred',    'active': false },
7266      *   { 'user': 'pebbles', 'active': true }
7267      * ];
7268      *
7269      * _.findIndex(users, function(o) { return o.user == 'barney'; });
7270      * // => 0
7271      *
7272      * // The `_.matches` iteratee shorthand.
7273      * _.findIndex(users, { 'user': 'fred', 'active': false });
7274      * // => 1
7275      *
7276      * // The `_.matchesProperty` iteratee shorthand.
7277      * _.findIndex(users, ['active', false]);
7278      * // => 0
7279      *
7280      * // The `_.property` iteratee shorthand.
7281      * _.findIndex(users, 'active');
7282      * // => 2
7283      */
7284     function findIndex(array, predicate, fromIndex) {
7285       var length = array == null ? 0 : array.length;
7286       if (!length) {
7287         return -1;
7288       }
7289       var index = fromIndex == null ? 0 : toInteger(fromIndex);
7290       if (index < 0) {
7291         index = nativeMax(length + index, 0);
7292       }
7293       return baseFindIndex(array, getIteratee(predicate, 3), index);
7294     }
7295
7296     /**
7297      * This method is like `_.findIndex` except that it iterates over elements
7298      * of `collection` from right to left.
7299      *
7300      * @static
7301      * @memberOf _
7302      * @since 2.0.0
7303      * @category Array
7304      * @param {Array} array The array to inspect.
7305      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7306      * @param {number} [fromIndex=array.length-1] The index to search from.
7307      * @returns {number} Returns the index of the found element, else `-1`.
7308      * @example
7309      *
7310      * var users = [
7311      *   { 'user': 'barney',  'active': true },
7312      *   { 'user': 'fred',    'active': false },
7313      *   { 'user': 'pebbles', 'active': false }
7314      * ];
7315      *
7316      * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
7317      * // => 2
7318      *
7319      * // The `_.matches` iteratee shorthand.
7320      * _.findLastIndex(users, { 'user': 'barney', 'active': true });
7321      * // => 0
7322      *
7323      * // The `_.matchesProperty` iteratee shorthand.
7324      * _.findLastIndex(users, ['active', false]);
7325      * // => 2
7326      *
7327      * // The `_.property` iteratee shorthand.
7328      * _.findLastIndex(users, 'active');
7329      * // => 0
7330      */
7331     function findLastIndex(array, predicate, fromIndex) {
7332       var length = array == null ? 0 : array.length;
7333       if (!length) {
7334         return -1;
7335       }
7336       var index = length - 1;
7337       if (fromIndex !== undefined) {
7338         index = toInteger(fromIndex);
7339         index = fromIndex < 0
7340           ? nativeMax(length + index, 0)
7341           : nativeMin(index, length - 1);
7342       }
7343       return baseFindIndex(array, getIteratee(predicate, 3), index, true);
7344     }
7345
7346     /**
7347      * Flattens `array` a single level deep.
7348      *
7349      * @static
7350      * @memberOf _
7351      * @since 0.1.0
7352      * @category Array
7353      * @param {Array} array The array to flatten.
7354      * @returns {Array} Returns the new flattened array.
7355      * @example
7356      *
7357      * _.flatten([1, [2, [3, [4]], 5]]);
7358      * // => [1, 2, [3, [4]], 5]
7359      */
7360     function flatten(array) {
7361       var length = array == null ? 0 : array.length;
7362       return length ? baseFlatten(array, 1) : [];
7363     }
7364
7365     /**
7366      * Recursively flattens `array`.
7367      *
7368      * @static
7369      * @memberOf _
7370      * @since 3.0.0
7371      * @category Array
7372      * @param {Array} array The array to flatten.
7373      * @returns {Array} Returns the new flattened array.
7374      * @example
7375      *
7376      * _.flattenDeep([1, [2, [3, [4]], 5]]);
7377      * // => [1, 2, 3, 4, 5]
7378      */
7379     function flattenDeep(array) {
7380       var length = array == null ? 0 : array.length;
7381       return length ? baseFlatten(array, INFINITY) : [];
7382     }
7383
7384     /**
7385      * Recursively flatten `array` up to `depth` times.
7386      *
7387      * @static
7388      * @memberOf _
7389      * @since 4.4.0
7390      * @category Array
7391      * @param {Array} array The array to flatten.
7392      * @param {number} [depth=1] The maximum recursion depth.
7393      * @returns {Array} Returns the new flattened array.
7394      * @example
7395      *
7396      * var array = [1, [2, [3, [4]], 5]];
7397      *
7398      * _.flattenDepth(array, 1);
7399      * // => [1, 2, [3, [4]], 5]
7400      *
7401      * _.flattenDepth(array, 2);
7402      * // => [1, 2, 3, [4], 5]
7403      */
7404     function flattenDepth(array, depth) {
7405       var length = array == null ? 0 : array.length;
7406       if (!length) {
7407         return [];
7408       }
7409       depth = depth === undefined ? 1 : toInteger(depth);
7410       return baseFlatten(array, depth);
7411     }
7412
7413     /**
7414      * The inverse of `_.toPairs`; this method returns an object composed
7415      * from key-value `pairs`.
7416      *
7417      * @static
7418      * @memberOf _
7419      * @since 4.0.0
7420      * @category Array
7421      * @param {Array} pairs The key-value pairs.
7422      * @returns {Object} Returns the new object.
7423      * @example
7424      *
7425      * _.fromPairs([['a', 1], ['b', 2]]);
7426      * // => { 'a': 1, 'b': 2 }
7427      */
7428     function fromPairs(pairs) {
7429       var index = -1,
7430           length = pairs == null ? 0 : pairs.length,
7431           result = {};
7432
7433       while (++index < length) {
7434         var pair = pairs[index];
7435         result[pair[0]] = pair[1];
7436       }
7437       return result;
7438     }
7439
7440     /**
7441      * Gets the first element of `array`.
7442      *
7443      * @static
7444      * @memberOf _
7445      * @since 0.1.0
7446      * @alias first
7447      * @category Array
7448      * @param {Array} array The array to query.
7449      * @returns {*} Returns the first element of `array`.
7450      * @example
7451      *
7452      * _.head([1, 2, 3]);
7453      * // => 1
7454      *
7455      * _.head([]);
7456      * // => undefined
7457      */
7458     function head(array) {
7459       return (array && array.length) ? array[0] : undefined;
7460     }
7461
7462     /**
7463      * Gets the index at which the first occurrence of `value` is found in `array`
7464      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7465      * for equality comparisons. If `fromIndex` is negative, it's used as the
7466      * offset from the end of `array`.
7467      *
7468      * @static
7469      * @memberOf _
7470      * @since 0.1.0
7471      * @category Array
7472      * @param {Array} array The array to inspect.
7473      * @param {*} value The value to search for.
7474      * @param {number} [fromIndex=0] The index to search from.
7475      * @returns {number} Returns the index of the matched value, else `-1`.
7476      * @example
7477      *
7478      * _.indexOf([1, 2, 1, 2], 2);
7479      * // => 1
7480      *
7481      * // Search from the `fromIndex`.
7482      * _.indexOf([1, 2, 1, 2], 2, 2);
7483      * // => 3
7484      */
7485     function indexOf(array, value, fromIndex) {
7486       var length = array == null ? 0 : array.length;
7487       if (!length) {
7488         return -1;
7489       }
7490       var index = fromIndex == null ? 0 : toInteger(fromIndex);
7491       if (index < 0) {
7492         index = nativeMax(length + index, 0);
7493       }
7494       return baseIndexOf(array, value, index);
7495     }
7496
7497     /**
7498      * Gets all but the last element of `array`.
7499      *
7500      * @static
7501      * @memberOf _
7502      * @since 0.1.0
7503      * @category Array
7504      * @param {Array} array The array to query.
7505      * @returns {Array} Returns the slice of `array`.
7506      * @example
7507      *
7508      * _.initial([1, 2, 3]);
7509      * // => [1, 2]
7510      */
7511     function initial(array) {
7512       var length = array == null ? 0 : array.length;
7513       return length ? baseSlice(array, 0, -1) : [];
7514     }
7515
7516     /**
7517      * Creates an array of unique values that are included in all given arrays
7518      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7519      * for equality comparisons. The order and references of result values are
7520      * determined by the first array.
7521      *
7522      * @static
7523      * @memberOf _
7524      * @since 0.1.0
7525      * @category Array
7526      * @param {...Array} [arrays] The arrays to inspect.
7527      * @returns {Array} Returns the new array of intersecting values.
7528      * @example
7529      *
7530      * _.intersection([2, 1], [2, 3]);
7531      * // => [2]
7532      */
7533     var intersection = baseRest(function(arrays) {
7534       var mapped = arrayMap(arrays, castArrayLikeObject);
7535       return (mapped.length && mapped[0] === arrays[0])
7536         ? baseIntersection(mapped)
7537         : [];
7538     });
7539
7540     /**
7541      * This method is like `_.intersection` except that it accepts `iteratee`
7542      * which is invoked for each element of each `arrays` to generate the criterion
7543      * by which they're compared. The order and references of result values are
7544      * determined by the first array. The iteratee is invoked with one argument:
7545      * (value).
7546      *
7547      * @static
7548      * @memberOf _
7549      * @since 4.0.0
7550      * @category Array
7551      * @param {...Array} [arrays] The arrays to inspect.
7552      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7553      * @returns {Array} Returns the new array of intersecting values.
7554      * @example
7555      *
7556      * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
7557      * // => [2.1]
7558      *
7559      * // The `_.property` iteratee shorthand.
7560      * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
7561      * // => [{ 'x': 1 }]
7562      */
7563     var intersectionBy = baseRest(function(arrays) {
7564       var iteratee = last(arrays),
7565           mapped = arrayMap(arrays, castArrayLikeObject);
7566
7567       if (iteratee === last(mapped)) {
7568         iteratee = undefined;
7569       } else {
7570         mapped.pop();
7571       }
7572       return (mapped.length && mapped[0] === arrays[0])
7573         ? baseIntersection(mapped, getIteratee(iteratee, 2))
7574         : [];
7575     });
7576
7577     /**
7578      * This method is like `_.intersection` except that it accepts `comparator`
7579      * which is invoked to compare elements of `arrays`. The order and references
7580      * of result values are determined by the first array. The comparator is
7581      * invoked with two arguments: (arrVal, othVal).
7582      *
7583      * @static
7584      * @memberOf _
7585      * @since 4.0.0
7586      * @category Array
7587      * @param {...Array} [arrays] The arrays to inspect.
7588      * @param {Function} [comparator] The comparator invoked per element.
7589      * @returns {Array} Returns the new array of intersecting values.
7590      * @example
7591      *
7592      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
7593      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
7594      *
7595      * _.intersectionWith(objects, others, _.isEqual);
7596      * // => [{ 'x': 1, 'y': 2 }]
7597      */
7598     var intersectionWith = baseRest(function(arrays) {
7599       var comparator = last(arrays),
7600           mapped = arrayMap(arrays, castArrayLikeObject);
7601
7602       comparator = typeof comparator == 'function' ? comparator : undefined;
7603       if (comparator) {
7604         mapped.pop();
7605       }
7606       return (mapped.length && mapped[0] === arrays[0])
7607         ? baseIntersection(mapped, undefined, comparator)
7608         : [];
7609     });
7610
7611     /**
7612      * Converts all elements in `array` into a string separated by `separator`.
7613      *
7614      * @static
7615      * @memberOf _
7616      * @since 4.0.0
7617      * @category Array
7618      * @param {Array} array The array to convert.
7619      * @param {string} [separator=','] The element separator.
7620      * @returns {string} Returns the joined string.
7621      * @example
7622      *
7623      * _.join(['a', 'b', 'c'], '~');
7624      * // => 'a~b~c'
7625      */
7626     function join(array, separator) {
7627       return array == null ? '' : nativeJoin.call(array, separator);
7628     }
7629
7630     /**
7631      * Gets the last element of `array`.
7632      *
7633      * @static
7634      * @memberOf _
7635      * @since 0.1.0
7636      * @category Array
7637      * @param {Array} array The array to query.
7638      * @returns {*} Returns the last element of `array`.
7639      * @example
7640      *
7641      * _.last([1, 2, 3]);
7642      * // => 3
7643      */
7644     function last(array) {
7645       var length = array == null ? 0 : array.length;
7646       return length ? array[length - 1] : undefined;
7647     }
7648
7649     /**
7650      * This method is like `_.indexOf` except that it iterates over elements of
7651      * `array` from right to left.
7652      *
7653      * @static
7654      * @memberOf _
7655      * @since 0.1.0
7656      * @category Array
7657      * @param {Array} array The array to inspect.
7658      * @param {*} value The value to search for.
7659      * @param {number} [fromIndex=array.length-1] The index to search from.
7660      * @returns {number} Returns the index of the matched value, else `-1`.
7661      * @example
7662      *
7663      * _.lastIndexOf([1, 2, 1, 2], 2);
7664      * // => 3
7665      *
7666      * // Search from the `fromIndex`.
7667      * _.lastIndexOf([1, 2, 1, 2], 2, 2);
7668      * // => 1
7669      */
7670     function lastIndexOf(array, value, fromIndex) {
7671       var length = array == null ? 0 : array.length;
7672       if (!length) {
7673         return -1;
7674       }
7675       var index = length;
7676       if (fromIndex !== undefined) {
7677         index = toInteger(fromIndex);
7678         index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
7679       }
7680       return value === value
7681         ? strictLastIndexOf(array, value, index)
7682         : baseFindIndex(array, baseIsNaN, index, true);
7683     }
7684
7685     /**
7686      * Gets the element at index `n` of `array`. If `n` is negative, the nth
7687      * element from the end is returned.
7688      *
7689      * @static
7690      * @memberOf _
7691      * @since 4.11.0
7692      * @category Array
7693      * @param {Array} array The array to query.
7694      * @param {number} [n=0] The index of the element to return.
7695      * @returns {*} Returns the nth element of `array`.
7696      * @example
7697      *
7698      * var array = ['a', 'b', 'c', 'd'];
7699      *
7700      * _.nth(array, 1);
7701      * // => 'b'
7702      *
7703      * _.nth(array, -2);
7704      * // => 'c';
7705      */
7706     function nth(array, n) {
7707       return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
7708     }
7709
7710     /**
7711      * Removes all given values from `array` using
7712      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7713      * for equality comparisons.
7714      *
7715      * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
7716      * to remove elements from an array by predicate.
7717      *
7718      * @static
7719      * @memberOf _
7720      * @since 2.0.0
7721      * @category Array
7722      * @param {Array} array The array to modify.
7723      * @param {...*} [values] The values to remove.
7724      * @returns {Array} Returns `array`.
7725      * @example
7726      *
7727      * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
7728      *
7729      * _.pull(array, 'a', 'c');
7730      * console.log(array);
7731      * // => ['b', 'b']
7732      */
7733     var pull = baseRest(pullAll);
7734
7735     /**
7736      * This method is like `_.pull` except that it accepts an array of values to remove.
7737      *
7738      * **Note:** Unlike `_.difference`, this method mutates `array`.
7739      *
7740      * @static
7741      * @memberOf _
7742      * @since 4.0.0
7743      * @category Array
7744      * @param {Array} array The array to modify.
7745      * @param {Array} values The values to remove.
7746      * @returns {Array} Returns `array`.
7747      * @example
7748      *
7749      * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
7750      *
7751      * _.pullAll(array, ['a', 'c']);
7752      * console.log(array);
7753      * // => ['b', 'b']
7754      */
7755     function pullAll(array, values) {
7756       return (array && array.length && values && values.length)
7757         ? basePullAll(array, values)
7758         : array;
7759     }
7760
7761     /**
7762      * This method is like `_.pullAll` except that it accepts `iteratee` which is
7763      * invoked for each element of `array` and `values` to generate the criterion
7764      * by which they're compared. The iteratee is invoked with one argument: (value).
7765      *
7766      * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
7767      *
7768      * @static
7769      * @memberOf _
7770      * @since 4.0.0
7771      * @category Array
7772      * @param {Array} array The array to modify.
7773      * @param {Array} values The values to remove.
7774      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7775      * @returns {Array} Returns `array`.
7776      * @example
7777      *
7778      * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
7779      *
7780      * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
7781      * console.log(array);
7782      * // => [{ 'x': 2 }]
7783      */
7784     function pullAllBy(array, values, iteratee) {
7785       return (array && array.length && values && values.length)
7786         ? basePullAll(array, values, getIteratee(iteratee, 2))
7787         : array;
7788     }
7789
7790     /**
7791      * This method is like `_.pullAll` except that it accepts `comparator` which
7792      * is invoked to compare elements of `array` to `values`. The comparator is
7793      * invoked with two arguments: (arrVal, othVal).
7794      *
7795      * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
7796      *
7797      * @static
7798      * @memberOf _
7799      * @since 4.6.0
7800      * @category Array
7801      * @param {Array} array The array to modify.
7802      * @param {Array} values The values to remove.
7803      * @param {Function} [comparator] The comparator invoked per element.
7804      * @returns {Array} Returns `array`.
7805      * @example
7806      *
7807      * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
7808      *
7809      * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
7810      * console.log(array);
7811      * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
7812      */
7813     function pullAllWith(array, values, comparator) {
7814       return (array && array.length && values && values.length)
7815         ? basePullAll(array, values, undefined, comparator)
7816         : array;
7817     }
7818
7819     /**
7820      * Removes elements from `array` corresponding to `indexes` and returns an
7821      * array of removed elements.
7822      *
7823      * **Note:** Unlike `_.at`, this method mutates `array`.
7824      *
7825      * @static
7826      * @memberOf _
7827      * @since 3.0.0
7828      * @category Array
7829      * @param {Array} array The array to modify.
7830      * @param {...(number|number[])} [indexes] The indexes of elements to remove.
7831      * @returns {Array} Returns the new array of removed elements.
7832      * @example
7833      *
7834      * var array = ['a', 'b', 'c', 'd'];
7835      * var pulled = _.pullAt(array, [1, 3]);
7836      *
7837      * console.log(array);
7838      * // => ['a', 'c']
7839      *
7840      * console.log(pulled);
7841      * // => ['b', 'd']
7842      */
7843     var pullAt = flatRest(function(array, indexes) {
7844       var length = array == null ? 0 : array.length,
7845           result = baseAt(array, indexes);
7846
7847       basePullAt(array, arrayMap(indexes, function(index) {
7848         return isIndex(index, length) ? +index : index;
7849       }).sort(compareAscending));
7850
7851       return result;
7852     });
7853
7854     /**
7855      * Removes all elements from `array` that `predicate` returns truthy for
7856      * and returns an array of the removed elements. The predicate is invoked
7857      * with three arguments: (value, index, array).
7858      *
7859      * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
7860      * to pull elements from an array by value.
7861      *
7862      * @static
7863      * @memberOf _
7864      * @since 2.0.0
7865      * @category Array
7866      * @param {Array} array The array to modify.
7867      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7868      * @returns {Array} Returns the new array of removed elements.
7869      * @example
7870      *
7871      * var array = [1, 2, 3, 4];
7872      * var evens = _.remove(array, function(n) {
7873      *   return n % 2 == 0;
7874      * });
7875      *
7876      * console.log(array);
7877      * // => [1, 3]
7878      *
7879      * console.log(evens);
7880      * // => [2, 4]
7881      */
7882     function remove(array, predicate) {
7883       var result = [];
7884       if (!(array && array.length)) {
7885         return result;
7886       }
7887       var index = -1,
7888           indexes = [],
7889           length = array.length;
7890
7891       predicate = getIteratee(predicate, 3);
7892       while (++index < length) {
7893         var value = array[index];
7894         if (predicate(value, index, array)) {
7895           result.push(value);
7896           indexes.push(index);
7897         }
7898       }
7899       basePullAt(array, indexes);
7900       return result;
7901     }
7902
7903     /**
7904      * Reverses `array` so that the first element becomes the last, the second
7905      * element becomes the second to last, and so on.
7906      *
7907      * **Note:** This method mutates `array` and is based on
7908      * [`Array#reverse`](https://mdn.io/Array/reverse).
7909      *
7910      * @static
7911      * @memberOf _
7912      * @since 4.0.0
7913      * @category Array
7914      * @param {Array} array The array to modify.
7915      * @returns {Array} Returns `array`.
7916      * @example
7917      *
7918      * var array = [1, 2, 3];
7919      *
7920      * _.reverse(array);
7921      * // => [3, 2, 1]
7922      *
7923      * console.log(array);
7924      * // => [3, 2, 1]
7925      */
7926     function reverse(array) {
7927       return array == null ? array : nativeReverse.call(array);
7928     }
7929
7930     /**
7931      * Creates a slice of `array` from `start` up to, but not including, `end`.
7932      *
7933      * **Note:** This method is used instead of
7934      * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
7935      * returned.
7936      *
7937      * @static
7938      * @memberOf _
7939      * @since 3.0.0
7940      * @category Array
7941      * @param {Array} array The array to slice.
7942      * @param {number} [start=0] The start position.
7943      * @param {number} [end=array.length] The end position.
7944      * @returns {Array} Returns the slice of `array`.
7945      */
7946     function slice(array, start, end) {
7947       var length = array == null ? 0 : array.length;
7948       if (!length) {
7949         return [];
7950       }
7951       if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
7952         start = 0;
7953         end = length;
7954       }
7955       else {
7956         start = start == null ? 0 : toInteger(start);
7957         end = end === undefined ? length : toInteger(end);
7958       }
7959       return baseSlice(array, start, end);
7960     }
7961
7962     /**
7963      * Uses a binary search to determine the lowest index at which `value`
7964      * should be inserted into `array` in order to maintain its sort order.
7965      *
7966      * @static
7967      * @memberOf _
7968      * @since 0.1.0
7969      * @category Array
7970      * @param {Array} array The sorted array to inspect.
7971      * @param {*} value The value to evaluate.
7972      * @returns {number} Returns the index at which `value` should be inserted
7973      *  into `array`.
7974      * @example
7975      *
7976      * _.sortedIndex([30, 50], 40);
7977      * // => 1
7978      */
7979     function sortedIndex(array, value) {
7980       return baseSortedIndex(array, value);
7981     }
7982
7983     /**
7984      * This method is like `_.sortedIndex` except that it accepts `iteratee`
7985      * which is invoked for `value` and each element of `array` to compute their
7986      * sort ranking. The iteratee is invoked with one argument: (value).
7987      *
7988      * @static
7989      * @memberOf _
7990      * @since 4.0.0
7991      * @category Array
7992      * @param {Array} array The sorted array to inspect.
7993      * @param {*} value The value to evaluate.
7994      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7995      * @returns {number} Returns the index at which `value` should be inserted
7996      *  into `array`.
7997      * @example
7998      *
7999      * var objects = [{ 'x': 4 }, { 'x': 5 }];
8000      *
8001      * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
8002      * // => 0
8003      *
8004      * // The `_.property` iteratee shorthand.
8005      * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
8006      * // => 0
8007      */
8008     function sortedIndexBy(array, value, iteratee) {
8009       return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
8010     }
8011
8012     /**
8013      * This method is like `_.indexOf` except that it performs a binary
8014      * search on a sorted `array`.
8015      *
8016      * @static
8017      * @memberOf _
8018      * @since 4.0.0
8019      * @category Array
8020      * @param {Array} array The array to inspect.
8021      * @param {*} value The value to search for.
8022      * @returns {number} Returns the index of the matched value, else `-1`.
8023      * @example
8024      *
8025      * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
8026      * // => 1
8027      */
8028     function sortedIndexOf(array, value) {
8029       var length = array == null ? 0 : array.length;
8030       if (length) {
8031         var index = baseSortedIndex(array, value);
8032         if (index < length && eq(array[index], value)) {
8033           return index;
8034         }
8035       }
8036       return -1;
8037     }
8038
8039     /**
8040      * This method is like `_.sortedIndex` except that it returns the highest
8041      * index at which `value` should be inserted into `array` in order to
8042      * maintain its sort order.
8043      *
8044      * @static
8045      * @memberOf _
8046      * @since 3.0.0
8047      * @category Array
8048      * @param {Array} array The sorted array to inspect.
8049      * @param {*} value The value to evaluate.
8050      * @returns {number} Returns the index at which `value` should be inserted
8051      *  into `array`.
8052      * @example
8053      *
8054      * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
8055      * // => 4
8056      */
8057     function sortedLastIndex(array, value) {
8058       return baseSortedIndex(array, value, true);
8059     }
8060
8061     /**
8062      * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
8063      * which is invoked for `value` and each element of `array` to compute their
8064      * sort ranking. The iteratee is invoked with one argument: (value).
8065      *
8066      * @static
8067      * @memberOf _
8068      * @since 4.0.0
8069      * @category Array
8070      * @param {Array} array The sorted array to inspect.
8071      * @param {*} value The value to evaluate.
8072      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8073      * @returns {number} Returns the index at which `value` should be inserted
8074      *  into `array`.
8075      * @example
8076      *
8077      * var objects = [{ 'x': 4 }, { 'x': 5 }];
8078      *
8079      * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
8080      * // => 1
8081      *
8082      * // The `_.property` iteratee shorthand.
8083      * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
8084      * // => 1
8085      */
8086     function sortedLastIndexBy(array, value, iteratee) {
8087       return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
8088     }
8089
8090     /**
8091      * This method is like `_.lastIndexOf` except that it performs a binary
8092      * search on a sorted `array`.
8093      *
8094      * @static
8095      * @memberOf _
8096      * @since 4.0.0
8097      * @category Array
8098      * @param {Array} array The array to inspect.
8099      * @param {*} value The value to search for.
8100      * @returns {number} Returns the index of the matched value, else `-1`.
8101      * @example
8102      *
8103      * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
8104      * // => 3
8105      */
8106     function sortedLastIndexOf(array, value) {
8107       var length = array == null ? 0 : array.length;
8108       if (length) {
8109         var index = baseSortedIndex(array, value, true) - 1;
8110         if (eq(array[index], value)) {
8111           return index;
8112         }
8113       }
8114       return -1;
8115     }
8116
8117     /**
8118      * This method is like `_.uniq` except that it's designed and optimized
8119      * for sorted arrays.
8120      *
8121      * @static
8122      * @memberOf _
8123      * @since 4.0.0
8124      * @category Array
8125      * @param {Array} array The array to inspect.
8126      * @returns {Array} Returns the new duplicate free array.
8127      * @example
8128      *
8129      * _.sortedUniq([1, 1, 2]);
8130      * // => [1, 2]
8131      */
8132     function sortedUniq(array) {
8133       return (array && array.length)
8134         ? baseSortedUniq(array)
8135         : [];
8136     }
8137
8138     /**
8139      * This method is like `_.uniqBy` except that it's designed and optimized
8140      * for sorted arrays.
8141      *
8142      * @static
8143      * @memberOf _
8144      * @since 4.0.0
8145      * @category Array
8146      * @param {Array} array The array to inspect.
8147      * @param {Function} [iteratee] The iteratee invoked per element.
8148      * @returns {Array} Returns the new duplicate free array.
8149      * @example
8150      *
8151      * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
8152      * // => [1.1, 2.3]
8153      */
8154     function sortedUniqBy(array, iteratee) {
8155       return (array && array.length)
8156         ? baseSortedUniq(array, getIteratee(iteratee, 2))
8157         : [];
8158     }
8159
8160     /**
8161      * Gets all but the first element of `array`.
8162      *
8163      * @static
8164      * @memberOf _
8165      * @since 4.0.0
8166      * @category Array
8167      * @param {Array} array The array to query.
8168      * @returns {Array} Returns the slice of `array`.
8169      * @example
8170      *
8171      * _.tail([1, 2, 3]);
8172      * // => [2, 3]
8173      */
8174     function tail(array) {
8175       var length = array == null ? 0 : array.length;
8176       return length ? baseSlice(array, 1, length) : [];
8177     }
8178
8179     /**
8180      * Creates a slice of `array` with `n` elements taken from the beginning.
8181      *
8182      * @static
8183      * @memberOf _
8184      * @since 0.1.0
8185      * @category Array
8186      * @param {Array} array The array to query.
8187      * @param {number} [n=1] The number of elements to take.
8188      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8189      * @returns {Array} Returns the slice of `array`.
8190      * @example
8191      *
8192      * _.take([1, 2, 3]);
8193      * // => [1]
8194      *
8195      * _.take([1, 2, 3], 2);
8196      * // => [1, 2]
8197      *
8198      * _.take([1, 2, 3], 5);
8199      * // => [1, 2, 3]
8200      *
8201      * _.take([1, 2, 3], 0);
8202      * // => []
8203      */
8204     function take(array, n, guard) {
8205       if (!(array && array.length)) {
8206         return [];
8207       }
8208       n = (guard || n === undefined) ? 1 : toInteger(n);
8209       return baseSlice(array, 0, n < 0 ? 0 : n);
8210     }
8211
8212     /**
8213      * Creates a slice of `array` with `n` elements taken from the end.
8214      *
8215      * @static
8216      * @memberOf _
8217      * @since 3.0.0
8218      * @category Array
8219      * @param {Array} array The array to query.
8220      * @param {number} [n=1] The number of elements to take.
8221      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8222      * @returns {Array} Returns the slice of `array`.
8223      * @example
8224      *
8225      * _.takeRight([1, 2, 3]);
8226      * // => [3]
8227      *
8228      * _.takeRight([1, 2, 3], 2);
8229      * // => [2, 3]
8230      *
8231      * _.takeRight([1, 2, 3], 5);
8232      * // => [1, 2, 3]
8233      *
8234      * _.takeRight([1, 2, 3], 0);
8235      * // => []
8236      */
8237     function takeRight(array, n, guard) {
8238       var length = array == null ? 0 : array.length;
8239       if (!length) {
8240         return [];
8241       }
8242       n = (guard || n === undefined) ? 1 : toInteger(n);
8243       n = length - n;
8244       return baseSlice(array, n < 0 ? 0 : n, length);
8245     }
8246
8247     /**
8248      * Creates a slice of `array` with elements taken from the end. Elements are
8249      * taken until `predicate` returns falsey. The predicate is invoked with
8250      * three arguments: (value, index, array).
8251      *
8252      * @static
8253      * @memberOf _
8254      * @since 3.0.0
8255      * @category Array
8256      * @param {Array} array The array to query.
8257      * @param {Function} [predicate=_.identity] The function invoked per iteration.
8258      * @returns {Array} Returns the slice of `array`.
8259      * @example
8260      *
8261      * var users = [
8262      *   { 'user': 'barney',  'active': true },
8263      *   { 'user': 'fred',    'active': false },
8264      *   { 'user': 'pebbles', 'active': false }
8265      * ];
8266      *
8267      * _.takeRightWhile(users, function(o) { return !o.active; });
8268      * // => objects for ['fred', 'pebbles']
8269      *
8270      * // The `_.matches` iteratee shorthand.
8271      * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
8272      * // => objects for ['pebbles']
8273      *
8274      * // The `_.matchesProperty` iteratee shorthand.
8275      * _.takeRightWhile(users, ['active', false]);
8276      * // => objects for ['fred', 'pebbles']
8277      *
8278      * // The `_.property` iteratee shorthand.
8279      * _.takeRightWhile(users, 'active');
8280      * // => []
8281      */
8282     function takeRightWhile(array, predicate) {
8283       return (array && array.length)
8284         ? baseWhile(array, getIteratee(predicate, 3), false, true)
8285         : [];
8286     }
8287
8288     /**
8289      * Creates a slice of `array` with elements taken from the beginning. Elements
8290      * are taken until `predicate` returns falsey. The predicate is invoked with
8291      * three arguments: (value, index, array).
8292      *
8293      * @static
8294      * @memberOf _
8295      * @since 3.0.0
8296      * @category Array
8297      * @param {Array} array The array to query.
8298      * @param {Function} [predicate=_.identity] The function invoked per iteration.
8299      * @returns {Array} Returns the slice of `array`.
8300      * @example
8301      *
8302      * var users = [
8303      *   { 'user': 'barney',  'active': false },
8304      *   { 'user': 'fred',    'active': false },
8305      *   { 'user': 'pebbles', 'active': true }
8306      * ];
8307      *
8308      * _.takeWhile(users, function(o) { return !o.active; });
8309      * // => objects for ['barney', 'fred']
8310      *
8311      * // The `_.matches` iteratee shorthand.
8312      * _.takeWhile(users, { 'user': 'barney', 'active': false });
8313      * // => objects for ['barney']
8314      *
8315      * // The `_.matchesProperty` iteratee shorthand.
8316      * _.takeWhile(users, ['active', false]);
8317      * // => objects for ['barney', 'fred']
8318      *
8319      * // The `_.property` iteratee shorthand.
8320      * _.takeWhile(users, 'active');
8321      * // => []
8322      */
8323     function takeWhile(array, predicate) {
8324       return (array && array.length)
8325         ? baseWhile(array, getIteratee(predicate, 3))
8326         : [];
8327     }
8328
8329     /**
8330      * Creates an array of unique values, in order, from all given arrays using
8331      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8332      * for equality comparisons.
8333      *
8334      * @static
8335      * @memberOf _
8336      * @since 0.1.0
8337      * @category Array
8338      * @param {...Array} [arrays] The arrays to inspect.
8339      * @returns {Array} Returns the new array of combined values.
8340      * @example
8341      *
8342      * _.union([2], [1, 2]);
8343      * // => [2, 1]
8344      */
8345     var union = baseRest(function(arrays) {
8346       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
8347     });
8348
8349     /**
8350      * This method is like `_.union` except that it accepts `iteratee` which is
8351      * invoked for each element of each `arrays` to generate the criterion by
8352      * which uniqueness is computed. Result values are chosen from the first
8353      * array in which the value occurs. The iteratee is invoked with one argument:
8354      * (value).
8355      *
8356      * @static
8357      * @memberOf _
8358      * @since 4.0.0
8359      * @category Array
8360      * @param {...Array} [arrays] The arrays to inspect.
8361      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8362      * @returns {Array} Returns the new array of combined values.
8363      * @example
8364      *
8365      * _.unionBy([2.1], [1.2, 2.3], Math.floor);
8366      * // => [2.1, 1.2]
8367      *
8368      * // The `_.property` iteratee shorthand.
8369      * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
8370      * // => [{ 'x': 1 }, { 'x': 2 }]
8371      */
8372     var unionBy = baseRest(function(arrays) {
8373       var iteratee = last(arrays);
8374       if (isArrayLikeObject(iteratee)) {
8375         iteratee = undefined;
8376       }
8377       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
8378     });
8379
8380     /**
8381      * This method is like `_.union` except that it accepts `comparator` which
8382      * is invoked to compare elements of `arrays`. Result values are chosen from
8383      * the first array in which the value occurs. The comparator is invoked
8384      * with two arguments: (arrVal, othVal).
8385      *
8386      * @static
8387      * @memberOf _
8388      * @since 4.0.0
8389      * @category Array
8390      * @param {...Array} [arrays] The arrays to inspect.
8391      * @param {Function} [comparator] The comparator invoked per element.
8392      * @returns {Array} Returns the new array of combined values.
8393      * @example
8394      *
8395      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
8396      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
8397      *
8398      * _.unionWith(objects, others, _.isEqual);
8399      * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
8400      */
8401     var unionWith = baseRest(function(arrays) {
8402       var comparator = last(arrays);
8403       comparator = typeof comparator == 'function' ? comparator : undefined;
8404       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
8405     });
8406
8407     /**
8408      * Creates a duplicate-free version of an array, using
8409      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8410      * for equality comparisons, in which only the first occurrence of each element
8411      * is kept. The order of result values is determined by the order they occur
8412      * in the array.
8413      *
8414      * @static
8415      * @memberOf _
8416      * @since 0.1.0
8417      * @category Array
8418      * @param {Array} array The array to inspect.
8419      * @returns {Array} Returns the new duplicate free array.
8420      * @example
8421      *
8422      * _.uniq([2, 1, 2]);
8423      * // => [2, 1]
8424      */
8425     function uniq(array) {
8426       return (array && array.length) ? baseUniq(array) : [];
8427     }
8428
8429     /**
8430      * This method is like `_.uniq` except that it accepts `iteratee` which is
8431      * invoked for each element in `array` to generate the criterion by which
8432      * uniqueness is computed. The order of result values is determined by the
8433      * order they occur in the array. The iteratee is invoked with one argument:
8434      * (value).
8435      *
8436      * @static
8437      * @memberOf _
8438      * @since 4.0.0
8439      * @category Array
8440      * @param {Array} array The array to inspect.
8441      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8442      * @returns {Array} Returns the new duplicate free array.
8443      * @example
8444      *
8445      * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
8446      * // => [2.1, 1.2]
8447      *
8448      * // The `_.property` iteratee shorthand.
8449      * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
8450      * // => [{ 'x': 1 }, { 'x': 2 }]
8451      */
8452     function uniqBy(array, iteratee) {
8453       return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : [];
8454     }
8455
8456     /**
8457      * This method is like `_.uniq` except that it accepts `comparator` which
8458      * is invoked to compare elements of `array`. The order of result values is
8459      * determined by the order they occur in the array.The comparator is invoked
8460      * with two arguments: (arrVal, othVal).
8461      *
8462      * @static
8463      * @memberOf _
8464      * @since 4.0.0
8465      * @category Array
8466      * @param {Array} array The array to inspect.
8467      * @param {Function} [comparator] The comparator invoked per element.
8468      * @returns {Array} Returns the new duplicate free array.
8469      * @example
8470      *
8471      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
8472      *
8473      * _.uniqWith(objects, _.isEqual);
8474      * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
8475      */
8476     function uniqWith(array, comparator) {
8477       comparator = typeof comparator == 'function' ? comparator : undefined;
8478       return (array && array.length) ? baseUniq(array, undefined, comparator) : [];
8479     }
8480
8481     /**
8482      * This method is like `_.zip` except that it accepts an array of grouped
8483      * elements and creates an array regrouping the elements to their pre-zip
8484      * configuration.
8485      *
8486      * @static
8487      * @memberOf _
8488      * @since 1.2.0
8489      * @category Array
8490      * @param {Array} array The array of grouped elements to process.
8491      * @returns {Array} Returns the new array of regrouped elements.
8492      * @example
8493      *
8494      * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
8495      * // => [['a', 1, true], ['b', 2, false]]
8496      *
8497      * _.unzip(zipped);
8498      * // => [['a', 'b'], [1, 2], [true, false]]
8499      */
8500     function unzip(array) {
8501       if (!(array && array.length)) {
8502         return [];
8503       }
8504       var length = 0;
8505       array = arrayFilter(array, function(group) {
8506         if (isArrayLikeObject(group)) {
8507           length = nativeMax(group.length, length);
8508           return true;
8509         }
8510       });
8511       return baseTimes(length, function(index) {
8512         return arrayMap(array, baseProperty(index));
8513       });
8514     }
8515
8516     /**
8517      * This method is like `_.unzip` except that it accepts `iteratee` to specify
8518      * how regrouped values should be combined. The iteratee is invoked with the
8519      * elements of each group: (...group).
8520      *
8521      * @static
8522      * @memberOf _
8523      * @since 3.8.0
8524      * @category Array
8525      * @param {Array} array The array of grouped elements to process.
8526      * @param {Function} [iteratee=_.identity] The function to combine
8527      *  regrouped values.
8528      * @returns {Array} Returns the new array of regrouped elements.
8529      * @example
8530      *
8531      * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
8532      * // => [[1, 10, 100], [2, 20, 200]]
8533      *
8534      * _.unzipWith(zipped, _.add);
8535      * // => [3, 30, 300]
8536      */
8537     function unzipWith(array, iteratee) {
8538       if (!(array && array.length)) {
8539         return [];
8540       }
8541       var result = unzip(array);
8542       if (iteratee == null) {
8543         return result;
8544       }
8545       return arrayMap(result, function(group) {
8546         return apply(iteratee, undefined, group);
8547       });
8548     }
8549
8550     /**
8551      * Creates an array excluding all given values using
8552      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8553      * for equality comparisons.
8554      *
8555      * **Note:** Unlike `_.pull`, this method returns a new array.
8556      *
8557      * @static
8558      * @memberOf _
8559      * @since 0.1.0
8560      * @category Array
8561      * @param {Array} array The array to inspect.
8562      * @param {...*} [values] The values to exclude.
8563      * @returns {Array} Returns the new array of filtered values.
8564      * @see _.difference, _.xor
8565      * @example
8566      *
8567      * _.without([2, 1, 2, 3], 1, 2);
8568      * // => [3]
8569      */
8570     var without = baseRest(function(array, values) {
8571       return isArrayLikeObject(array)
8572         ? baseDifference(array, values)
8573         : [];
8574     });
8575
8576     /**
8577      * Creates an array of unique values that is the
8578      * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
8579      * of the given arrays. The order of result values is determined by the order
8580      * they occur in the arrays.
8581      *
8582      * @static
8583      * @memberOf _
8584      * @since 2.4.0
8585      * @category Array
8586      * @param {...Array} [arrays] The arrays to inspect.
8587      * @returns {Array} Returns the new array of filtered values.
8588      * @see _.difference, _.without
8589      * @example
8590      *
8591      * _.xor([2, 1], [2, 3]);
8592      * // => [1, 3]
8593      */
8594     var xor = baseRest(function(arrays) {
8595       return baseXor(arrayFilter(arrays, isArrayLikeObject));
8596     });
8597
8598     /**
8599      * This method is like `_.xor` except that it accepts `iteratee` which is
8600      * invoked for each element of each `arrays` to generate the criterion by
8601      * which by which they're compared. The order of result values is determined
8602      * by the order they occur in the arrays. The iteratee is invoked with one
8603      * argument: (value).
8604      *
8605      * @static
8606      * @memberOf _
8607      * @since 4.0.0
8608      * @category Array
8609      * @param {...Array} [arrays] The arrays to inspect.
8610      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8611      * @returns {Array} Returns the new array of filtered values.
8612      * @example
8613      *
8614      * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
8615      * // => [1.2, 3.4]
8616      *
8617      * // The `_.property` iteratee shorthand.
8618      * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
8619      * // => [{ 'x': 2 }]
8620      */
8621     var xorBy = baseRest(function(arrays) {
8622       var iteratee = last(arrays);
8623       if (isArrayLikeObject(iteratee)) {
8624         iteratee = undefined;
8625       }
8626       return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
8627     });
8628
8629     /**
8630      * This method is like `_.xor` except that it accepts `comparator` which is
8631      * invoked to compare elements of `arrays`. The order of result values is
8632      * determined by the order they occur in the arrays. The comparator is invoked
8633      * with two arguments: (arrVal, othVal).
8634      *
8635      * @static
8636      * @memberOf _
8637      * @since 4.0.0
8638      * @category Array
8639      * @param {...Array} [arrays] The arrays to inspect.
8640      * @param {Function} [comparator] The comparator invoked per element.
8641      * @returns {Array} Returns the new array of filtered values.
8642      * @example
8643      *
8644      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
8645      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
8646      *
8647      * _.xorWith(objects, others, _.isEqual);
8648      * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
8649      */
8650     var xorWith = baseRest(function(arrays) {
8651       var comparator = last(arrays);
8652       comparator = typeof comparator == 'function' ? comparator : undefined;
8653       return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
8654     });
8655
8656     /**
8657      * Creates an array of grouped elements, the first of which contains the
8658      * first elements of the given arrays, the second of which contains the
8659      * second elements of the given arrays, and so on.
8660      *
8661      * @static
8662      * @memberOf _
8663      * @since 0.1.0
8664      * @category Array
8665      * @param {...Array} [arrays] The arrays to process.
8666      * @returns {Array} Returns the new array of grouped elements.
8667      * @example
8668      *
8669      * _.zip(['a', 'b'], [1, 2], [true, false]);
8670      * // => [['a', 1, true], ['b', 2, false]]
8671      */
8672     var zip = baseRest(unzip);
8673
8674     /**
8675      * This method is like `_.fromPairs` except that it accepts two arrays,
8676      * one of property identifiers and one of corresponding values.
8677      *
8678      * @static
8679      * @memberOf _
8680      * @since 0.4.0
8681      * @category Array
8682      * @param {Array} [props=[]] The property identifiers.
8683      * @param {Array} [values=[]] The property values.
8684      * @returns {Object} Returns the new object.
8685      * @example
8686      *
8687      * _.zipObject(['a', 'b'], [1, 2]);
8688      * // => { 'a': 1, 'b': 2 }
8689      */
8690     function zipObject(props, values) {
8691       return baseZipObject(props || [], values || [], assignValue);
8692     }
8693
8694     /**
8695      * This method is like `_.zipObject` except that it supports property paths.
8696      *
8697      * @static
8698      * @memberOf _
8699      * @since 4.1.0
8700      * @category Array
8701      * @param {Array} [props=[]] The property identifiers.
8702      * @param {Array} [values=[]] The property values.
8703      * @returns {Object} Returns the new object.
8704      * @example
8705      *
8706      * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
8707      * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
8708      */
8709     function zipObjectDeep(props, values) {
8710       return baseZipObject(props || [], values || [], baseSet);
8711     }
8712
8713     /**
8714      * This method is like `_.zip` except that it accepts `iteratee` to specify
8715      * how grouped values should be combined. The iteratee is invoked with the
8716      * elements of each group: (...group).
8717      *
8718      * @static
8719      * @memberOf _
8720      * @since 3.8.0
8721      * @category Array
8722      * @param {...Array} [arrays] The arrays to process.
8723      * @param {Function} [iteratee=_.identity] The function to combine
8724      *  grouped values.
8725      * @returns {Array} Returns the new array of grouped elements.
8726      * @example
8727      *
8728      * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
8729      *   return a + b + c;
8730      * });
8731      * // => [111, 222]
8732      */
8733     var zipWith = baseRest(function(arrays) {
8734       var length = arrays.length,
8735           iteratee = length > 1 ? arrays[length - 1] : undefined;
8736
8737       iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
8738       return unzipWith(arrays, iteratee);
8739     });
8740
8741     /*------------------------------------------------------------------------*/
8742
8743     /**
8744      * Creates a `lodash` wrapper instance that wraps `value` with explicit method
8745      * chain sequences enabled. The result of such sequences must be unwrapped
8746      * with `_#value`.
8747      *
8748      * @static
8749      * @memberOf _
8750      * @since 1.3.0
8751      * @category Seq
8752      * @param {*} value The value to wrap.
8753      * @returns {Object} Returns the new `lodash` wrapper instance.
8754      * @example
8755      *
8756      * var users = [
8757      *   { 'user': 'barney',  'age': 36 },
8758      *   { 'user': 'fred',    'age': 40 },
8759      *   { 'user': 'pebbles', 'age': 1 }
8760      * ];
8761      *
8762      * var youngest = _
8763      *   .chain(users)
8764      *   .sortBy('age')
8765      *   .map(function(o) {
8766      *     return o.user + ' is ' + o.age;
8767      *   })
8768      *   .head()
8769      *   .value();
8770      * // => 'pebbles is 1'
8771      */
8772     function chain(value) {
8773       var result = lodash(value);
8774       result.__chain__ = true;
8775       return result;
8776     }
8777
8778     /**
8779      * This method invokes `interceptor` and returns `value`. The interceptor
8780      * is invoked with one argument; (value). The purpose of this method is to
8781      * "tap into" a method chain sequence in order to modify intermediate results.
8782      *
8783      * @static
8784      * @memberOf _
8785      * @since 0.1.0
8786      * @category Seq
8787      * @param {*} value The value to provide to `interceptor`.
8788      * @param {Function} interceptor The function to invoke.
8789      * @returns {*} Returns `value`.
8790      * @example
8791      *
8792      * _([1, 2, 3])
8793      *  .tap(function(array) {
8794      *    // Mutate input array.
8795      *    array.pop();
8796      *  })
8797      *  .reverse()
8798      *  .value();
8799      * // => [2, 1]
8800      */
8801     function tap(value, interceptor) {
8802       interceptor(value);
8803       return value;
8804     }
8805
8806     /**
8807      * This method is like `_.tap` except that it returns the result of `interceptor`.
8808      * The purpose of this method is to "pass thru" values replacing intermediate
8809      * results in a method chain sequence.
8810      *
8811      * @static
8812      * @memberOf _
8813      * @since 3.0.0
8814      * @category Seq
8815      * @param {*} value The value to provide to `interceptor`.
8816      * @param {Function} interceptor The function to invoke.
8817      * @returns {*} Returns the result of `interceptor`.
8818      * @example
8819      *
8820      * _('  abc  ')
8821      *  .chain()
8822      *  .trim()
8823      *  .thru(function(value) {
8824      *    return [value];
8825      *  })
8826      *  .value();
8827      * // => ['abc']
8828      */
8829     function thru(value, interceptor) {
8830       return interceptor(value);
8831     }
8832
8833     /**
8834      * This method is the wrapper version of `_.at`.
8835      *
8836      * @name at
8837      * @memberOf _
8838      * @since 1.0.0
8839      * @category Seq
8840      * @param {...(string|string[])} [paths] The property paths to pick.
8841      * @returns {Object} Returns the new `lodash` wrapper instance.
8842      * @example
8843      *
8844      * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
8845      *
8846      * _(object).at(['a[0].b.c', 'a[1]']).value();
8847      * // => [3, 4]
8848      */
8849     var wrapperAt = flatRest(function(paths) {
8850       var length = paths.length,
8851           start = length ? paths[0] : 0,
8852           value = this.__wrapped__,
8853           interceptor = function(object) { return baseAt(object, paths); };
8854
8855       if (length > 1 || this.__actions__.length ||
8856           !(value instanceof LazyWrapper) || !isIndex(start)) {
8857         return this.thru(interceptor);
8858       }
8859       value = value.slice(start, +start + (length ? 1 : 0));
8860       value.__actions__.push({
8861         'func': thru,
8862         'args': [interceptor],
8863         'thisArg': undefined
8864       });
8865       return new LodashWrapper(value, this.__chain__).thru(function(array) {
8866         if (length && !array.length) {
8867           array.push(undefined);
8868         }
8869         return array;
8870       });
8871     });
8872
8873     /**
8874      * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
8875      *
8876      * @name chain
8877      * @memberOf _
8878      * @since 0.1.0
8879      * @category Seq
8880      * @returns {Object} Returns the new `lodash` wrapper instance.
8881      * @example
8882      *
8883      * var users = [
8884      *   { 'user': 'barney', 'age': 36 },
8885      *   { 'user': 'fred',   'age': 40 }
8886      * ];
8887      *
8888      * // A sequence without explicit chaining.
8889      * _(users).head();
8890      * // => { 'user': 'barney', 'age': 36 }
8891      *
8892      * // A sequence with explicit chaining.
8893      * _(users)
8894      *   .chain()
8895      *   .head()
8896      *   .pick('user')
8897      *   .value();
8898      * // => { 'user': 'barney' }
8899      */
8900     function wrapperChain() {
8901       return chain(this);
8902     }
8903
8904     /**
8905      * Executes the chain sequence and returns the wrapped result.
8906      *
8907      * @name commit
8908      * @memberOf _
8909      * @since 3.2.0
8910      * @category Seq
8911      * @returns {Object} Returns the new `lodash` wrapper instance.
8912      * @example
8913      *
8914      * var array = [1, 2];
8915      * var wrapped = _(array).push(3);
8916      *
8917      * console.log(array);
8918      * // => [1, 2]
8919      *
8920      * wrapped = wrapped.commit();
8921      * console.log(array);
8922      * // => [1, 2, 3]
8923      *
8924      * wrapped.last();
8925      * // => 3
8926      *
8927      * console.log(array);
8928      * // => [1, 2, 3]
8929      */
8930     function wrapperCommit() {
8931       return new LodashWrapper(this.value(), this.__chain__);
8932     }
8933
8934     /**
8935      * Gets the next value on a wrapped object following the
8936      * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
8937      *
8938      * @name next
8939      * @memberOf _
8940      * @since 4.0.0
8941      * @category Seq
8942      * @returns {Object} Returns the next iterator value.
8943      * @example
8944      *
8945      * var wrapped = _([1, 2]);
8946      *
8947      * wrapped.next();
8948      * // => { 'done': false, 'value': 1 }
8949      *
8950      * wrapped.next();
8951      * // => { 'done': false, 'value': 2 }
8952      *
8953      * wrapped.next();
8954      * // => { 'done': true, 'value': undefined }
8955      */
8956     function wrapperNext() {
8957       if (this.__values__ === undefined) {
8958         this.__values__ = toArray(this.value());
8959       }
8960       var done = this.__index__ >= this.__values__.length,
8961           value = done ? undefined : this.__values__[this.__index__++];
8962
8963       return { 'done': done, 'value': value };
8964     }
8965
8966     /**
8967      * Enables the wrapper to be iterable.
8968      *
8969      * @name Symbol.iterator
8970      * @memberOf _
8971      * @since 4.0.0
8972      * @category Seq
8973      * @returns {Object} Returns the wrapper object.
8974      * @example
8975      *
8976      * var wrapped = _([1, 2]);
8977      *
8978      * wrapped[Symbol.iterator]() === wrapped;
8979      * // => true
8980      *
8981      * Array.from(wrapped);
8982      * // => [1, 2]
8983      */
8984     function wrapperToIterator() {
8985       return this;
8986     }
8987
8988     /**
8989      * Creates a clone of the chain sequence planting `value` as the wrapped value.
8990      *
8991      * @name plant
8992      * @memberOf _
8993      * @since 3.2.0
8994      * @category Seq
8995      * @param {*} value The value to plant.
8996      * @returns {Object} Returns the new `lodash` wrapper instance.
8997      * @example
8998      *
8999      * function square(n) {
9000      *   return n * n;
9001      * }
9002      *
9003      * var wrapped = _([1, 2]).map(square);
9004      * var other = wrapped.plant([3, 4]);
9005      *
9006      * other.value();
9007      * // => [9, 16]
9008      *
9009      * wrapped.value();
9010      * // => [1, 4]
9011      */
9012     function wrapperPlant(value) {
9013       var result,
9014           parent = this;
9015
9016       while (parent instanceof baseLodash) {
9017         var clone = wrapperClone(parent);
9018         clone.__index__ = 0;
9019         clone.__values__ = undefined;
9020         if (result) {
9021           previous.__wrapped__ = clone;
9022         } else {
9023           result = clone;
9024         }
9025         var previous = clone;
9026         parent = parent.__wrapped__;
9027       }
9028       previous.__wrapped__ = value;
9029       return result;
9030     }
9031
9032     /**
9033      * This method is the wrapper version of `_.reverse`.
9034      *
9035      * **Note:** This method mutates the wrapped array.
9036      *
9037      * @name reverse
9038      * @memberOf _
9039      * @since 0.1.0
9040      * @category Seq
9041      * @returns {Object} Returns the new `lodash` wrapper instance.
9042      * @example
9043      *
9044      * var array = [1, 2, 3];
9045      *
9046      * _(array).reverse().value()
9047      * // => [3, 2, 1]
9048      *
9049      * console.log(array);
9050      * // => [3, 2, 1]
9051      */
9052     function wrapperReverse() {
9053       var value = this.__wrapped__;
9054       if (value instanceof LazyWrapper) {
9055         var wrapped = value;
9056         if (this.__actions__.length) {
9057           wrapped = new LazyWrapper(this);
9058         }
9059         wrapped = wrapped.reverse();
9060         wrapped.__actions__.push({
9061           'func': thru,
9062           'args': [reverse],
9063           'thisArg': undefined
9064         });
9065         return new LodashWrapper(wrapped, this.__chain__);
9066       }
9067       return this.thru(reverse);
9068     }
9069
9070     /**
9071      * Executes the chain sequence to resolve the unwrapped value.
9072      *
9073      * @name value
9074      * @memberOf _
9075      * @since 0.1.0
9076      * @alias toJSON, valueOf
9077      * @category Seq
9078      * @returns {*} Returns the resolved unwrapped value.
9079      * @example
9080      *
9081      * _([1, 2, 3]).value();
9082      * // => [1, 2, 3]
9083      */
9084     function wrapperValue() {
9085       return baseWrapperValue(this.__wrapped__, this.__actions__);
9086     }
9087
9088     /*------------------------------------------------------------------------*/
9089
9090     /**
9091      * Creates an object composed of keys generated from the results of running
9092      * each element of `collection` thru `iteratee`. The corresponding value of
9093      * each key is the number of times the key was returned by `iteratee`. The
9094      * iteratee is invoked with one argument: (value).
9095      *
9096      * @static
9097      * @memberOf _
9098      * @since 0.5.0
9099      * @category Collection
9100      * @param {Array|Object} collection The collection to iterate over.
9101      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9102      * @returns {Object} Returns the composed aggregate object.
9103      * @example
9104      *
9105      * _.countBy([6.1, 4.2, 6.3], Math.floor);
9106      * // => { '4': 1, '6': 2 }
9107      *
9108      * // The `_.property` iteratee shorthand.
9109      * _.countBy(['one', 'two', 'three'], 'length');
9110      * // => { '3': 2, '5': 1 }
9111      */
9112     var countBy = createAggregator(function(result, value, key) {
9113       if (hasOwnProperty.call(result, key)) {
9114         ++result[key];
9115       } else {
9116         baseAssignValue(result, key, 1);
9117       }
9118     });
9119
9120     /**
9121      * Checks if `predicate` returns truthy for **all** elements of `collection`.
9122      * Iteration is stopped once `predicate` returns falsey. The predicate is
9123      * invoked with three arguments: (value, index|key, collection).
9124      *
9125      * **Note:** This method returns `true` for
9126      * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
9127      * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
9128      * elements of empty collections.
9129      *
9130      * @static
9131      * @memberOf _
9132      * @since 0.1.0
9133      * @category Collection
9134      * @param {Array|Object} collection The collection to iterate over.
9135      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9136      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9137      * @returns {boolean} Returns `true` if all elements pass the predicate check,
9138      *  else `false`.
9139      * @example
9140      *
9141      * _.every([true, 1, null, 'yes'], Boolean);
9142      * // => false
9143      *
9144      * var users = [
9145      *   { 'user': 'barney', 'age': 36, 'active': false },
9146      *   { 'user': 'fred',   'age': 40, 'active': false }
9147      * ];
9148      *
9149      * // The `_.matches` iteratee shorthand.
9150      * _.every(users, { 'user': 'barney', 'active': false });
9151      * // => false
9152      *
9153      * // The `_.matchesProperty` iteratee shorthand.
9154      * _.every(users, ['active', false]);
9155      * // => true
9156      *
9157      * // The `_.property` iteratee shorthand.
9158      * _.every(users, 'active');
9159      * // => false
9160      */
9161     function every(collection, predicate, guard) {
9162       var func = isArray(collection) ? arrayEvery : baseEvery;
9163       if (guard && isIterateeCall(collection, predicate, guard)) {
9164         predicate = undefined;
9165       }
9166       return func(collection, getIteratee(predicate, 3));
9167     }
9168
9169     /**
9170      * Iterates over elements of `collection`, returning an array of all elements
9171      * `predicate` returns truthy for. The predicate is invoked with three
9172      * arguments: (value, index|key, collection).
9173      *
9174      * **Note:** Unlike `_.remove`, this method returns a new array.
9175      *
9176      * @static
9177      * @memberOf _
9178      * @since 0.1.0
9179      * @category Collection
9180      * @param {Array|Object} collection The collection to iterate over.
9181      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9182      * @returns {Array} Returns the new filtered array.
9183      * @see _.reject
9184      * @example
9185      *
9186      * var users = [
9187      *   { 'user': 'barney', 'age': 36, 'active': true },
9188      *   { 'user': 'fred',   'age': 40, 'active': false }
9189      * ];
9190      *
9191      * _.filter(users, function(o) { return !o.active; });
9192      * // => objects for ['fred']
9193      *
9194      * // The `_.matches` iteratee shorthand.
9195      * _.filter(users, { 'age': 36, 'active': true });
9196      * // => objects for ['barney']
9197      *
9198      * // The `_.matchesProperty` iteratee shorthand.
9199      * _.filter(users, ['active', false]);
9200      * // => objects for ['fred']
9201      *
9202      * // The `_.property` iteratee shorthand.
9203      * _.filter(users, 'active');
9204      * // => objects for ['barney']
9205      */
9206     function filter(collection, predicate) {
9207       var func = isArray(collection) ? arrayFilter : baseFilter;
9208       return func(collection, getIteratee(predicate, 3));
9209     }
9210
9211     /**
9212      * Iterates over elements of `collection`, returning the first element
9213      * `predicate` returns truthy for. The predicate is invoked with three
9214      * arguments: (value, index|key, collection).
9215      *
9216      * @static
9217      * @memberOf _
9218      * @since 0.1.0
9219      * @category Collection
9220      * @param {Array|Object} collection The collection to inspect.
9221      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9222      * @param {number} [fromIndex=0] The index to search from.
9223      * @returns {*} Returns the matched element, else `undefined`.
9224      * @example
9225      *
9226      * var users = [
9227      *   { 'user': 'barney',  'age': 36, 'active': true },
9228      *   { 'user': 'fred',    'age': 40, 'active': false },
9229      *   { 'user': 'pebbles', 'age': 1,  'active': true }
9230      * ];
9231      *
9232      * _.find(users, function(o) { return o.age < 40; });
9233      * // => object for 'barney'
9234      *
9235      * // The `_.matches` iteratee shorthand.
9236      * _.find(users, { 'age': 1, 'active': true });
9237      * // => object for 'pebbles'
9238      *
9239      * // The `_.matchesProperty` iteratee shorthand.
9240      * _.find(users, ['active', false]);
9241      * // => object for 'fred'
9242      *
9243      * // The `_.property` iteratee shorthand.
9244      * _.find(users, 'active');
9245      * // => object for 'barney'
9246      */
9247     var find = createFind(findIndex);
9248
9249     /**
9250      * This method is like `_.find` except that it iterates over elements of
9251      * `collection` from right to left.
9252      *
9253      * @static
9254      * @memberOf _
9255      * @since 2.0.0
9256      * @category Collection
9257      * @param {Array|Object} collection The collection to inspect.
9258      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9259      * @param {number} [fromIndex=collection.length-1] The index to search from.
9260      * @returns {*} Returns the matched element, else `undefined`.
9261      * @example
9262      *
9263      * _.findLast([1, 2, 3, 4], function(n) {
9264      *   return n % 2 == 1;
9265      * });
9266      * // => 3
9267      */
9268     var findLast = createFind(findLastIndex);
9269
9270     /**
9271      * Creates a flattened array of values by running each element in `collection`
9272      * thru `iteratee` and flattening the mapped results. The iteratee is invoked
9273      * with three arguments: (value, index|key, collection).
9274      *
9275      * @static
9276      * @memberOf _
9277      * @since 4.0.0
9278      * @category Collection
9279      * @param {Array|Object} collection The collection to iterate over.
9280      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9281      * @returns {Array} Returns the new flattened array.
9282      * @example
9283      *
9284      * function duplicate(n) {
9285      *   return [n, n];
9286      * }
9287      *
9288      * _.flatMap([1, 2], duplicate);
9289      * // => [1, 1, 2, 2]
9290      */
9291     function flatMap(collection, iteratee) {
9292       return baseFlatten(map(collection, iteratee), 1);
9293     }
9294
9295     /**
9296      * This method is like `_.flatMap` except that it recursively flattens the
9297      * mapped results.
9298      *
9299      * @static
9300      * @memberOf _
9301      * @since 4.7.0
9302      * @category Collection
9303      * @param {Array|Object} collection The collection to iterate over.
9304      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9305      * @returns {Array} Returns the new flattened array.
9306      * @example
9307      *
9308      * function duplicate(n) {
9309      *   return [[[n, n]]];
9310      * }
9311      *
9312      * _.flatMapDeep([1, 2], duplicate);
9313      * // => [1, 1, 2, 2]
9314      */
9315     function flatMapDeep(collection, iteratee) {
9316       return baseFlatten(map(collection, iteratee), INFINITY);
9317     }
9318
9319     /**
9320      * This method is like `_.flatMap` except that it recursively flattens the
9321      * mapped results up to `depth` times.
9322      *
9323      * @static
9324      * @memberOf _
9325      * @since 4.7.0
9326      * @category Collection
9327      * @param {Array|Object} collection The collection to iterate over.
9328      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9329      * @param {number} [depth=1] The maximum recursion depth.
9330      * @returns {Array} Returns the new flattened array.
9331      * @example
9332      *
9333      * function duplicate(n) {
9334      *   return [[[n, n]]];
9335      * }
9336      *
9337      * _.flatMapDepth([1, 2], duplicate, 2);
9338      * // => [[1, 1], [2, 2]]
9339      */
9340     function flatMapDepth(collection, iteratee, depth) {
9341       depth = depth === undefined ? 1 : toInteger(depth);
9342       return baseFlatten(map(collection, iteratee), depth);
9343     }
9344
9345     /**
9346      * Iterates over elements of `collection` and invokes `iteratee` for each element.
9347      * The iteratee is invoked with three arguments: (value, index|key, collection).
9348      * Iteratee functions may exit iteration early by explicitly returning `false`.
9349      *
9350      * **Note:** As with other "Collections" methods, objects with a "length"
9351      * property are iterated like arrays. To avoid this behavior use `_.forIn`
9352      * or `_.forOwn` for object iteration.
9353      *
9354      * @static
9355      * @memberOf _
9356      * @since 0.1.0
9357      * @alias each
9358      * @category Collection
9359      * @param {Array|Object} collection The collection to iterate over.
9360      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9361      * @returns {Array|Object} Returns `collection`.
9362      * @see _.forEachRight
9363      * @example
9364      *
9365      * _.forEach([1, 2], function(value) {
9366      *   console.log(value);
9367      * });
9368      * // => Logs `1` then `2`.
9369      *
9370      * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
9371      *   console.log(key);
9372      * });
9373      * // => Logs 'a' then 'b' (iteration order is not guaranteed).
9374      */
9375     function forEach(collection, iteratee) {
9376       var func = isArray(collection) ? arrayEach : baseEach;
9377       return func(collection, getIteratee(iteratee, 3));
9378     }
9379
9380     /**
9381      * This method is like `_.forEach` except that it iterates over elements of
9382      * `collection` from right to left.
9383      *
9384      * @static
9385      * @memberOf _
9386      * @since 2.0.0
9387      * @alias eachRight
9388      * @category Collection
9389      * @param {Array|Object} collection The collection to iterate over.
9390      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9391      * @returns {Array|Object} Returns `collection`.
9392      * @see _.forEach
9393      * @example
9394      *
9395      * _.forEachRight([1, 2], function(value) {
9396      *   console.log(value);
9397      * });
9398      * // => Logs `2` then `1`.
9399      */
9400     function forEachRight(collection, iteratee) {
9401       var func = isArray(collection) ? arrayEachRight : baseEachRight;
9402       return func(collection, getIteratee(iteratee, 3));
9403     }
9404
9405     /**
9406      * Creates an object composed of keys generated from the results of running
9407      * each element of `collection` thru `iteratee`. The order of grouped values
9408      * is determined by the order they occur in `collection`. The corresponding
9409      * value of each key is an array of elements responsible for generating the
9410      * key. The iteratee is invoked with one argument: (value).
9411      *
9412      * @static
9413      * @memberOf _
9414      * @since 0.1.0
9415      * @category Collection
9416      * @param {Array|Object} collection The collection to iterate over.
9417      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9418      * @returns {Object} Returns the composed aggregate object.
9419      * @example
9420      *
9421      * _.groupBy([6.1, 4.2, 6.3], Math.floor);
9422      * // => { '4': [4.2], '6': [6.1, 6.3] }
9423      *
9424      * // The `_.property` iteratee shorthand.
9425      * _.groupBy(['one', 'two', 'three'], 'length');
9426      * // => { '3': ['one', 'two'], '5': ['three'] }
9427      */
9428     var groupBy = createAggregator(function(result, value, key) {
9429       if (hasOwnProperty.call(result, key)) {
9430         result[key].push(value);
9431       } else {
9432         baseAssignValue(result, key, [value]);
9433       }
9434     });
9435
9436     /**
9437      * Checks if `value` is in `collection`. If `collection` is a string, it's
9438      * checked for a substring of `value`, otherwise
9439      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
9440      * is used for equality comparisons. If `fromIndex` is negative, it's used as
9441      * the offset from the end of `collection`.
9442      *
9443      * @static
9444      * @memberOf _
9445      * @since 0.1.0
9446      * @category Collection
9447      * @param {Array|Object|string} collection The collection to inspect.
9448      * @param {*} value The value to search for.
9449      * @param {number} [fromIndex=0] The index to search from.
9450      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
9451      * @returns {boolean} Returns `true` if `value` is found, else `false`.
9452      * @example
9453      *
9454      * _.includes([1, 2, 3], 1);
9455      * // => true
9456      *
9457      * _.includes([1, 2, 3], 1, 2);
9458      * // => false
9459      *
9460      * _.includes({ 'a': 1, 'b': 2 }, 1);
9461      * // => true
9462      *
9463      * _.includes('abcd', 'bc');
9464      * // => true
9465      */
9466     function includes(collection, value, fromIndex, guard) {
9467       collection = isArrayLike(collection) ? collection : values(collection);
9468       fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
9469
9470       var length = collection.length;
9471       if (fromIndex < 0) {
9472         fromIndex = nativeMax(length + fromIndex, 0);
9473       }
9474       return isString(collection)
9475         ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
9476         : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
9477     }
9478
9479     /**
9480      * Invokes the method at `path` of each element in `collection`, returning
9481      * an array of the results of each invoked method. Any additional arguments
9482      * are provided to each invoked method. If `path` is a function, it's invoked
9483      * for, and `this` bound to, each element in `collection`.
9484      *
9485      * @static
9486      * @memberOf _
9487      * @since 4.0.0
9488      * @category Collection
9489      * @param {Array|Object} collection The collection to iterate over.
9490      * @param {Array|Function|string} path The path of the method to invoke or
9491      *  the function invoked per iteration.
9492      * @param {...*} [args] The arguments to invoke each method with.
9493      * @returns {Array} Returns the array of results.
9494      * @example
9495      *
9496      * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
9497      * // => [[1, 5, 7], [1, 2, 3]]
9498      *
9499      * _.invokeMap([123, 456], String.prototype.split, '');
9500      * // => [['1', '2', '3'], ['4', '5', '6']]
9501      */
9502     var invokeMap = baseRest(function(collection, path, args) {
9503       var index = -1,
9504           isFunc = typeof path == 'function',
9505           result = isArrayLike(collection) ? Array(collection.length) : [];
9506
9507       baseEach(collection, function(value) {
9508         result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
9509       });
9510       return result;
9511     });
9512
9513     /**
9514      * Creates an object composed of keys generated from the results of running
9515      * each element of `collection` thru `iteratee`. The corresponding value of
9516      * each key is the last element responsible for generating the key. The
9517      * iteratee is invoked with one argument: (value).
9518      *
9519      * @static
9520      * @memberOf _
9521      * @since 4.0.0
9522      * @category Collection
9523      * @param {Array|Object} collection The collection to iterate over.
9524      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9525      * @returns {Object} Returns the composed aggregate object.
9526      * @example
9527      *
9528      * var array = [
9529      *   { 'dir': 'left', 'code': 97 },
9530      *   { 'dir': 'right', 'code': 100 }
9531      * ];
9532      *
9533      * _.keyBy(array, function(o) {
9534      *   return String.fromCharCode(o.code);
9535      * });
9536      * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
9537      *
9538      * _.keyBy(array, 'dir');
9539      * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
9540      */
9541     var keyBy = createAggregator(function(result, value, key) {
9542       baseAssignValue(result, key, value);
9543     });
9544
9545     /**
9546      * Creates an array of values by running each element in `collection` thru
9547      * `iteratee`. The iteratee is invoked with three arguments:
9548      * (value, index|key, collection).
9549      *
9550      * Many lodash methods are guarded to work as iteratees for methods like
9551      * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
9552      *
9553      * The guarded methods are:
9554      * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
9555      * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
9556      * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
9557      * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
9558      *
9559      * @static
9560      * @memberOf _
9561      * @since 0.1.0
9562      * @category Collection
9563      * @param {Array|Object} collection The collection to iterate over.
9564      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9565      * @returns {Array} Returns the new mapped array.
9566      * @example
9567      *
9568      * function square(n) {
9569      *   return n * n;
9570      * }
9571      *
9572      * _.map([4, 8], square);
9573      * // => [16, 64]
9574      *
9575      * _.map({ 'a': 4, 'b': 8 }, square);
9576      * // => [16, 64] (iteration order is not guaranteed)
9577      *
9578      * var users = [
9579      *   { 'user': 'barney' },
9580      *   { 'user': 'fred' }
9581      * ];
9582      *
9583      * // The `_.property` iteratee shorthand.
9584      * _.map(users, 'user');
9585      * // => ['barney', 'fred']
9586      */
9587     function map(collection, iteratee) {
9588       var func = isArray(collection) ? arrayMap : baseMap;
9589       return func(collection, getIteratee(iteratee, 3));
9590     }
9591
9592     /**
9593      * This method is like `_.sortBy` except that it allows specifying the sort
9594      * orders of the iteratees to sort by. If `orders` is unspecified, all values
9595      * are sorted in ascending order. Otherwise, specify an order of "desc" for
9596      * descending or "asc" for ascending sort order of corresponding values.
9597      *
9598      * @static
9599      * @memberOf _
9600      * @since 4.0.0
9601      * @category Collection
9602      * @param {Array|Object} collection The collection to iterate over.
9603      * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
9604      *  The iteratees to sort by.
9605      * @param {string[]} [orders] The sort orders of `iteratees`.
9606      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
9607      * @returns {Array} Returns the new sorted array.
9608      * @example
9609      *
9610      * var users = [
9611      *   { 'user': 'fred',   'age': 48 },
9612      *   { 'user': 'barney', 'age': 34 },
9613      *   { 'user': 'fred',   'age': 40 },
9614      *   { 'user': 'barney', 'age': 36 }
9615      * ];
9616      *
9617      * // Sort by `user` in ascending order and by `age` in descending order.
9618      * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
9619      * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
9620      */
9621     function orderBy(collection, iteratees, orders, guard) {
9622       if (collection == null) {
9623         return [];
9624       }
9625       if (!isArray(iteratees)) {
9626         iteratees = iteratees == null ? [] : [iteratees];
9627       }
9628       orders = guard ? undefined : orders;
9629       if (!isArray(orders)) {
9630         orders = orders == null ? [] : [orders];
9631       }
9632       return baseOrderBy(collection, iteratees, orders);
9633     }
9634
9635     /**
9636      * Creates an array of elements split into two groups, the first of which
9637      * contains elements `predicate` returns truthy for, the second of which
9638      * contains elements `predicate` returns falsey for. The predicate is
9639      * invoked with one argument: (value).
9640      *
9641      * @static
9642      * @memberOf _
9643      * @since 3.0.0
9644      * @category Collection
9645      * @param {Array|Object} collection The collection to iterate over.
9646      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9647      * @returns {Array} Returns the array of grouped elements.
9648      * @example
9649      *
9650      * var users = [
9651      *   { 'user': 'barney',  'age': 36, 'active': false },
9652      *   { 'user': 'fred',    'age': 40, 'active': true },
9653      *   { 'user': 'pebbles', 'age': 1,  'active': false }
9654      * ];
9655      *
9656      * _.partition(users, function(o) { return o.active; });
9657      * // => objects for [['fred'], ['barney', 'pebbles']]
9658      *
9659      * // The `_.matches` iteratee shorthand.
9660      * _.partition(users, { 'age': 1, 'active': false });
9661      * // => objects for [['pebbles'], ['barney', 'fred']]
9662      *
9663      * // The `_.matchesProperty` iteratee shorthand.
9664      * _.partition(users, ['active', false]);
9665      * // => objects for [['barney', 'pebbles'], ['fred']]
9666      *
9667      * // The `_.property` iteratee shorthand.
9668      * _.partition(users, 'active');
9669      * // => objects for [['fred'], ['barney', 'pebbles']]
9670      */
9671     var partition = createAggregator(function(result, value, key) {
9672       result[key ? 0 : 1].push(value);
9673     }, function() { return [[], []]; });
9674
9675     /**
9676      * Reduces `collection` to a value which is the accumulated result of running
9677      * each element in `collection` thru `iteratee`, where each successive
9678      * invocation is supplied the return value of the previous. If `accumulator`
9679      * is not given, the first element of `collection` is used as the initial
9680      * value. The iteratee is invoked with four arguments:
9681      * (accumulator, value, index|key, collection).
9682      *
9683      * Many lodash methods are guarded to work as iteratees for methods like
9684      * `_.reduce`, `_.reduceRight`, and `_.transform`.
9685      *
9686      * The guarded methods are:
9687      * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
9688      * and `sortBy`
9689      *
9690      * @static
9691      * @memberOf _
9692      * @since 0.1.0
9693      * @category Collection
9694      * @param {Array|Object} collection The collection to iterate over.
9695      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9696      * @param {*} [accumulator] The initial value.
9697      * @returns {*} Returns the accumulated value.
9698      * @see _.reduceRight
9699      * @example
9700      *
9701      * _.reduce([1, 2], function(sum, n) {
9702      *   return sum + n;
9703      * }, 0);
9704      * // => 3
9705      *
9706      * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
9707      *   (result[value] || (result[value] = [])).push(key);
9708      *   return result;
9709      * }, {});
9710      * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
9711      */
9712     function reduce(collection, iteratee, accumulator) {
9713       var func = isArray(collection) ? arrayReduce : baseReduce,
9714           initAccum = arguments.length < 3;
9715
9716       return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
9717     }
9718
9719     /**
9720      * This method is like `_.reduce` except that it iterates over elements of
9721      * `collection` from right to left.
9722      *
9723      * @static
9724      * @memberOf _
9725      * @since 0.1.0
9726      * @category Collection
9727      * @param {Array|Object} collection The collection to iterate over.
9728      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9729      * @param {*} [accumulator] The initial value.
9730      * @returns {*} Returns the accumulated value.
9731      * @see _.reduce
9732      * @example
9733      *
9734      * var array = [[0, 1], [2, 3], [4, 5]];
9735      *
9736      * _.reduceRight(array, function(flattened, other) {
9737      *   return flattened.concat(other);
9738      * }, []);
9739      * // => [4, 5, 2, 3, 0, 1]
9740      */
9741     function reduceRight(collection, iteratee, accumulator) {
9742       var func = isArray(collection) ? arrayReduceRight : baseReduce,
9743           initAccum = arguments.length < 3;
9744
9745       return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
9746     }
9747
9748     /**
9749      * The opposite of `_.filter`; this method returns the elements of `collection`
9750      * that `predicate` does **not** return truthy for.
9751      *
9752      * @static
9753      * @memberOf _
9754      * @since 0.1.0
9755      * @category Collection
9756      * @param {Array|Object} collection The collection to iterate over.
9757      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9758      * @returns {Array} Returns the new filtered array.
9759      * @see _.filter
9760      * @example
9761      *
9762      * var users = [
9763      *   { 'user': 'barney', 'age': 36, 'active': false },
9764      *   { 'user': 'fred',   'age': 40, 'active': true }
9765      * ];
9766      *
9767      * _.reject(users, function(o) { return !o.active; });
9768      * // => objects for ['fred']
9769      *
9770      * // The `_.matches` iteratee shorthand.
9771      * _.reject(users, { 'age': 40, 'active': true });
9772      * // => objects for ['barney']
9773      *
9774      * // The `_.matchesProperty` iteratee shorthand.
9775      * _.reject(users, ['active', false]);
9776      * // => objects for ['fred']
9777      *
9778      * // The `_.property` iteratee shorthand.
9779      * _.reject(users, 'active');
9780      * // => objects for ['barney']
9781      */
9782     function reject(collection, predicate) {
9783       var func = isArray(collection) ? arrayFilter : baseFilter;
9784       return func(collection, negate(getIteratee(predicate, 3)));
9785     }
9786
9787     /**
9788      * Gets a random element from `collection`.
9789      *
9790      * @static
9791      * @memberOf _
9792      * @since 2.0.0
9793      * @category Collection
9794      * @param {Array|Object} collection The collection to sample.
9795      * @returns {*} Returns the random element.
9796      * @example
9797      *
9798      * _.sample([1, 2, 3, 4]);
9799      * // => 2
9800      */
9801     function sample(collection) {
9802       var func = isArray(collection) ? arraySample : baseSample;
9803       return func(collection);
9804     }
9805
9806     /**
9807      * Gets `n` random elements at unique keys from `collection` up to the
9808      * size of `collection`.
9809      *
9810      * @static
9811      * @memberOf _
9812      * @since 4.0.0
9813      * @category Collection
9814      * @param {Array|Object} collection The collection to sample.
9815      * @param {number} [n=1] The number of elements to sample.
9816      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9817      * @returns {Array} Returns the random elements.
9818      * @example
9819      *
9820      * _.sampleSize([1, 2, 3], 2);
9821      * // => [3, 1]
9822      *
9823      * _.sampleSize([1, 2, 3], 4);
9824      * // => [2, 3, 1]
9825      */
9826     function sampleSize(collection, n, guard) {
9827       if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
9828         n = 1;
9829       } else {
9830         n = toInteger(n);
9831       }
9832       var func = isArray(collection) ? arraySampleSize : baseSampleSize;
9833       return func(collection, n);
9834     }
9835
9836     /**
9837      * Creates an array of shuffled values, using a version of the
9838      * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
9839      *
9840      * @static
9841      * @memberOf _
9842      * @since 0.1.0
9843      * @category Collection
9844      * @param {Array|Object} collection The collection to shuffle.
9845      * @returns {Array} Returns the new shuffled array.
9846      * @example
9847      *
9848      * _.shuffle([1, 2, 3, 4]);
9849      * // => [4, 1, 3, 2]
9850      */
9851     function shuffle(collection) {
9852       var func = isArray(collection) ? arrayShuffle : baseShuffle;
9853       return func(collection);
9854     }
9855
9856     /**
9857      * Gets the size of `collection` by returning its length for array-like
9858      * values or the number of own enumerable string keyed properties for objects.
9859      *
9860      * @static
9861      * @memberOf _
9862      * @since 0.1.0
9863      * @category Collection
9864      * @param {Array|Object|string} collection The collection to inspect.
9865      * @returns {number} Returns the collection size.
9866      * @example
9867      *
9868      * _.size([1, 2, 3]);
9869      * // => 3
9870      *
9871      * _.size({ 'a': 1, 'b': 2 });
9872      * // => 2
9873      *
9874      * _.size('pebbles');
9875      * // => 7
9876      */
9877     function size(collection) {
9878       if (collection == null) {
9879         return 0;
9880       }
9881       if (isArrayLike(collection)) {
9882         return isString(collection) ? stringSize(collection) : collection.length;
9883       }
9884       var tag = getTag(collection);
9885       if (tag == mapTag || tag == setTag) {
9886         return collection.size;
9887       }
9888       return baseKeys(collection).length;
9889     }
9890
9891     /**
9892      * Checks if `predicate` returns truthy for **any** element of `collection`.
9893      * Iteration is stopped once `predicate` returns truthy. The predicate is
9894      * invoked with three arguments: (value, index|key, collection).
9895      *
9896      * @static
9897      * @memberOf _
9898      * @since 0.1.0
9899      * @category Collection
9900      * @param {Array|Object} collection The collection to iterate over.
9901      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9902      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9903      * @returns {boolean} Returns `true` if any element passes the predicate check,
9904      *  else `false`.
9905      * @example
9906      *
9907      * _.some([null, 0, 'yes', false], Boolean);
9908      * // => true
9909      *
9910      * var users = [
9911      *   { 'user': 'barney', 'active': true },
9912      *   { 'user': 'fred',   'active': false }
9913      * ];
9914      *
9915      * // The `_.matches` iteratee shorthand.
9916      * _.some(users, { 'user': 'barney', 'active': false });
9917      * // => false
9918      *
9919      * // The `_.matchesProperty` iteratee shorthand.
9920      * _.some(users, ['active', false]);
9921      * // => true
9922      *
9923      * // The `_.property` iteratee shorthand.
9924      * _.some(users, 'active');
9925      * // => true
9926      */
9927     function some(collection, predicate, guard) {
9928       var func = isArray(collection) ? arraySome : baseSome;
9929       if (guard && isIterateeCall(collection, predicate, guard)) {
9930         predicate = undefined;
9931       }
9932       return func(collection, getIteratee(predicate, 3));
9933     }
9934
9935     /**
9936      * Creates an array of elements, sorted in ascending order by the results of
9937      * running each element in a collection thru each iteratee. This method
9938      * performs a stable sort, that is, it preserves the original sort order of
9939      * equal elements. The iteratees are invoked with one argument: (value).
9940      *
9941      * @static
9942      * @memberOf _
9943      * @since 0.1.0
9944      * @category Collection
9945      * @param {Array|Object} collection The collection to iterate over.
9946      * @param {...(Function|Function[])} [iteratees=[_.identity]]
9947      *  The iteratees to sort by.
9948      * @returns {Array} Returns the new sorted array.
9949      * @example
9950      *
9951      * var users = [
9952      *   { 'user': 'fred',   'age': 48 },
9953      *   { 'user': 'barney', 'age': 36 },
9954      *   { 'user': 'fred',   'age': 40 },
9955      *   { 'user': 'barney', 'age': 34 }
9956      * ];
9957      *
9958      * _.sortBy(users, [function(o) { return o.user; }]);
9959      * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
9960      *
9961      * _.sortBy(users, ['user', 'age']);
9962      * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
9963      */
9964     var sortBy = baseRest(function(collection, iteratees) {
9965       if (collection == null) {
9966         return [];
9967       }
9968       var length = iteratees.length;
9969       if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
9970         iteratees = [];
9971       } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
9972         iteratees = [iteratees[0]];
9973       }
9974       return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
9975     });
9976
9977     /*------------------------------------------------------------------------*/
9978
9979     /**
9980      * Gets the timestamp of the number of milliseconds that have elapsed since
9981      * the Unix epoch (1 January 1970 00:00:00 UTC).
9982      *
9983      * @static
9984      * @memberOf _
9985      * @since 2.4.0
9986      * @category Date
9987      * @returns {number} Returns the timestamp.
9988      * @example
9989      *
9990      * _.defer(function(stamp) {
9991      *   console.log(_.now() - stamp);
9992      * }, _.now());
9993      * // => Logs the number of milliseconds it took for the deferred invocation.
9994      */
9995     var now = ctxNow || function() {
9996       return root.Date.now();
9997     };
9998
9999     /*------------------------------------------------------------------------*/
10000
10001     /**
10002      * The opposite of `_.before`; this method creates a function that invokes
10003      * `func` once it's called `n` or more times.
10004      *
10005      * @static
10006      * @memberOf _
10007      * @since 0.1.0
10008      * @category Function
10009      * @param {number} n The number of calls before `func` is invoked.
10010      * @param {Function} func The function to restrict.
10011      * @returns {Function} Returns the new restricted function.
10012      * @example
10013      *
10014      * var saves = ['profile', 'settings'];
10015      *
10016      * var done = _.after(saves.length, function() {
10017      *   console.log('done saving!');
10018      * });
10019      *
10020      * _.forEach(saves, function(type) {
10021      *   asyncSave({ 'type': type, 'complete': done });
10022      * });
10023      * // => Logs 'done saving!' after the two async saves have completed.
10024      */
10025     function after(n, func) {
10026       if (typeof func != 'function') {
10027         throw new TypeError(FUNC_ERROR_TEXT);
10028       }
10029       n = toInteger(n);
10030       return function() {
10031         if (--n < 1) {
10032           return func.apply(this, arguments);
10033         }
10034       };
10035     }
10036
10037     /**
10038      * Creates a function that invokes `func`, with up to `n` arguments,
10039      * ignoring any additional arguments.
10040      *
10041      * @static
10042      * @memberOf _
10043      * @since 3.0.0
10044      * @category Function
10045      * @param {Function} func The function to cap arguments for.
10046      * @param {number} [n=func.length] The arity cap.
10047      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10048      * @returns {Function} Returns the new capped function.
10049      * @example
10050      *
10051      * _.map(['6', '8', '10'], _.ary(parseInt, 1));
10052      * // => [6, 8, 10]
10053      */
10054     function ary(func, n, guard) {
10055       n = guard ? undefined : n;
10056       n = (func && n == null) ? func.length : n;
10057       return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
10058     }
10059
10060     /**
10061      * Creates a function that invokes `func`, with the `this` binding and arguments
10062      * of the created function, while it's called less than `n` times. Subsequent
10063      * calls to the created function return the result of the last `func` invocation.
10064      *
10065      * @static
10066      * @memberOf _
10067      * @since 3.0.0
10068      * @category Function
10069      * @param {number} n The number of calls at which `func` is no longer invoked.
10070      * @param {Function} func The function to restrict.
10071      * @returns {Function} Returns the new restricted function.
10072      * @example
10073      *
10074      * jQuery(element).on('click', _.before(5, addContactToList));
10075      * // => Allows adding up to 4 contacts to the list.
10076      */
10077     function before(n, func) {
10078       var result;
10079       if (typeof func != 'function') {
10080         throw new TypeError(FUNC_ERROR_TEXT);
10081       }
10082       n = toInteger(n);
10083       return function() {
10084         if (--n > 0) {
10085           result = func.apply(this, arguments);
10086         }
10087         if (n <= 1) {
10088           func = undefined;
10089         }
10090         return result;
10091       };
10092     }
10093
10094     /**
10095      * Creates a function that invokes `func` with the `this` binding of `thisArg`
10096      * and `partials` prepended to the arguments it receives.
10097      *
10098      * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
10099      * may be used as a placeholder for partially applied arguments.
10100      *
10101      * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
10102      * property of bound functions.
10103      *
10104      * @static
10105      * @memberOf _
10106      * @since 0.1.0
10107      * @category Function
10108      * @param {Function} func The function to bind.
10109      * @param {*} thisArg The `this` binding of `func`.
10110      * @param {...*} [partials] The arguments to be partially applied.
10111      * @returns {Function} Returns the new bound function.
10112      * @example
10113      *
10114      * function greet(greeting, punctuation) {
10115      *   return greeting + ' ' + this.user + punctuation;
10116      * }
10117      *
10118      * var object = { 'user': 'fred' };
10119      *
10120      * var bound = _.bind(greet, object, 'hi');
10121      * bound('!');
10122      * // => 'hi fred!'
10123      *
10124      * // Bound with placeholders.
10125      * var bound = _.bind(greet, object, _, '!');
10126      * bound('hi');
10127      * // => 'hi fred!'
10128      */
10129     var bind = baseRest(function(func, thisArg, partials) {
10130       var bitmask = WRAP_BIND_FLAG;
10131       if (partials.length) {
10132         var holders = replaceHolders(partials, getHolder(bind));
10133         bitmask |= WRAP_PARTIAL_FLAG;
10134       }
10135       return createWrap(func, bitmask, thisArg, partials, holders);
10136     });
10137
10138     /**
10139      * Creates a function that invokes the method at `object[key]` with `partials`
10140      * prepended to the arguments it receives.
10141      *
10142      * This method differs from `_.bind` by allowing bound functions to reference
10143      * methods that may be redefined or don't yet exist. See
10144      * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
10145      * for more details.
10146      *
10147      * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
10148      * builds, may be used as a placeholder for partially applied arguments.
10149      *
10150      * @static
10151      * @memberOf _
10152      * @since 0.10.0
10153      * @category Function
10154      * @param {Object} object The object to invoke the method on.
10155      * @param {string} key The key of the method.
10156      * @param {...*} [partials] The arguments to be partially applied.
10157      * @returns {Function} Returns the new bound function.
10158      * @example
10159      *
10160      * var object = {
10161      *   'user': 'fred',
10162      *   'greet': function(greeting, punctuation) {
10163      *     return greeting + ' ' + this.user + punctuation;
10164      *   }
10165      * };
10166      *
10167      * var bound = _.bindKey(object, 'greet', 'hi');
10168      * bound('!');
10169      * // => 'hi fred!'
10170      *
10171      * object.greet = function(greeting, punctuation) {
10172      *   return greeting + 'ya ' + this.user + punctuation;
10173      * };
10174      *
10175      * bound('!');
10176      * // => 'hiya fred!'
10177      *
10178      * // Bound with placeholders.
10179      * var bound = _.bindKey(object, 'greet', _, '!');
10180      * bound('hi');
10181      * // => 'hiya fred!'
10182      */
10183     var bindKey = baseRest(function(object, key, partials) {
10184       var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
10185       if (partials.length) {
10186         var holders = replaceHolders(partials, getHolder(bindKey));
10187         bitmask |= WRAP_PARTIAL_FLAG;
10188       }
10189       return createWrap(key, bitmask, object, partials, holders);
10190     });
10191
10192     /**
10193      * Creates a function that accepts arguments of `func` and either invokes
10194      * `func` returning its result, if at least `arity` number of arguments have
10195      * been provided, or returns a function that accepts the remaining `func`
10196      * arguments, and so on. The arity of `func` may be specified if `func.length`
10197      * is not sufficient.
10198      *
10199      * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
10200      * may be used as a placeholder for provided arguments.
10201      *
10202      * **Note:** This method doesn't set the "length" property of curried functions.
10203      *
10204      * @static
10205      * @memberOf _
10206      * @since 2.0.0
10207      * @category Function
10208      * @param {Function} func The function to curry.
10209      * @param {number} [arity=func.length] The arity of `func`.
10210      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10211      * @returns {Function} Returns the new curried function.
10212      * @example
10213      *
10214      * var abc = function(a, b, c) {
10215      *   return [a, b, c];
10216      * };
10217      *
10218      * var curried = _.curry(abc);
10219      *
10220      * curried(1)(2)(3);
10221      * // => [1, 2, 3]
10222      *
10223      * curried(1, 2)(3);
10224      * // => [1, 2, 3]
10225      *
10226      * curried(1, 2, 3);
10227      * // => [1, 2, 3]
10228      *
10229      * // Curried with placeholders.
10230      * curried(1)(_, 3)(2);
10231      * // => [1, 2, 3]
10232      */
10233     function curry(func, arity, guard) {
10234       arity = guard ? undefined : arity;
10235       var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
10236       result.placeholder = curry.placeholder;
10237       return result;
10238     }
10239
10240     /**
10241      * This method is like `_.curry` except that arguments are applied to `func`
10242      * in the manner of `_.partialRight` instead of `_.partial`.
10243      *
10244      * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
10245      * builds, may be used as a placeholder for provided arguments.
10246      *
10247      * **Note:** This method doesn't set the "length" property of curried functions.
10248      *
10249      * @static
10250      * @memberOf _
10251      * @since 3.0.0
10252      * @category Function
10253      * @param {Function} func The function to curry.
10254      * @param {number} [arity=func.length] The arity of `func`.
10255      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10256      * @returns {Function} Returns the new curried function.
10257      * @example
10258      *
10259      * var abc = function(a, b, c) {
10260      *   return [a, b, c];
10261      * };
10262      *
10263      * var curried = _.curryRight(abc);
10264      *
10265      * curried(3)(2)(1);
10266      * // => [1, 2, 3]
10267      *
10268      * curried(2, 3)(1);
10269      * // => [1, 2, 3]
10270      *
10271      * curried(1, 2, 3);
10272      * // => [1, 2, 3]
10273      *
10274      * // Curried with placeholders.
10275      * curried(3)(1, _)(2);
10276      * // => [1, 2, 3]
10277      */
10278     function curryRight(func, arity, guard) {
10279       arity = guard ? undefined : arity;
10280       var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
10281       result.placeholder = curryRight.placeholder;
10282       return result;
10283     }
10284
10285     /**
10286      * Creates a debounced function that delays invoking `func` until after `wait`
10287      * milliseconds have elapsed since the last time the debounced function was
10288      * invoked. The debounced function comes with a `cancel` method to cancel
10289      * delayed `func` invocations and a `flush` method to immediately invoke them.
10290      * Provide `options` to indicate whether `func` should be invoked on the
10291      * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
10292      * with the last arguments provided to the debounced function. Subsequent
10293      * calls to the debounced function return the result of the last `func`
10294      * invocation.
10295      *
10296      * **Note:** If `leading` and `trailing` options are `true`, `func` is
10297      * invoked on the trailing edge of the timeout only if the debounced function
10298      * is invoked more than once during the `wait` timeout.
10299      *
10300      * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
10301      * until to the next tick, similar to `setTimeout` with a timeout of `0`.
10302      *
10303      * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
10304      * for details over the differences between `_.debounce` and `_.throttle`.
10305      *
10306      * @static
10307      * @memberOf _
10308      * @since 0.1.0
10309      * @category Function
10310      * @param {Function} func The function to debounce.
10311      * @param {number} [wait=0] The number of milliseconds to delay.
10312      * @param {Object} [options={}] The options object.
10313      * @param {boolean} [options.leading=false]
10314      *  Specify invoking on the leading edge of the timeout.
10315      * @param {number} [options.maxWait]
10316      *  The maximum time `func` is allowed to be delayed before it's invoked.
10317      * @param {boolean} [options.trailing=true]
10318      *  Specify invoking on the trailing edge of the timeout.
10319      * @returns {Function} Returns the new debounced function.
10320      * @example
10321      *
10322      * // Avoid costly calculations while the window size is in flux.
10323      * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
10324      *
10325      * // Invoke `sendMail` when clicked, debouncing subsequent calls.
10326      * jQuery(element).on('click', _.debounce(sendMail, 300, {
10327      *   'leading': true,
10328      *   'trailing': false
10329      * }));
10330      *
10331      * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
10332      * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
10333      * var source = new EventSource('/stream');
10334      * jQuery(source).on('message', debounced);
10335      *
10336      * // Cancel the trailing debounced invocation.
10337      * jQuery(window).on('popstate', debounced.cancel);
10338      */
10339     function debounce(func, wait, options) {
10340       var lastArgs,
10341           lastThis,
10342           maxWait,
10343           result,
10344           timerId,
10345           lastCallTime,
10346           lastInvokeTime = 0,
10347           leading = false,
10348           maxing = false,
10349           trailing = true;
10350
10351       if (typeof func != 'function') {
10352         throw new TypeError(FUNC_ERROR_TEXT);
10353       }
10354       wait = toNumber(wait) || 0;
10355       if (isObject(options)) {
10356         leading = !!options.leading;
10357         maxing = 'maxWait' in options;
10358         maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
10359         trailing = 'trailing' in options ? !!options.trailing : trailing;
10360       }
10361
10362       function invokeFunc(time) {
10363         var args = lastArgs,
10364             thisArg = lastThis;
10365
10366         lastArgs = lastThis = undefined;
10367         lastInvokeTime = time;
10368         result = func.apply(thisArg, args);
10369         return result;
10370       }
10371
10372       function leadingEdge(time) {
10373         // Reset any `maxWait` timer.
10374         lastInvokeTime = time;
10375         // Start the timer for the trailing edge.
10376         timerId = setTimeout(timerExpired, wait);
10377         // Invoke the leading edge.
10378         return leading ? invokeFunc(time) : result;
10379       }
10380
10381       function remainingWait(time) {
10382         var timeSinceLastCall = time - lastCallTime,
10383             timeSinceLastInvoke = time - lastInvokeTime,
10384             result = wait - timeSinceLastCall;
10385
10386         return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
10387       }
10388
10389       function shouldInvoke(time) {
10390         var timeSinceLastCall = time - lastCallTime,
10391             timeSinceLastInvoke = time - lastInvokeTime;
10392
10393         // Either this is the first call, activity has stopped and we're at the
10394         // trailing edge, the system time has gone backwards and we're treating
10395         // it as the trailing edge, or we've hit the `maxWait` limit.
10396         return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
10397           (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
10398       }
10399
10400       function timerExpired() {
10401         var time = now();
10402         if (shouldInvoke(time)) {
10403           return trailingEdge(time);
10404         }
10405         // Restart the timer.
10406         timerId = setTimeout(timerExpired, remainingWait(time));
10407       }
10408
10409       function trailingEdge(time) {
10410         timerId = undefined;
10411
10412         // Only invoke if we have `lastArgs` which means `func` has been
10413         // debounced at least once.
10414         if (trailing && lastArgs) {
10415           return invokeFunc(time);
10416         }
10417         lastArgs = lastThis = undefined;
10418         return result;
10419       }
10420
10421       function cancel() {
10422         if (timerId !== undefined) {
10423           clearTimeout(timerId);
10424         }
10425         lastInvokeTime = 0;
10426         lastArgs = lastCallTime = lastThis = timerId = undefined;
10427       }
10428
10429       function flush() {
10430         return timerId === undefined ? result : trailingEdge(now());
10431       }
10432
10433       function debounced() {
10434         var time = now(),
10435             isInvoking = shouldInvoke(time);
10436
10437         lastArgs = arguments;
10438         lastThis = this;
10439         lastCallTime = time;
10440
10441         if (isInvoking) {
10442           if (timerId === undefined) {
10443             return leadingEdge(lastCallTime);
10444           }
10445           if (maxing) {
10446             // Handle invocations in a tight loop.
10447             timerId = setTimeout(timerExpired, wait);
10448             return invokeFunc(lastCallTime);
10449           }
10450         }
10451         if (timerId === undefined) {
10452           timerId = setTimeout(timerExpired, wait);
10453         }
10454         return result;
10455       }
10456       debounced.cancel = cancel;
10457       debounced.flush = flush;
10458       return debounced;
10459     }
10460
10461     /**
10462      * Defers invoking the `func` until the current call stack has cleared. Any
10463      * additional arguments are provided to `func` when it's invoked.
10464      *
10465      * @static
10466      * @memberOf _
10467      * @since 0.1.0
10468      * @category Function
10469      * @param {Function} func The function to defer.
10470      * @param {...*} [args] The arguments to invoke `func` with.
10471      * @returns {number} Returns the timer id.
10472      * @example
10473      *
10474      * _.defer(function(text) {
10475      *   console.log(text);
10476      * }, 'deferred');
10477      * // => Logs 'deferred' after one millisecond.
10478      */
10479     var defer = baseRest(function(func, args) {
10480       return baseDelay(func, 1, args);
10481     });
10482
10483     /**
10484      * Invokes `func` after `wait` milliseconds. Any additional arguments are
10485      * provided to `func` when it's invoked.
10486      *
10487      * @static
10488      * @memberOf _
10489      * @since 0.1.0
10490      * @category Function
10491      * @param {Function} func The function to delay.
10492      * @param {number} wait The number of milliseconds to delay invocation.
10493      * @param {...*} [args] The arguments to invoke `func` with.
10494      * @returns {number} Returns the timer id.
10495      * @example
10496      *
10497      * _.delay(function(text) {
10498      *   console.log(text);
10499      * }, 1000, 'later');
10500      * // => Logs 'later' after one second.
10501      */
10502     var delay = baseRest(function(func, wait, args) {
10503       return baseDelay(func, toNumber(wait) || 0, args);
10504     });
10505
10506     /**
10507      * Creates a function that invokes `func` with arguments reversed.
10508      *
10509      * @static
10510      * @memberOf _
10511      * @since 4.0.0
10512      * @category Function
10513      * @param {Function} func The function to flip arguments for.
10514      * @returns {Function} Returns the new flipped function.
10515      * @example
10516      *
10517      * var flipped = _.flip(function() {
10518      *   return _.toArray(arguments);
10519      * });
10520      *
10521      * flipped('a', 'b', 'c', 'd');
10522      * // => ['d', 'c', 'b', 'a']
10523      */
10524     function flip(func) {
10525       return createWrap(func, WRAP_FLIP_FLAG);
10526     }
10527
10528     /**
10529      * Creates a function that memoizes the result of `func`. If `resolver` is
10530      * provided, it determines the cache key for storing the result based on the
10531      * arguments provided to the memoized function. By default, the first argument
10532      * provided to the memoized function is used as the map cache key. The `func`
10533      * is invoked with the `this` binding of the memoized function.
10534      *
10535      * **Note:** The cache is exposed as the `cache` property on the memoized
10536      * function. Its creation may be customized by replacing the `_.memoize.Cache`
10537      * constructor with one whose instances implement the
10538      * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
10539      * method interface of `clear`, `delete`, `get`, `has`, and `set`.
10540      *
10541      * @static
10542      * @memberOf _
10543      * @since 0.1.0
10544      * @category Function
10545      * @param {Function} func The function to have its output memoized.
10546      * @param {Function} [resolver] The function to resolve the cache key.
10547      * @returns {Function} Returns the new memoized function.
10548      * @example
10549      *
10550      * var object = { 'a': 1, 'b': 2 };
10551      * var other = { 'c': 3, 'd': 4 };
10552      *
10553      * var values = _.memoize(_.values);
10554      * values(object);
10555      * // => [1, 2]
10556      *
10557      * values(other);
10558      * // => [3, 4]
10559      *
10560      * object.a = 2;
10561      * values(object);
10562      * // => [1, 2]
10563      *
10564      * // Modify the result cache.
10565      * values.cache.set(object, ['a', 'b']);
10566      * values(object);
10567      * // => ['a', 'b']
10568      *
10569      * // Replace `_.memoize.Cache`.
10570      * _.memoize.Cache = WeakMap;
10571      */
10572     function memoize(func, resolver) {
10573       if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
10574         throw new TypeError(FUNC_ERROR_TEXT);
10575       }
10576       var memoized = function() {
10577         var args = arguments,
10578             key = resolver ? resolver.apply(this, args) : args[0],
10579             cache = memoized.cache;
10580
10581         if (cache.has(key)) {
10582           return cache.get(key);
10583         }
10584         var result = func.apply(this, args);
10585         memoized.cache = cache.set(key, result) || cache;
10586         return result;
10587       };
10588       memoized.cache = new (memoize.Cache || MapCache);
10589       return memoized;
10590     }
10591
10592     // Expose `MapCache`.
10593     memoize.Cache = MapCache;
10594
10595     /**
10596      * Creates a function that negates the result of the predicate `func`. The
10597      * `func` predicate is invoked with the `this` binding and arguments of the
10598      * created function.
10599      *
10600      * @static
10601      * @memberOf _
10602      * @since 3.0.0
10603      * @category Function
10604      * @param {Function} predicate The predicate to negate.
10605      * @returns {Function} Returns the new negated function.
10606      * @example
10607      *
10608      * function isEven(n) {
10609      *   return n % 2 == 0;
10610      * }
10611      *
10612      * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
10613      * // => [1, 3, 5]
10614      */
10615     function negate(predicate) {
10616       if (typeof predicate != 'function') {
10617         throw new TypeError(FUNC_ERROR_TEXT);
10618       }
10619       return function() {
10620         var args = arguments;
10621         switch (args.length) {
10622           case 0: return !predicate.call(this);
10623           case 1: return !predicate.call(this, args[0]);
10624           case 2: return !predicate.call(this, args[0], args[1]);
10625           case 3: return !predicate.call(this, args[0], args[1], args[2]);
10626         }
10627         return !predicate.apply(this, args);
10628       };
10629     }
10630
10631     /**
10632      * Creates a function that is restricted to invoking `func` once. Repeat calls
10633      * to the function return the value of the first invocation. The `func` is
10634      * invoked with the `this` binding and arguments of the created function.
10635      *
10636      * @static
10637      * @memberOf _
10638      * @since 0.1.0
10639      * @category Function
10640      * @param {Function} func The function to restrict.
10641      * @returns {Function} Returns the new restricted function.
10642      * @example
10643      *
10644      * var initialize = _.once(createApplication);
10645      * initialize();
10646      * initialize();
10647      * // => `createApplication` is invoked once
10648      */
10649     function once(func) {
10650       return before(2, func);
10651     }
10652
10653     /**
10654      * Creates a function that invokes `func` with its arguments transformed.
10655      *
10656      * @static
10657      * @since 4.0.0
10658      * @memberOf _
10659      * @category Function
10660      * @param {Function} func The function to wrap.
10661      * @param {...(Function|Function[])} [transforms=[_.identity]]
10662      *  The argument transforms.
10663      * @returns {Function} Returns the new function.
10664      * @example
10665      *
10666      * function doubled(n) {
10667      *   return n * 2;
10668      * }
10669      *
10670      * function square(n) {
10671      *   return n * n;
10672      * }
10673      *
10674      * var func = _.overArgs(function(x, y) {
10675      *   return [x, y];
10676      * }, [square, doubled]);
10677      *
10678      * func(9, 3);
10679      * // => [81, 6]
10680      *
10681      * func(10, 5);
10682      * // => [100, 10]
10683      */
10684     var overArgs = castRest(function(func, transforms) {
10685       transforms = (transforms.length == 1 && isArray(transforms[0]))
10686         ? arrayMap(transforms[0], baseUnary(getIteratee()))
10687         : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));
10688
10689       var funcsLength = transforms.length;
10690       return baseRest(function(args) {
10691         var index = -1,
10692             length = nativeMin(args.length, funcsLength);
10693
10694         while (++index < length) {
10695           args[index] = transforms[index].call(this, args[index]);
10696         }
10697         return apply(func, this, args);
10698       });
10699     });
10700
10701     /**
10702      * Creates a function that invokes `func` with `partials` prepended to the
10703      * arguments it receives. This method is like `_.bind` except it does **not**
10704      * alter the `this` binding.
10705      *
10706      * The `_.partial.placeholder` value, which defaults to `_` in monolithic
10707      * builds, may be used as a placeholder for partially applied arguments.
10708      *
10709      * **Note:** This method doesn't set the "length" property of partially
10710      * applied functions.
10711      *
10712      * @static
10713      * @memberOf _
10714      * @since 0.2.0
10715      * @category Function
10716      * @param {Function} func The function to partially apply arguments to.
10717      * @param {...*} [partials] The arguments to be partially applied.
10718      * @returns {Function} Returns the new partially applied function.
10719      * @example
10720      *
10721      * function greet(greeting, name) {
10722      *   return greeting + ' ' + name;
10723      * }
10724      *
10725      * var sayHelloTo = _.partial(greet, 'hello');
10726      * sayHelloTo('fred');
10727      * // => 'hello fred'
10728      *
10729      * // Partially applied with placeholders.
10730      * var greetFred = _.partial(greet, _, 'fred');
10731      * greetFred('hi');
10732      * // => 'hi fred'
10733      */
10734     var partial = baseRest(function(func, partials) {
10735       var holders = replaceHolders(partials, getHolder(partial));
10736       return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
10737     });
10738
10739     /**
10740      * This method is like `_.partial` except that partially applied arguments
10741      * are appended to the arguments it receives.
10742      *
10743      * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
10744      * builds, may be used as a placeholder for partially applied arguments.
10745      *
10746      * **Note:** This method doesn't set the "length" property of partially
10747      * applied functions.
10748      *
10749      * @static
10750      * @memberOf _
10751      * @since 1.0.0
10752      * @category Function
10753      * @param {Function} func The function to partially apply arguments to.
10754      * @param {...*} [partials] The arguments to be partially applied.
10755      * @returns {Function} Returns the new partially applied function.
10756      * @example
10757      *
10758      * function greet(greeting, name) {
10759      *   return greeting + ' ' + name;
10760      * }
10761      *
10762      * var greetFred = _.partialRight(greet, 'fred');
10763      * greetFred('hi');
10764      * // => 'hi fred'
10765      *
10766      * // Partially applied with placeholders.
10767      * var sayHelloTo = _.partialRight(greet, 'hello', _);
10768      * sayHelloTo('fred');
10769      * // => 'hello fred'
10770      */
10771     var partialRight = baseRest(function(func, partials) {
10772       var holders = replaceHolders(partials, getHolder(partialRight));
10773       return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
10774     });
10775
10776     /**
10777      * Creates a function that invokes `func` with arguments arranged according
10778      * to the specified `indexes` where the argument value at the first index is
10779      * provided as the first argument, the argument value at the second index is
10780      * provided as the second argument, and so on.
10781      *
10782      * @static
10783      * @memberOf _
10784      * @since 3.0.0
10785      * @category Function
10786      * @param {Function} func The function to rearrange arguments for.
10787      * @param {...(number|number[])} indexes The arranged argument indexes.
10788      * @returns {Function} Returns the new function.
10789      * @example
10790      *
10791      * var rearged = _.rearg(function(a, b, c) {
10792      *   return [a, b, c];
10793      * }, [2, 0, 1]);
10794      *
10795      * rearged('b', 'c', 'a')
10796      * // => ['a', 'b', 'c']
10797      */
10798     var rearg = flatRest(function(func, indexes) {
10799       return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
10800     });
10801
10802     /**
10803      * Creates a function that invokes `func` with the `this` binding of the
10804      * created function and arguments from `start` and beyond provided as
10805      * an array.
10806      *
10807      * **Note:** This method is based on the
10808      * [rest parameter](https://mdn.io/rest_parameters).
10809      *
10810      * @static
10811      * @memberOf _
10812      * @since 4.0.0
10813      * @category Function
10814      * @param {Function} func The function to apply a rest parameter to.
10815      * @param {number} [start=func.length-1] The start position of the rest parameter.
10816      * @returns {Function} Returns the new function.
10817      * @example
10818      *
10819      * var say = _.rest(function(what, names) {
10820      *   return what + ' ' + _.initial(names).join(', ') +
10821      *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
10822      * });
10823      *
10824      * say('hello', 'fred', 'barney', 'pebbles');
10825      * // => 'hello fred, barney, & pebbles'
10826      */
10827     function rest(func, start) {
10828       if (typeof func != 'function') {
10829         throw new TypeError(FUNC_ERROR_TEXT);
10830       }
10831       start = start === undefined ? start : toInteger(start);
10832       return baseRest(func, start);
10833     }
10834
10835     /**
10836      * Creates a function that invokes `func` with the `this` binding of the
10837      * create function and an array of arguments much like
10838      * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
10839      *
10840      * **Note:** This method is based on the
10841      * [spread operator](https://mdn.io/spread_operator).
10842      *
10843      * @static
10844      * @memberOf _
10845      * @since 3.2.0
10846      * @category Function
10847      * @param {Function} func The function to spread arguments over.
10848      * @param {number} [start=0] The start position of the spread.
10849      * @returns {Function} Returns the new function.
10850      * @example
10851      *
10852      * var say = _.spread(function(who, what) {
10853      *   return who + ' says ' + what;
10854      * });
10855      *
10856      * say(['fred', 'hello']);
10857      * // => 'fred says hello'
10858      *
10859      * var numbers = Promise.all([
10860      *   Promise.resolve(40),
10861      *   Promise.resolve(36)
10862      * ]);
10863      *
10864      * numbers.then(_.spread(function(x, y) {
10865      *   return x + y;
10866      * }));
10867      * // => a Promise of 76
10868      */
10869     function spread(func, start) {
10870       if (typeof func != 'function') {
10871         throw new TypeError(FUNC_ERROR_TEXT);
10872       }
10873       start = start == null ? 0 : nativeMax(toInteger(start), 0);
10874       return baseRest(function(args) {
10875         var array = args[start],
10876             otherArgs = castSlice(args, 0, start);
10877
10878         if (array) {
10879           arrayPush(otherArgs, array);
10880         }
10881         return apply(func, this, otherArgs);
10882       });
10883     }
10884
10885     /**
10886      * Creates a throttled function that only invokes `func` at most once per
10887      * every `wait` milliseconds. The throttled function comes with a `cancel`
10888      * method to cancel delayed `func` invocations and a `flush` method to
10889      * immediately invoke them. Provide `options` to indicate whether `func`
10890      * should be invoked on the leading and/or trailing edge of the `wait`
10891      * timeout. The `func` is invoked with the last arguments provided to the
10892      * throttled function. Subsequent calls to the throttled function return the
10893      * result of the last `func` invocation.
10894      *
10895      * **Note:** If `leading` and `trailing` options are `true`, `func` is
10896      * invoked on the trailing edge of the timeout only if the throttled function
10897      * is invoked more than once during the `wait` timeout.
10898      *
10899      * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
10900      * until to the next tick, similar to `setTimeout` with a timeout of `0`.
10901      *
10902      * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
10903      * for details over the differences between `_.throttle` and `_.debounce`.
10904      *
10905      * @static
10906      * @memberOf _
10907      * @since 0.1.0
10908      * @category Function
10909      * @param {Function} func The function to throttle.
10910      * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
10911      * @param {Object} [options={}] The options object.
10912      * @param {boolean} [options.leading=true]
10913      *  Specify invoking on the leading edge of the timeout.
10914      * @param {boolean} [options.trailing=true]
10915      *  Specify invoking on the trailing edge of the timeout.
10916      * @returns {Function} Returns the new throttled function.
10917      * @example
10918      *
10919      * // Avoid excessively updating the position while scrolling.
10920      * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
10921      *
10922      * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
10923      * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
10924      * jQuery(element).on('click', throttled);
10925      *
10926      * // Cancel the trailing throttled invocation.
10927      * jQuery(window).on('popstate', throttled.cancel);
10928      */
10929     function throttle(func, wait, options) {
10930       var leading = true,
10931           trailing = true;
10932
10933       if (typeof func != 'function') {
10934         throw new TypeError(FUNC_ERROR_TEXT);
10935       }
10936       if (isObject(options)) {
10937         leading = 'leading' in options ? !!options.leading : leading;
10938         trailing = 'trailing' in options ? !!options.trailing : trailing;
10939       }
10940       return debounce(func, wait, {
10941         'leading': leading,
10942         'maxWait': wait,
10943         'trailing': trailing
10944       });
10945     }
10946
10947     /**
10948      * Creates a function that accepts up to one argument, ignoring any
10949      * additional arguments.
10950      *
10951      * @static
10952      * @memberOf _
10953      * @since 4.0.0
10954      * @category Function
10955      * @param {Function} func The function to cap arguments for.
10956      * @returns {Function} Returns the new capped function.
10957      * @example
10958      *
10959      * _.map(['6', '8', '10'], _.unary(parseInt));
10960      * // => [6, 8, 10]
10961      */
10962     function unary(func) {
10963       return ary(func, 1);
10964     }
10965
10966     /**
10967      * Creates a function that provides `value` to `wrapper` as its first
10968      * argument. Any additional arguments provided to the function are appended
10969      * to those provided to the `wrapper`. The wrapper is invoked with the `this`
10970      * binding of the created function.
10971      *
10972      * @static
10973      * @memberOf _
10974      * @since 0.1.0
10975      * @category Function
10976      * @param {*} value The value to wrap.
10977      * @param {Function} [wrapper=identity] The wrapper function.
10978      * @returns {Function} Returns the new function.
10979      * @example
10980      *
10981      * var p = _.wrap(_.escape, function(func, text) {
10982      *   return '<p>' + func(text) + '</p>';
10983      * });
10984      *
10985      * p('fred, barney, & pebbles');
10986      * // => '<p>fred, barney, &amp; pebbles</p>'
10987      */
10988     function wrap(value, wrapper) {
10989       return partial(castFunction(wrapper), value);
10990     }
10991
10992     /*------------------------------------------------------------------------*/
10993
10994     /**
10995      * Casts `value` as an array if it's not one.
10996      *
10997      * @static
10998      * @memberOf _
10999      * @since 4.4.0
11000      * @category Lang
11001      * @param {*} value The value to inspect.
11002      * @returns {Array} Returns the cast array.
11003      * @example
11004      *
11005      * _.castArray(1);
11006      * // => [1]
11007      *
11008      * _.castArray({ 'a': 1 });
11009      * // => [{ 'a': 1 }]
11010      *
11011      * _.castArray('abc');
11012      * // => ['abc']
11013      *
11014      * _.castArray(null);
11015      * // => [null]
11016      *
11017      * _.castArray(undefined);
11018      * // => [undefined]
11019      *
11020      * _.castArray();
11021      * // => []
11022      *
11023      * var array = [1, 2, 3];
11024      * console.log(_.castArray(array) === array);
11025      * // => true
11026      */
11027     function castArray() {
11028       if (!arguments.length) {
11029         return [];
11030       }
11031       var value = arguments[0];
11032       return isArray(value) ? value : [value];
11033     }
11034
11035     /**
11036      * Creates a shallow clone of `value`.
11037      *
11038      * **Note:** This method is loosely based on the
11039      * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
11040      * and supports cloning arrays, array buffers, booleans, date objects, maps,
11041      * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
11042      * arrays. The own enumerable properties of `arguments` objects are cloned
11043      * as plain objects. An empty object is returned for uncloneable values such
11044      * as error objects, functions, DOM nodes, and WeakMaps.
11045      *
11046      * @static
11047      * @memberOf _
11048      * @since 0.1.0
11049      * @category Lang
11050      * @param {*} value The value to clone.
11051      * @returns {*} Returns the cloned value.
11052      * @see _.cloneDeep
11053      * @example
11054      *
11055      * var objects = [{ 'a': 1 }, { 'b': 2 }];
11056      *
11057      * var shallow = _.clone(objects);
11058      * console.log(shallow[0] === objects[0]);
11059      * // => true
11060      */
11061     function clone(value) {
11062       return baseClone(value, CLONE_SYMBOLS_FLAG);
11063     }
11064
11065     /**
11066      * This method is like `_.clone` except that it accepts `customizer` which
11067      * is invoked to produce the cloned value. If `customizer` returns `undefined`,
11068      * cloning is handled by the method instead. The `customizer` is invoked with
11069      * up to four arguments; (value [, index|key, object, stack]).
11070      *
11071      * @static
11072      * @memberOf _
11073      * @since 4.0.0
11074      * @category Lang
11075      * @param {*} value The value to clone.
11076      * @param {Function} [customizer] The function to customize cloning.
11077      * @returns {*} Returns the cloned value.
11078      * @see _.cloneDeepWith
11079      * @example
11080      *
11081      * function customizer(value) {
11082      *   if (_.isElement(value)) {
11083      *     return value.cloneNode(false);
11084      *   }
11085      * }
11086      *
11087      * var el = _.cloneWith(document.body, customizer);
11088      *
11089      * console.log(el === document.body);
11090      * // => false
11091      * console.log(el.nodeName);
11092      * // => 'BODY'
11093      * console.log(el.childNodes.length);
11094      * // => 0
11095      */
11096     function cloneWith(value, customizer) {
11097       customizer = typeof customizer == 'function' ? customizer : undefined;
11098       return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);
11099     }
11100
11101     /**
11102      * This method is like `_.clone` except that it recursively clones `value`.
11103      *
11104      * @static
11105      * @memberOf _
11106      * @since 1.0.0
11107      * @category Lang
11108      * @param {*} value The value to recursively clone.
11109      * @returns {*} Returns the deep cloned value.
11110      * @see _.clone
11111      * @example
11112      *
11113      * var objects = [{ 'a': 1 }, { 'b': 2 }];
11114      *
11115      * var deep = _.cloneDeep(objects);
11116      * console.log(deep[0] === objects[0]);
11117      * // => false
11118      */
11119     function cloneDeep(value) {
11120       return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
11121     }
11122
11123     /**
11124      * This method is like `_.cloneWith` except that it recursively clones `value`.
11125      *
11126      * @static
11127      * @memberOf _
11128      * @since 4.0.0
11129      * @category Lang
11130      * @param {*} value The value to recursively clone.
11131      * @param {Function} [customizer] The function to customize cloning.
11132      * @returns {*} Returns the deep cloned value.
11133      * @see _.cloneWith
11134      * @example
11135      *
11136      * function customizer(value) {
11137      *   if (_.isElement(value)) {
11138      *     return value.cloneNode(true);
11139      *   }
11140      * }
11141      *
11142      * var el = _.cloneDeepWith(document.body, customizer);
11143      *
11144      * console.log(el === document.body);
11145      * // => false
11146      * console.log(el.nodeName);
11147      * // => 'BODY'
11148      * console.log(el.childNodes.length);
11149      * // => 20
11150      */
11151     function cloneDeepWith(value, customizer) {
11152       customizer = typeof customizer == 'function' ? customizer : undefined;
11153       return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
11154     }
11155
11156     /**
11157      * Checks if `object` conforms to `source` by invoking the predicate
11158      * properties of `source` with the corresponding property values of `object`.
11159      *
11160      * **Note:** This method is equivalent to `_.conforms` when `source` is
11161      * partially applied.
11162      *
11163      * @static
11164      * @memberOf _
11165      * @since 4.14.0
11166      * @category Lang
11167      * @param {Object} object The object to inspect.
11168      * @param {Object} source The object of property predicates to conform to.
11169      * @returns {boolean} Returns `true` if `object` conforms, else `false`.
11170      * @example
11171      *
11172      * var object = { 'a': 1, 'b': 2 };
11173      *
11174      * _.conformsTo(object, { 'b': function(n) { return n > 1; } });
11175      * // => true
11176      *
11177      * _.conformsTo(object, { 'b': function(n) { return n > 2; } });
11178      * // => false
11179      */
11180     function conformsTo(object, source) {
11181       return source == null || baseConformsTo(object, source, keys(source));
11182     }
11183
11184     /**
11185      * Performs a
11186      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
11187      * comparison between two values to determine if they are equivalent.
11188      *
11189      * @static
11190      * @memberOf _
11191      * @since 4.0.0
11192      * @category Lang
11193      * @param {*} value The value to compare.
11194      * @param {*} other The other value to compare.
11195      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11196      * @example
11197      *
11198      * var object = { 'a': 1 };
11199      * var other = { 'a': 1 };
11200      *
11201      * _.eq(object, object);
11202      * // => true
11203      *
11204      * _.eq(object, other);
11205      * // => false
11206      *
11207      * _.eq('a', 'a');
11208      * // => true
11209      *
11210      * _.eq('a', Object('a'));
11211      * // => false
11212      *
11213      * _.eq(NaN, NaN);
11214      * // => true
11215      */
11216     function eq(value, other) {
11217       return value === other || (value !== value && other !== other);
11218     }
11219
11220     /**
11221      * Checks if `value` is greater than `other`.
11222      *
11223      * @static
11224      * @memberOf _
11225      * @since 3.9.0
11226      * @category Lang
11227      * @param {*} value The value to compare.
11228      * @param {*} other The other value to compare.
11229      * @returns {boolean} Returns `true` if `value` is greater than `other`,
11230      *  else `false`.
11231      * @see _.lt
11232      * @example
11233      *
11234      * _.gt(3, 1);
11235      * // => true
11236      *
11237      * _.gt(3, 3);
11238      * // => false
11239      *
11240      * _.gt(1, 3);
11241      * // => false
11242      */
11243     var gt = createRelationalOperation(baseGt);
11244
11245     /**
11246      * Checks if `value` is greater than or equal to `other`.
11247      *
11248      * @static
11249      * @memberOf _
11250      * @since 3.9.0
11251      * @category Lang
11252      * @param {*} value The value to compare.
11253      * @param {*} other The other value to compare.
11254      * @returns {boolean} Returns `true` if `value` is greater than or equal to
11255      *  `other`, else `false`.
11256      * @see _.lte
11257      * @example
11258      *
11259      * _.gte(3, 1);
11260      * // => true
11261      *
11262      * _.gte(3, 3);
11263      * // => true
11264      *
11265      * _.gte(1, 3);
11266      * // => false
11267      */
11268     var gte = createRelationalOperation(function(value, other) {
11269       return value >= other;
11270     });
11271
11272     /**
11273      * Checks if `value` is likely an `arguments` object.
11274      *
11275      * @static
11276      * @memberOf _
11277      * @since 0.1.0
11278      * @category Lang
11279      * @param {*} value The value to check.
11280      * @returns {boolean} Returns `true` if `value` is an `arguments` object,
11281      *  else `false`.
11282      * @example
11283      *
11284      * _.isArguments(function() { return arguments; }());
11285      * // => true
11286      *
11287      * _.isArguments([1, 2, 3]);
11288      * // => false
11289      */
11290     var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
11291       return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
11292         !propertyIsEnumerable.call(value, 'callee');
11293     };
11294
11295     /**
11296      * Checks if `value` is classified as an `Array` object.
11297      *
11298      * @static
11299      * @memberOf _
11300      * @since 0.1.0
11301      * @category Lang
11302      * @param {*} value The value to check.
11303      * @returns {boolean} Returns `true` if `value` is an array, else `false`.
11304      * @example
11305      *
11306      * _.isArray([1, 2, 3]);
11307      * // => true
11308      *
11309      * _.isArray(document.body.children);
11310      * // => false
11311      *
11312      * _.isArray('abc');
11313      * // => false
11314      *
11315      * _.isArray(_.noop);
11316      * // => false
11317      */
11318     var isArray = Array.isArray;
11319
11320     /**
11321      * Checks if `value` is classified as an `ArrayBuffer` object.
11322      *
11323      * @static
11324      * @memberOf _
11325      * @since 4.3.0
11326      * @category Lang
11327      * @param {*} value The value to check.
11328      * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
11329      * @example
11330      *
11331      * _.isArrayBuffer(new ArrayBuffer(2));
11332      * // => true
11333      *
11334      * _.isArrayBuffer(new Array(2));
11335      * // => false
11336      */
11337     var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;
11338
11339     /**
11340      * Checks if `value` is array-like. A value is considered array-like if it's
11341      * not a function and has a `value.length` that's an integer greater than or
11342      * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
11343      *
11344      * @static
11345      * @memberOf _
11346      * @since 4.0.0
11347      * @category Lang
11348      * @param {*} value The value to check.
11349      * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
11350      * @example
11351      *
11352      * _.isArrayLike([1, 2, 3]);
11353      * // => true
11354      *
11355      * _.isArrayLike(document.body.children);
11356      * // => true
11357      *
11358      * _.isArrayLike('abc');
11359      * // => true
11360      *
11361      * _.isArrayLike(_.noop);
11362      * // => false
11363      */
11364     function isArrayLike(value) {
11365       return value != null && isLength(value.length) && !isFunction(value);
11366     }
11367
11368     /**
11369      * This method is like `_.isArrayLike` except that it also checks if `value`
11370      * is an object.
11371      *
11372      * @static
11373      * @memberOf _
11374      * @since 4.0.0
11375      * @category Lang
11376      * @param {*} value The value to check.
11377      * @returns {boolean} Returns `true` if `value` is an array-like object,
11378      *  else `false`.
11379      * @example
11380      *
11381      * _.isArrayLikeObject([1, 2, 3]);
11382      * // => true
11383      *
11384      * _.isArrayLikeObject(document.body.children);
11385      * // => true
11386      *
11387      * _.isArrayLikeObject('abc');
11388      * // => false
11389      *
11390      * _.isArrayLikeObject(_.noop);
11391      * // => false
11392      */
11393     function isArrayLikeObject(value) {
11394       return isObjectLike(value) && isArrayLike(value);
11395     }
11396
11397     /**
11398      * Checks if `value` is classified as a boolean primitive or object.
11399      *
11400      * @static
11401      * @memberOf _
11402      * @since 0.1.0
11403      * @category Lang
11404      * @param {*} value The value to check.
11405      * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
11406      * @example
11407      *
11408      * _.isBoolean(false);
11409      * // => true
11410      *
11411      * _.isBoolean(null);
11412      * // => false
11413      */
11414     function isBoolean(value) {
11415       return value === true || value === false ||
11416         (isObjectLike(value) && baseGetTag(value) == boolTag);
11417     }
11418
11419     /**
11420      * Checks if `value` is a buffer.
11421      *
11422      * @static
11423      * @memberOf _
11424      * @since 4.3.0
11425      * @category Lang
11426      * @param {*} value The value to check.
11427      * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
11428      * @example
11429      *
11430      * _.isBuffer(new Buffer(2));
11431      * // => true
11432      *
11433      * _.isBuffer(new Uint8Array(2));
11434      * // => false
11435      */
11436     var isBuffer = nativeIsBuffer || stubFalse;
11437
11438     /**
11439      * Checks if `value` is classified as a `Date` object.
11440      *
11441      * @static
11442      * @memberOf _
11443      * @since 0.1.0
11444      * @category Lang
11445      * @param {*} value The value to check.
11446      * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
11447      * @example
11448      *
11449      * _.isDate(new Date);
11450      * // => true
11451      *
11452      * _.isDate('Mon April 23 2012');
11453      * // => false
11454      */
11455     var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
11456
11457     /**
11458      * Checks if `value` is likely a DOM element.
11459      *
11460      * @static
11461      * @memberOf _
11462      * @since 0.1.0
11463      * @category Lang
11464      * @param {*} value The value to check.
11465      * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
11466      * @example
11467      *
11468      * _.isElement(document.body);
11469      * // => true
11470      *
11471      * _.isElement('<body>');
11472      * // => false
11473      */
11474     function isElement(value) {
11475       return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
11476     }
11477
11478     /**
11479      * Checks if `value` is an empty object, collection, map, or set.
11480      *
11481      * Objects are considered empty if they have no own enumerable string keyed
11482      * properties.
11483      *
11484      * Array-like values such as `arguments` objects, arrays, buffers, strings, or
11485      * jQuery-like collections are considered empty if they have a `length` of `0`.
11486      * Similarly, maps and sets are considered empty if they have a `size` of `0`.
11487      *
11488      * @static
11489      * @memberOf _
11490      * @since 0.1.0
11491      * @category Lang
11492      * @param {*} value The value to check.
11493      * @returns {boolean} Returns `true` if `value` is empty, else `false`.
11494      * @example
11495      *
11496      * _.isEmpty(null);
11497      * // => true
11498      *
11499      * _.isEmpty(true);
11500      * // => true
11501      *
11502      * _.isEmpty(1);
11503      * // => true
11504      *
11505      * _.isEmpty([1, 2, 3]);
11506      * // => false
11507      *
11508      * _.isEmpty({ 'a': 1 });
11509      * // => false
11510      */
11511     function isEmpty(value) {
11512       if (value == null) {
11513         return true;
11514       }
11515       if (isArrayLike(value) &&
11516           (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
11517             isBuffer(value) || isTypedArray(value) || isArguments(value))) {
11518         return !value.length;
11519       }
11520       var tag = getTag(value);
11521       if (tag == mapTag || tag == setTag) {
11522         return !value.size;
11523       }
11524       if (isPrototype(value)) {
11525         return !baseKeys(value).length;
11526       }
11527       for (var key in value) {
11528         if (hasOwnProperty.call(value, key)) {
11529           return false;
11530         }
11531       }
11532       return true;
11533     }
11534
11535     /**
11536      * Performs a deep comparison between two values to determine if they are
11537      * equivalent.
11538      *
11539      * **Note:** This method supports comparing arrays, array buffers, booleans,
11540      * date objects, error objects, maps, numbers, `Object` objects, regexes,
11541      * sets, strings, symbols, and typed arrays. `Object` objects are compared
11542      * by their own, not inherited, enumerable properties. Functions and DOM
11543      * nodes are compared by strict equality, i.e. `===`.
11544      *
11545      * @static
11546      * @memberOf _
11547      * @since 0.1.0
11548      * @category Lang
11549      * @param {*} value The value to compare.
11550      * @param {*} other The other value to compare.
11551      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11552      * @example
11553      *
11554      * var object = { 'a': 1 };
11555      * var other = { 'a': 1 };
11556      *
11557      * _.isEqual(object, other);
11558      * // => true
11559      *
11560      * object === other;
11561      * // => false
11562      */
11563     function isEqual(value, other) {
11564       return baseIsEqual(value, other);
11565     }
11566
11567     /**
11568      * This method is like `_.isEqual` except that it accepts `customizer` which
11569      * is invoked to compare values. If `customizer` returns `undefined`, comparisons
11570      * are handled by the method instead. The `customizer` is invoked with up to
11571      * six arguments: (objValue, othValue [, index|key, object, other, stack]).
11572      *
11573      * @static
11574      * @memberOf _
11575      * @since 4.0.0
11576      * @category Lang
11577      * @param {*} value The value to compare.
11578      * @param {*} other The other value to compare.
11579      * @param {Function} [customizer] The function to customize comparisons.
11580      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11581      * @example
11582      *
11583      * function isGreeting(value) {
11584      *   return /^h(?:i|ello)$/.test(value);
11585      * }
11586      *
11587      * function customizer(objValue, othValue) {
11588      *   if (isGreeting(objValue) && isGreeting(othValue)) {
11589      *     return true;
11590      *   }
11591      * }
11592      *
11593      * var array = ['hello', 'goodbye'];
11594      * var other = ['hi', 'goodbye'];
11595      *
11596      * _.isEqualWith(array, other, customizer);
11597      * // => true
11598      */
11599     function isEqualWith(value, other, customizer) {
11600       customizer = typeof customizer == 'function' ? customizer : undefined;
11601       var result = customizer ? customizer(value, other) : undefined;
11602       return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;
11603     }
11604
11605     /**
11606      * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
11607      * `SyntaxError`, `TypeError`, or `URIError` object.
11608      *
11609      * @static
11610      * @memberOf _
11611      * @since 3.0.0
11612      * @category Lang
11613      * @param {*} value The value to check.
11614      * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
11615      * @example
11616      *
11617      * _.isError(new Error);
11618      * // => true
11619      *
11620      * _.isError(Error);
11621      * // => false
11622      */
11623     function isError(value) {
11624       if (!isObjectLike(value)) {
11625         return false;
11626       }
11627       var tag = baseGetTag(value);
11628       return tag == errorTag || tag == domExcTag ||
11629         (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));
11630     }
11631
11632     /**
11633      * Checks if `value` is a finite primitive number.
11634      *
11635      * **Note:** This method is based on
11636      * [`Number.isFinite`](https://mdn.io/Number/isFinite).
11637      *
11638      * @static
11639      * @memberOf _
11640      * @since 0.1.0
11641      * @category Lang
11642      * @param {*} value The value to check.
11643      * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
11644      * @example
11645      *
11646      * _.isFinite(3);
11647      * // => true
11648      *
11649      * _.isFinite(Number.MIN_VALUE);
11650      * // => true
11651      *
11652      * _.isFinite(Infinity);
11653      * // => false
11654      *
11655      * _.isFinite('3');
11656      * // => false
11657      */
11658     function isFinite(value) {
11659       return typeof value == 'number' && nativeIsFinite(value);
11660     }
11661
11662     /**
11663      * Checks if `value` is classified as a `Function` object.
11664      *
11665      * @static
11666      * @memberOf _
11667      * @since 0.1.0
11668      * @category Lang
11669      * @param {*} value The value to check.
11670      * @returns {boolean} Returns `true` if `value` is a function, else `false`.
11671      * @example
11672      *
11673      * _.isFunction(_);
11674      * // => true
11675      *
11676      * _.isFunction(/abc/);
11677      * // => false
11678      */
11679     function isFunction(value) {
11680       if (!isObject(value)) {
11681         return false;
11682       }
11683       // The use of `Object#toString` avoids issues with the `typeof` operator
11684       // in Safari 9 which returns 'object' for typed arrays and other constructors.
11685       var tag = baseGetTag(value);
11686       return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
11687     }
11688
11689     /**
11690      * Checks if `value` is an integer.
11691      *
11692      * **Note:** This method is based on
11693      * [`Number.isInteger`](https://mdn.io/Number/isInteger).
11694      *
11695      * @static
11696      * @memberOf _
11697      * @since 4.0.0
11698      * @category Lang
11699      * @param {*} value The value to check.
11700      * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
11701      * @example
11702      *
11703      * _.isInteger(3);
11704      * // => true
11705      *
11706      * _.isInteger(Number.MIN_VALUE);
11707      * // => false
11708      *
11709      * _.isInteger(Infinity);
11710      * // => false
11711      *
11712      * _.isInteger('3');
11713      * // => false
11714      */
11715     function isInteger(value) {
11716       return typeof value == 'number' && value == toInteger(value);
11717     }
11718
11719     /**
11720      * Checks if `value` is a valid array-like length.
11721      *
11722      * **Note:** This method is loosely based on
11723      * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
11724      *
11725      * @static
11726      * @memberOf _
11727      * @since 4.0.0
11728      * @category Lang
11729      * @param {*} value The value to check.
11730      * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
11731      * @example
11732      *
11733      * _.isLength(3);
11734      * // => true
11735      *
11736      * _.isLength(Number.MIN_VALUE);
11737      * // => false
11738      *
11739      * _.isLength(Infinity);
11740      * // => false
11741      *
11742      * _.isLength('3');
11743      * // => false
11744      */
11745     function isLength(value) {
11746       return typeof value == 'number' &&
11747         value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
11748     }
11749
11750     /**
11751      * Checks if `value` is the
11752      * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
11753      * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
11754      *
11755      * @static
11756      * @memberOf _
11757      * @since 0.1.0
11758      * @category Lang
11759      * @param {*} value The value to check.
11760      * @returns {boolean} Returns `true` if `value` is an object, else `false`.
11761      * @example
11762      *
11763      * _.isObject({});
11764      * // => true
11765      *
11766      * _.isObject([1, 2, 3]);
11767      * // => true
11768      *
11769      * _.isObject(_.noop);
11770      * // => true
11771      *
11772      * _.isObject(null);
11773      * // => false
11774      */
11775     function isObject(value) {
11776       var type = typeof value;
11777       return value != null && (type == 'object' || type == 'function');
11778     }
11779
11780     /**
11781      * Checks if `value` is object-like. A value is object-like if it's not `null`
11782      * and has a `typeof` result of "object".
11783      *
11784      * @static
11785      * @memberOf _
11786      * @since 4.0.0
11787      * @category Lang
11788      * @param {*} value The value to check.
11789      * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
11790      * @example
11791      *
11792      * _.isObjectLike({});
11793      * // => true
11794      *
11795      * _.isObjectLike([1, 2, 3]);
11796      * // => true
11797      *
11798      * _.isObjectLike(_.noop);
11799      * // => false
11800      *
11801      * _.isObjectLike(null);
11802      * // => false
11803      */
11804     function isObjectLike(value) {
11805       return value != null && typeof value == 'object';
11806     }
11807
11808     /**
11809      * Checks if `value` is classified as a `Map` object.
11810      *
11811      * @static
11812      * @memberOf _
11813      * @since 4.3.0
11814      * @category Lang
11815      * @param {*} value The value to check.
11816      * @returns {boolean} Returns `true` if `value` is a map, else `false`.
11817      * @example
11818      *
11819      * _.isMap(new Map);
11820      * // => true
11821      *
11822      * _.isMap(new WeakMap);
11823      * // => false
11824      */
11825     var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;
11826
11827     /**
11828      * Performs a partial deep comparison between `object` and `source` to
11829      * determine if `object` contains equivalent property values.
11830      *
11831      * **Note:** This method is equivalent to `_.matches` when `source` is
11832      * partially applied.
11833      *
11834      * Partial comparisons will match empty array and empty object `source`
11835      * values against any array or object value, respectively. See `_.isEqual`
11836      * for a list of supported value comparisons.
11837      *
11838      * @static
11839      * @memberOf _
11840      * @since 3.0.0
11841      * @category Lang
11842      * @param {Object} object The object to inspect.
11843      * @param {Object} source The object of property values to match.
11844      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
11845      * @example
11846      *
11847      * var object = { 'a': 1, 'b': 2 };
11848      *
11849      * _.isMatch(object, { 'b': 2 });
11850      * // => true
11851      *
11852      * _.isMatch(object, { 'b': 1 });
11853      * // => false
11854      */
11855     function isMatch(object, source) {
11856       return object === source || baseIsMatch(object, source, getMatchData(source));
11857     }
11858
11859     /**
11860      * This method is like `_.isMatch` except that it accepts `customizer` which
11861      * is invoked to compare values. If `customizer` returns `undefined`, comparisons
11862      * are handled by the method instead. The `customizer` is invoked with five
11863      * arguments: (objValue, srcValue, index|key, object, source).
11864      *
11865      * @static
11866      * @memberOf _
11867      * @since 4.0.0
11868      * @category Lang
11869      * @param {Object} object The object to inspect.
11870      * @param {Object} source The object of property values to match.
11871      * @param {Function} [customizer] The function to customize comparisons.
11872      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
11873      * @example
11874      *
11875      * function isGreeting(value) {
11876      *   return /^h(?:i|ello)$/.test(value);
11877      * }
11878      *
11879      * function customizer(objValue, srcValue) {
11880      *   if (isGreeting(objValue) && isGreeting(srcValue)) {
11881      *     return true;
11882      *   }
11883      * }
11884      *
11885      * var object = { 'greeting': 'hello' };
11886      * var source = { 'greeting': 'hi' };
11887      *
11888      * _.isMatchWith(object, source, customizer);
11889      * // => true
11890      */
11891     function isMatchWith(object, source, customizer) {
11892       customizer = typeof customizer == 'function' ? customizer : undefined;
11893       return baseIsMatch(object, source, getMatchData(source), customizer);
11894     }
11895
11896     /**
11897      * Checks if `value` is `NaN`.
11898      *
11899      * **Note:** This method is based on
11900      * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
11901      * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
11902      * `undefined` and other non-number values.
11903      *
11904      * @static
11905      * @memberOf _
11906      * @since 0.1.0
11907      * @category Lang
11908      * @param {*} value The value to check.
11909      * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
11910      * @example
11911      *
11912      * _.isNaN(NaN);
11913      * // => true
11914      *
11915      * _.isNaN(new Number(NaN));
11916      * // => true
11917      *
11918      * isNaN(undefined);
11919      * // => true
11920      *
11921      * _.isNaN(undefined);
11922      * // => false
11923      */
11924     function isNaN(value) {
11925       // An `NaN` primitive is the only value that is not equal to itself.
11926       // Perform the `toStringTag` check first to avoid errors with some
11927       // ActiveX objects in IE.
11928       return isNumber(value) && value != +value;
11929     }
11930
11931     /**
11932      * Checks if `value` is a pristine native function.
11933      *
11934      * **Note:** This method can't reliably detect native functions in the presence
11935      * of the core-js package because core-js circumvents this kind of detection.
11936      * Despite multiple requests, the core-js maintainer has made it clear: any
11937      * attempt to fix the detection will be obstructed. As a result, we're left
11938      * with little choice but to throw an error. Unfortunately, this also affects
11939      * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
11940      * which rely on core-js.
11941      *
11942      * @static
11943      * @memberOf _
11944      * @since 3.0.0
11945      * @category Lang
11946      * @param {*} value The value to check.
11947      * @returns {boolean} Returns `true` if `value` is a native function,
11948      *  else `false`.
11949      * @example
11950      *
11951      * _.isNative(Array.prototype.push);
11952      * // => true
11953      *
11954      * _.isNative(_);
11955      * // => false
11956      */
11957     function isNative(value) {
11958       if (isMaskable(value)) {
11959         throw new Error(CORE_ERROR_TEXT);
11960       }
11961       return baseIsNative(value);
11962     }
11963
11964     /**
11965      * Checks if `value` is `null`.
11966      *
11967      * @static
11968      * @memberOf _
11969      * @since 0.1.0
11970      * @category Lang
11971      * @param {*} value The value to check.
11972      * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
11973      * @example
11974      *
11975      * _.isNull(null);
11976      * // => true
11977      *
11978      * _.isNull(void 0);
11979      * // => false
11980      */
11981     function isNull(value) {
11982       return value === null;
11983     }
11984
11985     /**
11986      * Checks if `value` is `null` or `undefined`.
11987      *
11988      * @static
11989      * @memberOf _
11990      * @since 4.0.0
11991      * @category Lang
11992      * @param {*} value The value to check.
11993      * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
11994      * @example
11995      *
11996      * _.isNil(null);
11997      * // => true
11998      *
11999      * _.isNil(void 0);
12000      * // => true
12001      *
12002      * _.isNil(NaN);
12003      * // => false
12004      */
12005     function isNil(value) {
12006       return value == null;
12007     }
12008
12009     /**
12010      * Checks if `value` is classified as a `Number` primitive or object.
12011      *
12012      * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
12013      * classified as numbers, use the `_.isFinite` method.
12014      *
12015      * @static
12016      * @memberOf _
12017      * @since 0.1.0
12018      * @category Lang
12019      * @param {*} value The value to check.
12020      * @returns {boolean} Returns `true` if `value` is a number, else `false`.
12021      * @example
12022      *
12023      * _.isNumber(3);
12024      * // => true
12025      *
12026      * _.isNumber(Number.MIN_VALUE);
12027      * // => true
12028      *
12029      * _.isNumber(Infinity);
12030      * // => true
12031      *
12032      * _.isNumber('3');
12033      * // => false
12034      */
12035     function isNumber(value) {
12036       return typeof value == 'number' ||
12037         (isObjectLike(value) && baseGetTag(value) == numberTag);
12038     }
12039
12040     /**
12041      * Checks if `value` is a plain object, that is, an object created by the
12042      * `Object` constructor or one with a `[[Prototype]]` of `null`.
12043      *
12044      * @static
12045      * @memberOf _
12046      * @since 0.8.0
12047      * @category Lang
12048      * @param {*} value The value to check.
12049      * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
12050      * @example
12051      *
12052      * function Foo() {
12053      *   this.a = 1;
12054      * }
12055      *
12056      * _.isPlainObject(new Foo);
12057      * // => false
12058      *
12059      * _.isPlainObject([1, 2, 3]);
12060      * // => false
12061      *
12062      * _.isPlainObject({ 'x': 0, 'y': 0 });
12063      * // => true
12064      *
12065      * _.isPlainObject(Object.create(null));
12066      * // => true
12067      */
12068     function isPlainObject(value) {
12069       if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
12070         return false;
12071       }
12072       var proto = getPrototype(value);
12073       if (proto === null) {
12074         return true;
12075       }
12076       var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
12077       return typeof Ctor == 'function' && Ctor instanceof Ctor &&
12078         funcToString.call(Ctor) == objectCtorString;
12079     }
12080
12081     /**
12082      * Checks if `value` is classified as a `RegExp` object.
12083      *
12084      * @static
12085      * @memberOf _
12086      * @since 0.1.0
12087      * @category Lang
12088      * @param {*} value The value to check.
12089      * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
12090      * @example
12091      *
12092      * _.isRegExp(/abc/);
12093      * // => true
12094      *
12095      * _.isRegExp('/abc/');
12096      * // => false
12097      */
12098     var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;
12099
12100     /**
12101      * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
12102      * double precision number which isn't the result of a rounded unsafe integer.
12103      *
12104      * **Note:** This method is based on
12105      * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
12106      *
12107      * @static
12108      * @memberOf _
12109      * @since 4.0.0
12110      * @category Lang
12111      * @param {*} value The value to check.
12112      * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
12113      * @example
12114      *
12115      * _.isSafeInteger(3);
12116      * // => true
12117      *
12118      * _.isSafeInteger(Number.MIN_VALUE);
12119      * // => false
12120      *
12121      * _.isSafeInteger(Infinity);
12122      * // => false
12123      *
12124      * _.isSafeInteger('3');
12125      * // => false
12126      */
12127     function isSafeInteger(value) {
12128       return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
12129     }
12130
12131     /**
12132      * Checks if `value` is classified as a `Set` object.
12133      *
12134      * @static
12135      * @memberOf _
12136      * @since 4.3.0
12137      * @category Lang
12138      * @param {*} value The value to check.
12139      * @returns {boolean} Returns `true` if `value` is a set, else `false`.
12140      * @example
12141      *
12142      * _.isSet(new Set);
12143      * // => true
12144      *
12145      * _.isSet(new WeakSet);
12146      * // => false
12147      */
12148     var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
12149
12150     /**
12151      * Checks if `value` is classified as a `String` primitive or object.
12152      *
12153      * @static
12154      * @since 0.1.0
12155      * @memberOf _
12156      * @category Lang
12157      * @param {*} value The value to check.
12158      * @returns {boolean} Returns `true` if `value` is a string, else `false`.
12159      * @example
12160      *
12161      * _.isString('abc');
12162      * // => true
12163      *
12164      * _.isString(1);
12165      * // => false
12166      */
12167     function isString(value) {
12168       return typeof value == 'string' ||
12169         (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);
12170     }
12171
12172     /**
12173      * Checks if `value` is classified as a `Symbol` primitive or object.
12174      *
12175      * @static
12176      * @memberOf _
12177      * @since 4.0.0
12178      * @category Lang
12179      * @param {*} value The value to check.
12180      * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
12181      * @example
12182      *
12183      * _.isSymbol(Symbol.iterator);
12184      * // => true
12185      *
12186      * _.isSymbol('abc');
12187      * // => false
12188      */
12189     function isSymbol(value) {
12190       return typeof value == 'symbol' ||
12191         (isObjectLike(value) && baseGetTag(value) == symbolTag);
12192     }
12193
12194     /**
12195      * Checks if `value` is classified as a typed array.
12196      *
12197      * @static
12198      * @memberOf _
12199      * @since 3.0.0
12200      * @category Lang
12201      * @param {*} value The value to check.
12202      * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
12203      * @example
12204      *
12205      * _.isTypedArray(new Uint8Array);
12206      * // => true
12207      *
12208      * _.isTypedArray([]);
12209      * // => false
12210      */
12211     var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
12212
12213     /**
12214      * Checks if `value` is `undefined`.
12215      *
12216      * @static
12217      * @since 0.1.0
12218      * @memberOf _
12219      * @category Lang
12220      * @param {*} value The value to check.
12221      * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
12222      * @example
12223      *
12224      * _.isUndefined(void 0);
12225      * // => true
12226      *
12227      * _.isUndefined(null);
12228      * // => false
12229      */
12230     function isUndefined(value) {
12231       return value === undefined;
12232     }
12233
12234     /**
12235      * Checks if `value` is classified as a `WeakMap` object.
12236      *
12237      * @static
12238      * @memberOf _
12239      * @since 4.3.0
12240      * @category Lang
12241      * @param {*} value The value to check.
12242      * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
12243      * @example
12244      *
12245      * _.isWeakMap(new WeakMap);
12246      * // => true
12247      *
12248      * _.isWeakMap(new Map);
12249      * // => false
12250      */
12251     function isWeakMap(value) {
12252       return isObjectLike(value) && getTag(value) == weakMapTag;
12253     }
12254
12255     /**
12256      * Checks if `value` is classified as a `WeakSet` object.
12257      *
12258      * @static
12259      * @memberOf _
12260      * @since 4.3.0
12261      * @category Lang
12262      * @param {*} value The value to check.
12263      * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
12264      * @example
12265      *
12266      * _.isWeakSet(new WeakSet);
12267      * // => true
12268      *
12269      * _.isWeakSet(new Set);
12270      * // => false
12271      */
12272     function isWeakSet(value) {
12273       return isObjectLike(value) && baseGetTag(value) == weakSetTag;
12274     }
12275
12276     /**
12277      * Checks if `value` is less than `other`.
12278      *
12279      * @static
12280      * @memberOf _
12281      * @since 3.9.0
12282      * @category Lang
12283      * @param {*} value The value to compare.
12284      * @param {*} other The other value to compare.
12285      * @returns {boolean} Returns `true` if `value` is less than `other`,
12286      *  else `false`.
12287      * @see _.gt
12288      * @example
12289      *
12290      * _.lt(1, 3);
12291      * // => true
12292      *
12293      * _.lt(3, 3);
12294      * // => false
12295      *
12296      * _.lt(3, 1);
12297      * // => false
12298      */
12299     var lt = createRelationalOperation(baseLt);
12300
12301     /**
12302      * Checks if `value` is less than or equal to `other`.
12303      *
12304      * @static
12305      * @memberOf _
12306      * @since 3.9.0
12307      * @category Lang
12308      * @param {*} value The value to compare.
12309      * @param {*} other The other value to compare.
12310      * @returns {boolean} Returns `true` if `value` is less than or equal to
12311      *  `other`, else `false`.
12312      * @see _.gte
12313      * @example
12314      *
12315      * _.lte(1, 3);
12316      * // => true
12317      *
12318      * _.lte(3, 3);
12319      * // => true
12320      *
12321      * _.lte(3, 1);
12322      * // => false
12323      */
12324     var lte = createRelationalOperation(function(value, other) {
12325       return value <= other;
12326     });
12327
12328     /**
12329      * Converts `value` to an array.
12330      *
12331      * @static
12332      * @since 0.1.0
12333      * @memberOf _
12334      * @category Lang
12335      * @param {*} value The value to convert.
12336      * @returns {Array} Returns the converted array.
12337      * @example
12338      *
12339      * _.toArray({ 'a': 1, 'b': 2 });
12340      * // => [1, 2]
12341      *
12342      * _.toArray('abc');
12343      * // => ['a', 'b', 'c']
12344      *
12345      * _.toArray(1);
12346      * // => []
12347      *
12348      * _.toArray(null);
12349      * // => []
12350      */
12351     function toArray(value) {
12352       if (!value) {
12353         return [];
12354       }
12355       if (isArrayLike(value)) {
12356         return isString(value) ? stringToArray(value) : copyArray(value);
12357       }
12358       if (symIterator && value[symIterator]) {
12359         return iteratorToArray(value[symIterator]());
12360       }
12361       var tag = getTag(value),
12362           func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
12363
12364       return func(value);
12365     }
12366
12367     /**
12368      * Converts `value` to a finite number.
12369      *
12370      * @static
12371      * @memberOf _
12372      * @since 4.12.0
12373      * @category Lang
12374      * @param {*} value The value to convert.
12375      * @returns {number} Returns the converted number.
12376      * @example
12377      *
12378      * _.toFinite(3.2);
12379      * // => 3.2
12380      *
12381      * _.toFinite(Number.MIN_VALUE);
12382      * // => 5e-324
12383      *
12384      * _.toFinite(Infinity);
12385      * // => 1.7976931348623157e+308
12386      *
12387      * _.toFinite('3.2');
12388      * // => 3.2
12389      */
12390     function toFinite(value) {
12391       if (!value) {
12392         return value === 0 ? value : 0;
12393       }
12394       value = toNumber(value);
12395       if (value === INFINITY || value === -INFINITY) {
12396         var sign = (value < 0 ? -1 : 1);
12397         return sign * MAX_INTEGER;
12398       }
12399       return value === value ? value : 0;
12400     }
12401
12402     /**
12403      * Converts `value` to an integer.
12404      *
12405      * **Note:** This method is loosely based on
12406      * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
12407      *
12408      * @static
12409      * @memberOf _
12410      * @since 4.0.0
12411      * @category Lang
12412      * @param {*} value The value to convert.
12413      * @returns {number} Returns the converted integer.
12414      * @example
12415      *
12416      * _.toInteger(3.2);
12417      * // => 3
12418      *
12419      * _.toInteger(Number.MIN_VALUE);
12420      * // => 0
12421      *
12422      * _.toInteger(Infinity);
12423      * // => 1.7976931348623157e+308
12424      *
12425      * _.toInteger('3.2');
12426      * // => 3
12427      */
12428     function toInteger(value) {
12429       var result = toFinite(value),
12430           remainder = result % 1;
12431
12432       return result === result ? (remainder ? result - remainder : result) : 0;
12433     }
12434
12435     /**
12436      * Converts `value` to an integer suitable for use as the length of an
12437      * array-like object.
12438      *
12439      * **Note:** This method is based on
12440      * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
12441      *
12442      * @static
12443      * @memberOf _
12444      * @since 4.0.0
12445      * @category Lang
12446      * @param {*} value The value to convert.
12447      * @returns {number} Returns the converted integer.
12448      * @example
12449      *
12450      * _.toLength(3.2);
12451      * // => 3
12452      *
12453      * _.toLength(Number.MIN_VALUE);
12454      * // => 0
12455      *
12456      * _.toLength(Infinity);
12457      * // => 4294967295
12458      *
12459      * _.toLength('3.2');
12460      * // => 3
12461      */
12462     function toLength(value) {
12463       return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
12464     }
12465
12466     /**
12467      * Converts `value` to a number.
12468      *
12469      * @static
12470      * @memberOf _
12471      * @since 4.0.0
12472      * @category Lang
12473      * @param {*} value The value to process.
12474      * @returns {number} Returns the number.
12475      * @example
12476      *
12477      * _.toNumber(3.2);
12478      * // => 3.2
12479      *
12480      * _.toNumber(Number.MIN_VALUE);
12481      * // => 5e-324
12482      *
12483      * _.toNumber(Infinity);
12484      * // => Infinity
12485      *
12486      * _.toNumber('3.2');
12487      * // => 3.2
12488      */
12489     function toNumber(value) {
12490       if (typeof value == 'number') {
12491         return value;
12492       }
12493       if (isSymbol(value)) {
12494         return NAN;
12495       }
12496       if (isObject(value)) {
12497         var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
12498         value = isObject(other) ? (other + '') : other;
12499       }
12500       if (typeof value != 'string') {
12501         return value === 0 ? value : +value;
12502       }
12503       value = value.replace(reTrim, '');
12504       var isBinary = reIsBinary.test(value);
12505       return (isBinary || reIsOctal.test(value))
12506         ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
12507         : (reIsBadHex.test(value) ? NAN : +value);
12508     }
12509
12510     /**
12511      * Converts `value` to a plain object flattening inherited enumerable string
12512      * keyed properties of `value` to own properties of the plain object.
12513      *
12514      * @static
12515      * @memberOf _
12516      * @since 3.0.0
12517      * @category Lang
12518      * @param {*} value The value to convert.
12519      * @returns {Object} Returns the converted plain object.
12520      * @example
12521      *
12522      * function Foo() {
12523      *   this.b = 2;
12524      * }
12525      *
12526      * Foo.prototype.c = 3;
12527      *
12528      * _.assign({ 'a': 1 }, new Foo);
12529      * // => { 'a': 1, 'b': 2 }
12530      *
12531      * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
12532      * // => { 'a': 1, 'b': 2, 'c': 3 }
12533      */
12534     function toPlainObject(value) {
12535       return copyObject(value, keysIn(value));
12536     }
12537
12538     /**
12539      * Converts `value` to a safe integer. A safe integer can be compared and
12540      * represented correctly.
12541      *
12542      * @static
12543      * @memberOf _
12544      * @since 4.0.0
12545      * @category Lang
12546      * @param {*} value The value to convert.
12547      * @returns {number} Returns the converted integer.
12548      * @example
12549      *
12550      * _.toSafeInteger(3.2);
12551      * // => 3
12552      *
12553      * _.toSafeInteger(Number.MIN_VALUE);
12554      * // => 0
12555      *
12556      * _.toSafeInteger(Infinity);
12557      * // => 9007199254740991
12558      *
12559      * _.toSafeInteger('3.2');
12560      * // => 3
12561      */
12562     function toSafeInteger(value) {
12563       return value
12564         ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)
12565         : (value === 0 ? value : 0);
12566     }
12567
12568     /**
12569      * Converts `value` to a string. An empty string is returned for `null`
12570      * and `undefined` values. The sign of `-0` is preserved.
12571      *
12572      * @static
12573      * @memberOf _
12574      * @since 4.0.0
12575      * @category Lang
12576      * @param {*} value The value to convert.
12577      * @returns {string} Returns the converted string.
12578      * @example
12579      *
12580      * _.toString(null);
12581      * // => ''
12582      *
12583      * _.toString(-0);
12584      * // => '-0'
12585      *
12586      * _.toString([1, 2, 3]);
12587      * // => '1,2,3'
12588      */
12589     function toString(value) {
12590       return value == null ? '' : baseToString(value);
12591     }
12592
12593     /*------------------------------------------------------------------------*/
12594
12595     /**
12596      * Assigns own enumerable string keyed properties of source objects to the
12597      * destination object. Source objects are applied from left to right.
12598      * Subsequent sources overwrite property assignments of previous sources.
12599      *
12600      * **Note:** This method mutates `object` and is loosely based on
12601      * [`Object.assign`](https://mdn.io/Object/assign).
12602      *
12603      * @static
12604      * @memberOf _
12605      * @since 0.10.0
12606      * @category Object
12607      * @param {Object} object The destination object.
12608      * @param {...Object} [sources] The source objects.
12609      * @returns {Object} Returns `object`.
12610      * @see _.assignIn
12611      * @example
12612      *
12613      * function Foo() {
12614      *   this.a = 1;
12615      * }
12616      *
12617      * function Bar() {
12618      *   this.c = 3;
12619      * }
12620      *
12621      * Foo.prototype.b = 2;
12622      * Bar.prototype.d = 4;
12623      *
12624      * _.assign({ 'a': 0 }, new Foo, new Bar);
12625      * // => { 'a': 1, 'c': 3 }
12626      */
12627     var assign = createAssigner(function(object, source) {
12628       if (isPrototype(source) || isArrayLike(source)) {
12629         copyObject(source, keys(source), object);
12630         return;
12631       }
12632       for (var key in source) {
12633         if (hasOwnProperty.call(source, key)) {
12634           assignValue(object, key, source[key]);
12635         }
12636       }
12637     });
12638
12639     /**
12640      * This method is like `_.assign` except that it iterates over own and
12641      * inherited source properties.
12642      *
12643      * **Note:** This method mutates `object`.
12644      *
12645      * @static
12646      * @memberOf _
12647      * @since 4.0.0
12648      * @alias extend
12649      * @category Object
12650      * @param {Object} object The destination object.
12651      * @param {...Object} [sources] The source objects.
12652      * @returns {Object} Returns `object`.
12653      * @see _.assign
12654      * @example
12655      *
12656      * function Foo() {
12657      *   this.a = 1;
12658      * }
12659      *
12660      * function Bar() {
12661      *   this.c = 3;
12662      * }
12663      *
12664      * Foo.prototype.b = 2;
12665      * Bar.prototype.d = 4;
12666      *
12667      * _.assignIn({ 'a': 0 }, new Foo, new Bar);
12668      * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
12669      */
12670     var assignIn = createAssigner(function(object, source) {
12671       copyObject(source, keysIn(source), object);
12672     });
12673
12674     /**
12675      * This method is like `_.assignIn` except that it accepts `customizer`
12676      * which is invoked to produce the assigned values. If `customizer` returns
12677      * `undefined`, assignment is handled by the method instead. The `customizer`
12678      * is invoked with five arguments: (objValue, srcValue, key, object, source).
12679      *
12680      * **Note:** This method mutates `object`.
12681      *
12682      * @static
12683      * @memberOf _
12684      * @since 4.0.0
12685      * @alias extendWith
12686      * @category Object
12687      * @param {Object} object The destination object.
12688      * @param {...Object} sources The source objects.
12689      * @param {Function} [customizer] The function to customize assigned values.
12690      * @returns {Object} Returns `object`.
12691      * @see _.assignWith
12692      * @example
12693      *
12694      * function customizer(objValue, srcValue) {
12695      *   return _.isUndefined(objValue) ? srcValue : objValue;
12696      * }
12697      *
12698      * var defaults = _.partialRight(_.assignInWith, customizer);
12699      *
12700      * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12701      * // => { 'a': 1, 'b': 2 }
12702      */
12703     var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {
12704       copyObject(source, keysIn(source), object, customizer);
12705     });
12706
12707     /**
12708      * This method is like `_.assign` except that it accepts `customizer`
12709      * which is invoked to produce the assigned values. If `customizer` returns
12710      * `undefined`, assignment is handled by the method instead. The `customizer`
12711      * is invoked with five arguments: (objValue, srcValue, key, object, source).
12712      *
12713      * **Note:** This method mutates `object`.
12714      *
12715      * @static
12716      * @memberOf _
12717      * @since 4.0.0
12718      * @category Object
12719      * @param {Object} object The destination object.
12720      * @param {...Object} sources The source objects.
12721      * @param {Function} [customizer] The function to customize assigned values.
12722      * @returns {Object} Returns `object`.
12723      * @see _.assignInWith
12724      * @example
12725      *
12726      * function customizer(objValue, srcValue) {
12727      *   return _.isUndefined(objValue) ? srcValue : objValue;
12728      * }
12729      *
12730      * var defaults = _.partialRight(_.assignWith, customizer);
12731      *
12732      * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12733      * // => { 'a': 1, 'b': 2 }
12734      */
12735     var assignWith = createAssigner(function(object, source, srcIndex, customizer) {
12736       copyObject(source, keys(source), object, customizer);
12737     });
12738
12739     /**
12740      * Creates an array of values corresponding to `paths` of `object`.
12741      *
12742      * @static
12743      * @memberOf _
12744      * @since 1.0.0
12745      * @category Object
12746      * @param {Object} object The object to iterate over.
12747      * @param {...(string|string[])} [paths] The property paths to pick.
12748      * @returns {Array} Returns the picked values.
12749      * @example
12750      *
12751      * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
12752      *
12753      * _.at(object, ['a[0].b.c', 'a[1]']);
12754      * // => [3, 4]
12755      */
12756     var at = flatRest(baseAt);
12757
12758     /**
12759      * Creates an object that inherits from the `prototype` object. If a
12760      * `properties` object is given, its own enumerable string keyed properties
12761      * are assigned to the created object.
12762      *
12763      * @static
12764      * @memberOf _
12765      * @since 2.3.0
12766      * @category Object
12767      * @param {Object} prototype The object to inherit from.
12768      * @param {Object} [properties] The properties to assign to the object.
12769      * @returns {Object} Returns the new object.
12770      * @example
12771      *
12772      * function Shape() {
12773      *   this.x = 0;
12774      *   this.y = 0;
12775      * }
12776      *
12777      * function Circle() {
12778      *   Shape.call(this);
12779      * }
12780      *
12781      * Circle.prototype = _.create(Shape.prototype, {
12782      *   'constructor': Circle
12783      * });
12784      *
12785      * var circle = new Circle;
12786      * circle instanceof Circle;
12787      * // => true
12788      *
12789      * circle instanceof Shape;
12790      * // => true
12791      */
12792     function create(prototype, properties) {
12793       var result = baseCreate(prototype);
12794       return properties == null ? result : baseAssign(result, properties);
12795     }
12796
12797     /**
12798      * Assigns own and inherited enumerable string keyed properties of source
12799      * objects to the destination object for all destination properties that
12800      * resolve to `undefined`. Source objects are applied from left to right.
12801      * Once a property is set, additional values of the same property are ignored.
12802      *
12803      * **Note:** This method mutates `object`.
12804      *
12805      * @static
12806      * @since 0.1.0
12807      * @memberOf _
12808      * @category Object
12809      * @param {Object} object The destination object.
12810      * @param {...Object} [sources] The source objects.
12811      * @returns {Object} Returns `object`.
12812      * @see _.defaultsDeep
12813      * @example
12814      *
12815      * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12816      * // => { 'a': 1, 'b': 2 }
12817      */
12818     var defaults = baseRest(function(args) {
12819       args.push(undefined, customDefaultsAssignIn);
12820       return apply(assignInWith, undefined, args);
12821     });
12822
12823     /**
12824      * This method is like `_.defaults` except that it recursively assigns
12825      * default properties.
12826      *
12827      * **Note:** This method mutates `object`.
12828      *
12829      * @static
12830      * @memberOf _
12831      * @since 3.10.0
12832      * @category Object
12833      * @param {Object} object The destination object.
12834      * @param {...Object} [sources] The source objects.
12835      * @returns {Object} Returns `object`.
12836      * @see _.defaults
12837      * @example
12838      *
12839      * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
12840      * // => { 'a': { 'b': 2, 'c': 3 } }
12841      */
12842     var defaultsDeep = baseRest(function(args) {
12843       args.push(undefined, customDefaultsMerge);
12844       return apply(mergeWith, undefined, args);
12845     });
12846
12847     /**
12848      * This method is like `_.find` except that it returns the key of the first
12849      * element `predicate` returns truthy for instead of the element itself.
12850      *
12851      * @static
12852      * @memberOf _
12853      * @since 1.1.0
12854      * @category Object
12855      * @param {Object} object The object to inspect.
12856      * @param {Function} [predicate=_.identity] The function invoked per iteration.
12857      * @returns {string|undefined} Returns the key of the matched element,
12858      *  else `undefined`.
12859      * @example
12860      *
12861      * var users = {
12862      *   'barney':  { 'age': 36, 'active': true },
12863      *   'fred':    { 'age': 40, 'active': false },
12864      *   'pebbles': { 'age': 1,  'active': true }
12865      * };
12866      *
12867      * _.findKey(users, function(o) { return o.age < 40; });
12868      * // => 'barney' (iteration order is not guaranteed)
12869      *
12870      * // The `_.matches` iteratee shorthand.
12871      * _.findKey(users, { 'age': 1, 'active': true });
12872      * // => 'pebbles'
12873      *
12874      * // The `_.matchesProperty` iteratee shorthand.
12875      * _.findKey(users, ['active', false]);
12876      * // => 'fred'
12877      *
12878      * // The `_.property` iteratee shorthand.
12879      * _.findKey(users, 'active');
12880      * // => 'barney'
12881      */
12882     function findKey(object, predicate) {
12883       return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);
12884     }
12885
12886     /**
12887      * This method is like `_.findKey` except that it iterates over elements of
12888      * a collection in the opposite order.
12889      *
12890      * @static
12891      * @memberOf _
12892      * @since 2.0.0
12893      * @category Object
12894      * @param {Object} object The object to inspect.
12895      * @param {Function} [predicate=_.identity] The function invoked per iteration.
12896      * @returns {string|undefined} Returns the key of the matched element,
12897      *  else `undefined`.
12898      * @example
12899      *
12900      * var users = {
12901      *   'barney':  { 'age': 36, 'active': true },
12902      *   'fred':    { 'age': 40, 'active': false },
12903      *   'pebbles': { 'age': 1,  'active': true }
12904      * };
12905      *
12906      * _.findLastKey(users, function(o) { return o.age < 40; });
12907      * // => returns 'pebbles' assuming `_.findKey` returns 'barney'
12908      *
12909      * // The `_.matches` iteratee shorthand.
12910      * _.findLastKey(users, { 'age': 36, 'active': true });
12911      * // => 'barney'
12912      *
12913      * // The `_.matchesProperty` iteratee shorthand.
12914      * _.findLastKey(users, ['active', false]);
12915      * // => 'fred'
12916      *
12917      * // The `_.property` iteratee shorthand.
12918      * _.findLastKey(users, 'active');
12919      * // => 'pebbles'
12920      */
12921     function findLastKey(object, predicate) {
12922       return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);
12923     }
12924
12925     /**
12926      * Iterates over own and inherited enumerable string keyed properties of an
12927      * object and invokes `iteratee` for each property. The iteratee is invoked
12928      * with three arguments: (value, key, object). Iteratee functions may exit
12929      * iteration early by explicitly returning `false`.
12930      *
12931      * @static
12932      * @memberOf _
12933      * @since 0.3.0
12934      * @category Object
12935      * @param {Object} object The object to iterate over.
12936      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12937      * @returns {Object} Returns `object`.
12938      * @see _.forInRight
12939      * @example
12940      *
12941      * function Foo() {
12942      *   this.a = 1;
12943      *   this.b = 2;
12944      * }
12945      *
12946      * Foo.prototype.c = 3;
12947      *
12948      * _.forIn(new Foo, function(value, key) {
12949      *   console.log(key);
12950      * });
12951      * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
12952      */
12953     function forIn(object, iteratee) {
12954       return object == null
12955         ? object
12956         : baseFor(object, getIteratee(iteratee, 3), keysIn);
12957     }
12958
12959     /**
12960      * This method is like `_.forIn` except that it iterates over properties of
12961      * `object` in the opposite order.
12962      *
12963      * @static
12964      * @memberOf _
12965      * @since 2.0.0
12966      * @category Object
12967      * @param {Object} object The object to iterate over.
12968      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12969      * @returns {Object} Returns `object`.
12970      * @see _.forIn
12971      * @example
12972      *
12973      * function Foo() {
12974      *   this.a = 1;
12975      *   this.b = 2;
12976      * }
12977      *
12978      * Foo.prototype.c = 3;
12979      *
12980      * _.forInRight(new Foo, function(value, key) {
12981      *   console.log(key);
12982      * });
12983      * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
12984      */
12985     function forInRight(object, iteratee) {
12986       return object == null
12987         ? object
12988         : baseForRight(object, getIteratee(iteratee, 3), keysIn);
12989     }
12990
12991     /**
12992      * Iterates over own enumerable string keyed properties of an object and
12993      * invokes `iteratee` for each property. The iteratee is invoked with three
12994      * arguments: (value, key, object). Iteratee functions may exit iteration
12995      * early by explicitly returning `false`.
12996      *
12997      * @static
12998      * @memberOf _
12999      * @since 0.3.0
13000      * @category Object
13001      * @param {Object} object The object to iterate over.
13002      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13003      * @returns {Object} Returns `object`.
13004      * @see _.forOwnRight
13005      * @example
13006      *
13007      * function Foo() {
13008      *   this.a = 1;
13009      *   this.b = 2;
13010      * }
13011      *
13012      * Foo.prototype.c = 3;
13013      *
13014      * _.forOwn(new Foo, function(value, key) {
13015      *   console.log(key);
13016      * });
13017      * // => Logs 'a' then 'b' (iteration order is not guaranteed).
13018      */
13019     function forOwn(object, iteratee) {
13020       return object && baseForOwn(object, getIteratee(iteratee, 3));
13021     }
13022
13023     /**
13024      * This method is like `_.forOwn` except that it iterates over properties of
13025      * `object` in the opposite order.
13026      *
13027      * @static
13028      * @memberOf _
13029      * @since 2.0.0
13030      * @category Object
13031      * @param {Object} object The object to iterate over.
13032      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13033      * @returns {Object} Returns `object`.
13034      * @see _.forOwn
13035      * @example
13036      *
13037      * function Foo() {
13038      *   this.a = 1;
13039      *   this.b = 2;
13040      * }
13041      *
13042      * Foo.prototype.c = 3;
13043      *
13044      * _.forOwnRight(new Foo, function(value, key) {
13045      *   console.log(key);
13046      * });
13047      * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
13048      */
13049     function forOwnRight(object, iteratee) {
13050       return object && baseForOwnRight(object, getIteratee(iteratee, 3));
13051     }
13052
13053     /**
13054      * Creates an array of function property names from own enumerable properties
13055      * of `object`.
13056      *
13057      * @static
13058      * @since 0.1.0
13059      * @memberOf _
13060      * @category Object
13061      * @param {Object} object The object to inspect.
13062      * @returns {Array} Returns the function names.
13063      * @see _.functionsIn
13064      * @example
13065      *
13066      * function Foo() {
13067      *   this.a = _.constant('a');
13068      *   this.b = _.constant('b');
13069      * }
13070      *
13071      * Foo.prototype.c = _.constant('c');
13072      *
13073      * _.functions(new Foo);
13074      * // => ['a', 'b']
13075      */
13076     function functions(object) {
13077       return object == null ? [] : baseFunctions(object, keys(object));
13078     }
13079
13080     /**
13081      * Creates an array of function property names from own and inherited
13082      * enumerable properties of `object`.
13083      *
13084      * @static
13085      * @memberOf _
13086      * @since 4.0.0
13087      * @category Object
13088      * @param {Object} object The object to inspect.
13089      * @returns {Array} Returns the function names.
13090      * @see _.functions
13091      * @example
13092      *
13093      * function Foo() {
13094      *   this.a = _.constant('a');
13095      *   this.b = _.constant('b');
13096      * }
13097      *
13098      * Foo.prototype.c = _.constant('c');
13099      *
13100      * _.functionsIn(new Foo);
13101      * // => ['a', 'b', 'c']
13102      */
13103     function functionsIn(object) {
13104       return object == null ? [] : baseFunctions(object, keysIn(object));
13105     }
13106
13107     /**
13108      * Gets the value at `path` of `object`. If the resolved value is
13109      * `undefined`, the `defaultValue` is returned in its place.
13110      *
13111      * @static
13112      * @memberOf _
13113      * @since 3.7.0
13114      * @category Object
13115      * @param {Object} object The object to query.
13116      * @param {Array|string} path The path of the property to get.
13117      * @param {*} [defaultValue] The value returned for `undefined` resolved values.
13118      * @returns {*} Returns the resolved value.
13119      * @example
13120      *
13121      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13122      *
13123      * _.get(object, 'a[0].b.c');
13124      * // => 3
13125      *
13126      * _.get(object, ['a', '0', 'b', 'c']);
13127      * // => 3
13128      *
13129      * _.get(object, 'a.b.c', 'default');
13130      * // => 'default'
13131      */
13132     function get(object, path, defaultValue) {
13133       var result = object == null ? undefined : baseGet(object, path);
13134       return result === undefined ? defaultValue : result;
13135     }
13136
13137     /**
13138      * Checks if `path` is a direct property of `object`.
13139      *
13140      * @static
13141      * @since 0.1.0
13142      * @memberOf _
13143      * @category Object
13144      * @param {Object} object The object to query.
13145      * @param {Array|string} path The path to check.
13146      * @returns {boolean} Returns `true` if `path` exists, else `false`.
13147      * @example
13148      *
13149      * var object = { 'a': { 'b': 2 } };
13150      * var other = _.create({ 'a': _.create({ 'b': 2 }) });
13151      *
13152      * _.has(object, 'a');
13153      * // => true
13154      *
13155      * _.has(object, 'a.b');
13156      * // => true
13157      *
13158      * _.has(object, ['a', 'b']);
13159      * // => true
13160      *
13161      * _.has(other, 'a');
13162      * // => false
13163      */
13164     function has(object, path) {
13165       return object != null && hasPath(object, path, baseHas);
13166     }
13167
13168     /**
13169      * Checks if `path` is a direct or inherited property of `object`.
13170      *
13171      * @static
13172      * @memberOf _
13173      * @since 4.0.0
13174      * @category Object
13175      * @param {Object} object The object to query.
13176      * @param {Array|string} path The path to check.
13177      * @returns {boolean} Returns `true` if `path` exists, else `false`.
13178      * @example
13179      *
13180      * var object = _.create({ 'a': _.create({ 'b': 2 }) });
13181      *
13182      * _.hasIn(object, 'a');
13183      * // => true
13184      *
13185      * _.hasIn(object, 'a.b');
13186      * // => true
13187      *
13188      * _.hasIn(object, ['a', 'b']);
13189      * // => true
13190      *
13191      * _.hasIn(object, 'b');
13192      * // => false
13193      */
13194     function hasIn(object, path) {
13195       return object != null && hasPath(object, path, baseHasIn);
13196     }
13197
13198     /**
13199      * Creates an object composed of the inverted keys and values of `object`.
13200      * If `object` contains duplicate values, subsequent values overwrite
13201      * property assignments of previous values.
13202      *
13203      * @static
13204      * @memberOf _
13205      * @since 0.7.0
13206      * @category Object
13207      * @param {Object} object The object to invert.
13208      * @returns {Object} Returns the new inverted object.
13209      * @example
13210      *
13211      * var object = { 'a': 1, 'b': 2, 'c': 1 };
13212      *
13213      * _.invert(object);
13214      * // => { '1': 'c', '2': 'b' }
13215      */
13216     var invert = createInverter(function(result, value, key) {
13217       result[value] = key;
13218     }, constant(identity));
13219
13220     /**
13221      * This method is like `_.invert` except that the inverted object is generated
13222      * from the results of running each element of `object` thru `iteratee`. The
13223      * corresponding inverted value of each inverted key is an array of keys
13224      * responsible for generating the inverted value. The iteratee is invoked
13225      * with one argument: (value).
13226      *
13227      * @static
13228      * @memberOf _
13229      * @since 4.1.0
13230      * @category Object
13231      * @param {Object} object The object to invert.
13232      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
13233      * @returns {Object} Returns the new inverted object.
13234      * @example
13235      *
13236      * var object = { 'a': 1, 'b': 2, 'c': 1 };
13237      *
13238      * _.invertBy(object);
13239      * // => { '1': ['a', 'c'], '2': ['b'] }
13240      *
13241      * _.invertBy(object, function(value) {
13242      *   return 'group' + value;
13243      * });
13244      * // => { 'group1': ['a', 'c'], 'group2': ['b'] }
13245      */
13246     var invertBy = createInverter(function(result, value, key) {
13247       if (hasOwnProperty.call(result, value)) {
13248         result[value].push(key);
13249       } else {
13250         result[value] = [key];
13251       }
13252     }, getIteratee);
13253
13254     /**
13255      * Invokes the method at `path` of `object`.
13256      *
13257      * @static
13258      * @memberOf _
13259      * @since 4.0.0
13260      * @category Object
13261      * @param {Object} object The object to query.
13262      * @param {Array|string} path The path of the method to invoke.
13263      * @param {...*} [args] The arguments to invoke the method with.
13264      * @returns {*} Returns the result of the invoked method.
13265      * @example
13266      *
13267      * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
13268      *
13269      * _.invoke(object, 'a[0].b.c.slice', 1, 3);
13270      * // => [2, 3]
13271      */
13272     var invoke = baseRest(baseInvoke);
13273
13274     /**
13275      * Creates an array of the own enumerable property names of `object`.
13276      *
13277      * **Note:** Non-object values are coerced to objects. See the
13278      * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
13279      * for more details.
13280      *
13281      * @static
13282      * @since 0.1.0
13283      * @memberOf _
13284      * @category Object
13285      * @param {Object} object The object to query.
13286      * @returns {Array} Returns the array of property names.
13287      * @example
13288      *
13289      * function Foo() {
13290      *   this.a = 1;
13291      *   this.b = 2;
13292      * }
13293      *
13294      * Foo.prototype.c = 3;
13295      *
13296      * _.keys(new Foo);
13297      * // => ['a', 'b'] (iteration order is not guaranteed)
13298      *
13299      * _.keys('hi');
13300      * // => ['0', '1']
13301      */
13302     function keys(object) {
13303       return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
13304     }
13305
13306     /**
13307      * Creates an array of the own and inherited enumerable property names of `object`.
13308      *
13309      * **Note:** Non-object values are coerced to objects.
13310      *
13311      * @static
13312      * @memberOf _
13313      * @since 3.0.0
13314      * @category Object
13315      * @param {Object} object The object to query.
13316      * @returns {Array} Returns the array of property names.
13317      * @example
13318      *
13319      * function Foo() {
13320      *   this.a = 1;
13321      *   this.b = 2;
13322      * }
13323      *
13324      * Foo.prototype.c = 3;
13325      *
13326      * _.keysIn(new Foo);
13327      * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
13328      */
13329     function keysIn(object) {
13330       return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
13331     }
13332
13333     /**
13334      * The opposite of `_.mapValues`; this method creates an object with the
13335      * same values as `object` and keys generated by running each own enumerable
13336      * string keyed property of `object` thru `iteratee`. The iteratee is invoked
13337      * with three arguments: (value, key, object).
13338      *
13339      * @static
13340      * @memberOf _
13341      * @since 3.8.0
13342      * @category Object
13343      * @param {Object} object The object to iterate over.
13344      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13345      * @returns {Object} Returns the new mapped object.
13346      * @see _.mapValues
13347      * @example
13348      *
13349      * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
13350      *   return key + value;
13351      * });
13352      * // => { 'a1': 1, 'b2': 2 }
13353      */
13354     function mapKeys(object, iteratee) {
13355       var result = {};
13356       iteratee = getIteratee(iteratee, 3);
13357
13358       baseForOwn(object, function(value, key, object) {
13359         baseAssignValue(result, iteratee(value, key, object), value);
13360       });
13361       return result;
13362     }
13363
13364     /**
13365      * Creates an object with the same keys as `object` and values generated
13366      * by running each own enumerable string keyed property of `object` thru
13367      * `iteratee`. The iteratee is invoked with three arguments:
13368      * (value, key, object).
13369      *
13370      * @static
13371      * @memberOf _
13372      * @since 2.4.0
13373      * @category Object
13374      * @param {Object} object The object to iterate over.
13375      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13376      * @returns {Object} Returns the new mapped object.
13377      * @see _.mapKeys
13378      * @example
13379      *
13380      * var users = {
13381      *   'fred':    { 'user': 'fred',    'age': 40 },
13382      *   'pebbles': { 'user': 'pebbles', 'age': 1 }
13383      * };
13384      *
13385      * _.mapValues(users, function(o) { return o.age; });
13386      * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
13387      *
13388      * // The `_.property` iteratee shorthand.
13389      * _.mapValues(users, 'age');
13390      * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
13391      */
13392     function mapValues(object, iteratee) {
13393       var result = {};
13394       iteratee = getIteratee(iteratee, 3);
13395
13396       baseForOwn(object, function(value, key, object) {
13397         baseAssignValue(result, key, iteratee(value, key, object));
13398       });
13399       return result;
13400     }
13401
13402     /**
13403      * This method is like `_.assign` except that it recursively merges own and
13404      * inherited enumerable string keyed properties of source objects into the
13405      * destination object. Source properties that resolve to `undefined` are
13406      * skipped if a destination value exists. Array and plain object properties
13407      * are merged recursively. Other objects and value types are overridden by
13408      * assignment. Source objects are applied from left to right. Subsequent
13409      * sources overwrite property assignments of previous sources.
13410      *
13411      * **Note:** This method mutates `object`.
13412      *
13413      * @static
13414      * @memberOf _
13415      * @since 0.5.0
13416      * @category Object
13417      * @param {Object} object The destination object.
13418      * @param {...Object} [sources] The source objects.
13419      * @returns {Object} Returns `object`.
13420      * @example
13421      *
13422      * var object = {
13423      *   'a': [{ 'b': 2 }, { 'd': 4 }]
13424      * };
13425      *
13426      * var other = {
13427      *   'a': [{ 'c': 3 }, { 'e': 5 }]
13428      * };
13429      *
13430      * _.merge(object, other);
13431      * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
13432      */
13433     var merge = createAssigner(function(object, source, srcIndex) {
13434       baseMerge(object, source, srcIndex);
13435     });
13436
13437     /**
13438      * This method is like `_.merge` except that it accepts `customizer` which
13439      * is invoked to produce the merged values of the destination and source
13440      * properties. If `customizer` returns `undefined`, merging is handled by the
13441      * method instead. The `customizer` is invoked with six arguments:
13442      * (objValue, srcValue, key, object, source, stack).
13443      *
13444      * **Note:** This method mutates `object`.
13445      *
13446      * @static
13447      * @memberOf _
13448      * @since 4.0.0
13449      * @category Object
13450      * @param {Object} object The destination object.
13451      * @param {...Object} sources The source objects.
13452      * @param {Function} customizer The function to customize assigned values.
13453      * @returns {Object} Returns `object`.
13454      * @example
13455      *
13456      * function customizer(objValue, srcValue) {
13457      *   if (_.isArray(objValue)) {
13458      *     return objValue.concat(srcValue);
13459      *   }
13460      * }
13461      *
13462      * var object = { 'a': [1], 'b': [2] };
13463      * var other = { 'a': [3], 'b': [4] };
13464      *
13465      * _.mergeWith(object, other, customizer);
13466      * // => { 'a': [1, 3], 'b': [2, 4] }
13467      */
13468     var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {
13469       baseMerge(object, source, srcIndex, customizer);
13470     });
13471
13472     /**
13473      * The opposite of `_.pick`; this method creates an object composed of the
13474      * own and inherited enumerable property paths of `object` that are not omitted.
13475      *
13476      * **Note:** This method is considerably slower than `_.pick`.
13477      *
13478      * @static
13479      * @since 0.1.0
13480      * @memberOf _
13481      * @category Object
13482      * @param {Object} object The source object.
13483      * @param {...(string|string[])} [paths] The property paths to omit.
13484      * @returns {Object} Returns the new object.
13485      * @example
13486      *
13487      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13488      *
13489      * _.omit(object, ['a', 'c']);
13490      * // => { 'b': '2' }
13491      */
13492     var omit = flatRest(function(object, paths) {
13493       var result = {};
13494       if (object == null) {
13495         return result;
13496       }
13497       var isDeep = false;
13498       paths = arrayMap(paths, function(path) {
13499         path = castPath(path, object);
13500         isDeep || (isDeep = path.length > 1);
13501         return path;
13502       });
13503       copyObject(object, getAllKeysIn(object), result);
13504       if (isDeep) {
13505         result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);
13506       }
13507       var length = paths.length;
13508       while (length--) {
13509         baseUnset(result, paths[length]);
13510       }
13511       return result;
13512     });
13513
13514     /**
13515      * The opposite of `_.pickBy`; this method creates an object composed of
13516      * the own and inherited enumerable string keyed properties of `object` that
13517      * `predicate` doesn't return truthy for. The predicate is invoked with two
13518      * arguments: (value, key).
13519      *
13520      * @static
13521      * @memberOf _
13522      * @since 4.0.0
13523      * @category Object
13524      * @param {Object} object The source object.
13525      * @param {Function} [predicate=_.identity] The function invoked per property.
13526      * @returns {Object} Returns the new object.
13527      * @example
13528      *
13529      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13530      *
13531      * _.omitBy(object, _.isNumber);
13532      * // => { 'b': '2' }
13533      */
13534     function omitBy(object, predicate) {
13535       return pickBy(object, negate(getIteratee(predicate)));
13536     }
13537
13538     /**
13539      * Creates an object composed of the picked `object` properties.
13540      *
13541      * @static
13542      * @since 0.1.0
13543      * @memberOf _
13544      * @category Object
13545      * @param {Object} object The source object.
13546      * @param {...(string|string[])} [paths] The property paths to pick.
13547      * @returns {Object} Returns the new object.
13548      * @example
13549      *
13550      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13551      *
13552      * _.pick(object, ['a', 'c']);
13553      * // => { 'a': 1, 'c': 3 }
13554      */
13555     var pick = flatRest(function(object, paths) {
13556       return object == null ? {} : basePick(object, paths);
13557     });
13558
13559     /**
13560      * Creates an object composed of the `object` properties `predicate` returns
13561      * truthy for. The predicate is invoked with two arguments: (value, key).
13562      *
13563      * @static
13564      * @memberOf _
13565      * @since 4.0.0
13566      * @category Object
13567      * @param {Object} object The source object.
13568      * @param {Function} [predicate=_.identity] The function invoked per property.
13569      * @returns {Object} Returns the new object.
13570      * @example
13571      *
13572      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13573      *
13574      * _.pickBy(object, _.isNumber);
13575      * // => { 'a': 1, 'c': 3 }
13576      */
13577     function pickBy(object, predicate) {
13578       if (object == null) {
13579         return {};
13580       }
13581       var props = arrayMap(getAllKeysIn(object), function(prop) {
13582         return [prop];
13583       });
13584       predicate = getIteratee(predicate);
13585       return basePickBy(object, props, function(value, path) {
13586         return predicate(value, path[0]);
13587       });
13588     }
13589
13590     /**
13591      * This method is like `_.get` except that if the resolved value is a
13592      * function it's invoked with the `this` binding of its parent object and
13593      * its result is returned.
13594      *
13595      * @static
13596      * @since 0.1.0
13597      * @memberOf _
13598      * @category Object
13599      * @param {Object} object The object to query.
13600      * @param {Array|string} path The path of the property to resolve.
13601      * @param {*} [defaultValue] The value returned for `undefined` resolved values.
13602      * @returns {*} Returns the resolved value.
13603      * @example
13604      *
13605      * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
13606      *
13607      * _.result(object, 'a[0].b.c1');
13608      * // => 3
13609      *
13610      * _.result(object, 'a[0].b.c2');
13611      * // => 4
13612      *
13613      * _.result(object, 'a[0].b.c3', 'default');
13614      * // => 'default'
13615      *
13616      * _.result(object, 'a[0].b.c3', _.constant('default'));
13617      * // => 'default'
13618      */
13619     function result(object, path, defaultValue) {
13620       path = castPath(path, object);
13621
13622       var index = -1,
13623           length = path.length;
13624
13625       // Ensure the loop is entered when path is empty.
13626       if (!length) {
13627         length = 1;
13628         object = undefined;
13629       }
13630       while (++index < length) {
13631         var value = object == null ? undefined : object[toKey(path[index])];
13632         if (value === undefined) {
13633           index = length;
13634           value = defaultValue;
13635         }
13636         object = isFunction(value) ? value.call(object) : value;
13637       }
13638       return object;
13639     }
13640
13641     /**
13642      * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
13643      * it's created. Arrays are created for missing index properties while objects
13644      * are created for all other missing properties. Use `_.setWith` to customize
13645      * `path` creation.
13646      *
13647      * **Note:** This method mutates `object`.
13648      *
13649      * @static
13650      * @memberOf _
13651      * @since 3.7.0
13652      * @category Object
13653      * @param {Object} object The object to modify.
13654      * @param {Array|string} path The path of the property to set.
13655      * @param {*} value The value to set.
13656      * @returns {Object} Returns `object`.
13657      * @example
13658      *
13659      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13660      *
13661      * _.set(object, 'a[0].b.c', 4);
13662      * console.log(object.a[0].b.c);
13663      * // => 4
13664      *
13665      * _.set(object, ['x', '0', 'y', 'z'], 5);
13666      * console.log(object.x[0].y.z);
13667      * // => 5
13668      */
13669     function set(object, path, value) {
13670       return object == null ? object : baseSet(object, path, value);
13671     }
13672
13673     /**
13674      * This method is like `_.set` except that it accepts `customizer` which is
13675      * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
13676      * path creation is handled by the method instead. The `customizer` is invoked
13677      * with three arguments: (nsValue, key, nsObject).
13678      *
13679      * **Note:** This method mutates `object`.
13680      *
13681      * @static
13682      * @memberOf _
13683      * @since 4.0.0
13684      * @category Object
13685      * @param {Object} object The object to modify.
13686      * @param {Array|string} path The path of the property to set.
13687      * @param {*} value The value to set.
13688      * @param {Function} [customizer] The function to customize assigned values.
13689      * @returns {Object} Returns `object`.
13690      * @example
13691      *
13692      * var object = {};
13693      *
13694      * _.setWith(object, '[0][1]', 'a', Object);
13695      * // => { '0': { '1': 'a' } }
13696      */
13697     function setWith(object, path, value, customizer) {
13698       customizer = typeof customizer == 'function' ? customizer : undefined;
13699       return object == null ? object : baseSet(object, path, value, customizer);
13700     }
13701
13702     /**
13703      * Creates an array of own enumerable string keyed-value pairs for `object`
13704      * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
13705      * entries are returned.
13706      *
13707      * @static
13708      * @memberOf _
13709      * @since 4.0.0
13710      * @alias entries
13711      * @category Object
13712      * @param {Object} object The object to query.
13713      * @returns {Array} Returns the key-value pairs.
13714      * @example
13715      *
13716      * function Foo() {
13717      *   this.a = 1;
13718      *   this.b = 2;
13719      * }
13720      *
13721      * Foo.prototype.c = 3;
13722      *
13723      * _.toPairs(new Foo);
13724      * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
13725      */
13726     var toPairs = createToPairs(keys);
13727
13728     /**
13729      * Creates an array of own and inherited enumerable string keyed-value pairs
13730      * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
13731      * or set, its entries are returned.
13732      *
13733      * @static
13734      * @memberOf _
13735      * @since 4.0.0
13736      * @alias entriesIn
13737      * @category Object
13738      * @param {Object} object The object to query.
13739      * @returns {Array} Returns the key-value pairs.
13740      * @example
13741      *
13742      * function Foo() {
13743      *   this.a = 1;
13744      *   this.b = 2;
13745      * }
13746      *
13747      * Foo.prototype.c = 3;
13748      *
13749      * _.toPairsIn(new Foo);
13750      * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
13751      */
13752     var toPairsIn = createToPairs(keysIn);
13753
13754     /**
13755      * An alternative to `_.reduce`; this method transforms `object` to a new
13756      * `accumulator` object which is the result of running each of its own
13757      * enumerable string keyed properties thru `iteratee`, with each invocation
13758      * potentially mutating the `accumulator` object. If `accumulator` is not
13759      * provided, a new object with the same `[[Prototype]]` will be used. The
13760      * iteratee is invoked with four arguments: (accumulator, value, key, object).
13761      * Iteratee functions may exit iteration early by explicitly returning `false`.
13762      *
13763      * @static
13764      * @memberOf _
13765      * @since 1.3.0
13766      * @category Object
13767      * @param {Object} object The object to iterate over.
13768      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13769      * @param {*} [accumulator] The custom accumulator value.
13770      * @returns {*} Returns the accumulated value.
13771      * @example
13772      *
13773      * _.transform([2, 3, 4], function(result, n) {
13774      *   result.push(n *= n);
13775      *   return n % 2 == 0;
13776      * }, []);
13777      * // => [4, 9]
13778      *
13779      * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
13780      *   (result[value] || (result[value] = [])).push(key);
13781      * }, {});
13782      * // => { '1': ['a', 'c'], '2': ['b'] }
13783      */
13784     function transform(object, iteratee, accumulator) {
13785       var isArr = isArray(object),
13786           isArrLike = isArr || isBuffer(object) || isTypedArray(object);
13787
13788       iteratee = getIteratee(iteratee, 4);
13789       if (accumulator == null) {
13790         var Ctor = object && object.constructor;
13791         if (isArrLike) {
13792           accumulator = isArr ? new Ctor : [];
13793         }
13794         else if (isObject(object)) {
13795           accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
13796         }
13797         else {
13798           accumulator = {};
13799         }
13800       }
13801       (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) {
13802         return iteratee(accumulator, value, index, object);
13803       });
13804       return accumulator;
13805     }
13806
13807     /**
13808      * Removes the property at `path` of `object`.
13809      *
13810      * **Note:** This method mutates `object`.
13811      *
13812      * @static
13813      * @memberOf _
13814      * @since 4.0.0
13815      * @category Object
13816      * @param {Object} object The object to modify.
13817      * @param {Array|string} path The path of the property to unset.
13818      * @returns {boolean} Returns `true` if the property is deleted, else `false`.
13819      * @example
13820      *
13821      * var object = { 'a': [{ 'b': { 'c': 7 } }] };
13822      * _.unset(object, 'a[0].b.c');
13823      * // => true
13824      *
13825      * console.log(object);
13826      * // => { 'a': [{ 'b': {} }] };
13827      *
13828      * _.unset(object, ['a', '0', 'b', 'c']);
13829      * // => true
13830      *
13831      * console.log(object);
13832      * // => { 'a': [{ 'b': {} }] };
13833      */
13834     function unset(object, path) {
13835       return object == null ? true : baseUnset(object, path);
13836     }
13837
13838     /**
13839      * This method is like `_.set` except that accepts `updater` to produce the
13840      * value to set. Use `_.updateWith` to customize `path` creation. The `updater`
13841      * is invoked with one argument: (value).
13842      *
13843      * **Note:** This method mutates `object`.
13844      *
13845      * @static
13846      * @memberOf _
13847      * @since 4.6.0
13848      * @category Object
13849      * @param {Object} object The object to modify.
13850      * @param {Array|string} path The path of the property to set.
13851      * @param {Function} updater The function to produce the updated value.
13852      * @returns {Object} Returns `object`.
13853      * @example
13854      *
13855      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13856      *
13857      * _.update(object, 'a[0].b.c', function(n) { return n * n; });
13858      * console.log(object.a[0].b.c);
13859      * // => 9
13860      *
13861      * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
13862      * console.log(object.x[0].y.z);
13863      * // => 0
13864      */
13865     function update(object, path, updater) {
13866       return object == null ? object : baseUpdate(object, path, castFunction(updater));
13867     }
13868
13869     /**
13870      * This method is like `_.update` except that it accepts `customizer` which is
13871      * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
13872      * path creation is handled by the method instead. The `customizer` is invoked
13873      * with three arguments: (nsValue, key, nsObject).
13874      *
13875      * **Note:** This method mutates `object`.
13876      *
13877      * @static
13878      * @memberOf _
13879      * @since 4.6.0
13880      * @category Object
13881      * @param {Object} object The object to modify.
13882      * @param {Array|string} path The path of the property to set.
13883      * @param {Function} updater The function to produce the updated value.
13884      * @param {Function} [customizer] The function to customize assigned values.
13885      * @returns {Object} Returns `object`.
13886      * @example
13887      *
13888      * var object = {};
13889      *
13890      * _.updateWith(object, '[0][1]', _.constant('a'), Object);
13891      * // => { '0': { '1': 'a' } }
13892      */
13893     function updateWith(object, path, updater, customizer) {
13894       customizer = typeof customizer == 'function' ? customizer : undefined;
13895       return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
13896     }
13897
13898     /**
13899      * Creates an array of the own enumerable string keyed property values of `object`.
13900      *
13901      * **Note:** Non-object values are coerced to objects.
13902      *
13903      * @static
13904      * @since 0.1.0
13905      * @memberOf _
13906      * @category Object
13907      * @param {Object} object The object to query.
13908      * @returns {Array} Returns the array of property values.
13909      * @example
13910      *
13911      * function Foo() {
13912      *   this.a = 1;
13913      *   this.b = 2;
13914      * }
13915      *
13916      * Foo.prototype.c = 3;
13917      *
13918      * _.values(new Foo);
13919      * // => [1, 2] (iteration order is not guaranteed)
13920      *
13921      * _.values('hi');
13922      * // => ['h', 'i']
13923      */
13924     function values(object) {
13925       return object == null ? [] : baseValues(object, keys(object));
13926     }
13927
13928     /**
13929      * Creates an array of the own and inherited enumerable string keyed property
13930      * values of `object`.
13931      *
13932      * **Note:** Non-object values are coerced to objects.
13933      *
13934      * @static
13935      * @memberOf _
13936      * @since 3.0.0
13937      * @category Object
13938      * @param {Object} object The object to query.
13939      * @returns {Array} Returns the array of property values.
13940      * @example
13941      *
13942      * function Foo() {
13943      *   this.a = 1;
13944      *   this.b = 2;
13945      * }
13946      *
13947      * Foo.prototype.c = 3;
13948      *
13949      * _.valuesIn(new Foo);
13950      * // => [1, 2, 3] (iteration order is not guaranteed)
13951      */
13952     function valuesIn(object) {
13953       return object == null ? [] : baseValues(object, keysIn(object));
13954     }
13955
13956     /*------------------------------------------------------------------------*/
13957
13958     /**
13959      * Clamps `number` within the inclusive `lower` and `upper` bounds.
13960      *
13961      * @static
13962      * @memberOf _
13963      * @since 4.0.0
13964      * @category Number
13965      * @param {number} number The number to clamp.
13966      * @param {number} [lower] The lower bound.
13967      * @param {number} upper The upper bound.
13968      * @returns {number} Returns the clamped number.
13969      * @example
13970      *
13971      * _.clamp(-10, -5, 5);
13972      * // => -5
13973      *
13974      * _.clamp(10, -5, 5);
13975      * // => 5
13976      */
13977     function clamp(number, lower, upper) {
13978       if (upper === undefined) {
13979         upper = lower;
13980         lower = undefined;
13981       }
13982       if (upper !== undefined) {
13983         upper = toNumber(upper);
13984         upper = upper === upper ? upper : 0;
13985       }
13986       if (lower !== undefined) {
13987         lower = toNumber(lower);
13988         lower = lower === lower ? lower : 0;
13989       }
13990       return baseClamp(toNumber(number), lower, upper);
13991     }
13992
13993     /**
13994      * Checks if `n` is between `start` and up to, but not including, `end`. If
13995      * `end` is not specified, it's set to `start` with `start` then set to `0`.
13996      * If `start` is greater than `end` the params are swapped to support
13997      * negative ranges.
13998      *
13999      * @static
14000      * @memberOf _
14001      * @since 3.3.0
14002      * @category Number
14003      * @param {number} number The number to check.
14004      * @param {number} [start=0] The start of the range.
14005      * @param {number} end The end of the range.
14006      * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
14007      * @see _.range, _.rangeRight
14008      * @example
14009      *
14010      * _.inRange(3, 2, 4);
14011      * // => true
14012      *
14013      * _.inRange(4, 8);
14014      * // => true
14015      *
14016      * _.inRange(4, 2);
14017      * // => false
14018      *
14019      * _.inRange(2, 2);
14020      * // => false
14021      *
14022      * _.inRange(1.2, 2);
14023      * // => true
14024      *
14025      * _.inRange(5.2, 4);
14026      * // => false
14027      *
14028      * _.inRange(-3, -2, -6);
14029      * // => true
14030      */
14031     function inRange(number, start, end) {
14032       start = toFinite(start);
14033       if (end === undefined) {
14034         end = start;
14035         start = 0;
14036       } else {
14037         end = toFinite(end);
14038       }
14039       number = toNumber(number);
14040       return baseInRange(number, start, end);
14041     }
14042
14043     /**
14044      * Produces a random number between the inclusive `lower` and `upper` bounds.
14045      * If only one argument is provided a number between `0` and the given number
14046      * is returned. If `floating` is `true`, or either `lower` or `upper` are
14047      * floats, a floating-point number is returned instead of an integer.
14048      *
14049      * **Note:** JavaScript follows the IEEE-754 standard for resolving
14050      * floating-point values which can produce unexpected results.
14051      *
14052      * @static
14053      * @memberOf _
14054      * @since 0.7.0
14055      * @category Number
14056      * @param {number} [lower=0] The lower bound.
14057      * @param {number} [upper=1] The upper bound.
14058      * @param {boolean} [floating] Specify returning a floating-point number.
14059      * @returns {number} Returns the random number.
14060      * @example
14061      *
14062      * _.random(0, 5);
14063      * // => an integer between 0 and 5
14064      *
14065      * _.random(5);
14066      * // => also an integer between 0 and 5
14067      *
14068      * _.random(5, true);
14069      * // => a floating-point number between 0 and 5
14070      *
14071      * _.random(1.2, 5.2);
14072      * // => a floating-point number between 1.2 and 5.2
14073      */
14074     function random(lower, upper, floating) {
14075       if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
14076         upper = floating = undefined;
14077       }
14078       if (floating === undefined) {
14079         if (typeof upper == 'boolean') {
14080           floating = upper;
14081           upper = undefined;
14082         }
14083         else if (typeof lower == 'boolean') {
14084           floating = lower;
14085           lower = undefined;
14086         }
14087       }
14088       if (lower === undefined && upper === undefined) {
14089         lower = 0;
14090         upper = 1;
14091       }
14092       else {
14093         lower = toFinite(lower);
14094         if (upper === undefined) {
14095           upper = lower;
14096           lower = 0;
14097         } else {
14098           upper = toFinite(upper);
14099         }
14100       }
14101       if (lower > upper) {
14102         var temp = lower;
14103         lower = upper;
14104         upper = temp;
14105       }
14106       if (floating || lower % 1 || upper % 1) {
14107         var rand = nativeRandom();
14108         return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);
14109       }
14110       return baseRandom(lower, upper);
14111     }
14112
14113     /*------------------------------------------------------------------------*/
14114
14115     /**
14116      * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
14117      *
14118      * @static
14119      * @memberOf _
14120      * @since 3.0.0
14121      * @category String
14122      * @param {string} [string=''] The string to convert.
14123      * @returns {string} Returns the camel cased string.
14124      * @example
14125      *
14126      * _.camelCase('Foo Bar');
14127      * // => 'fooBar'
14128      *
14129      * _.camelCase('--foo-bar--');
14130      * // => 'fooBar'
14131      *
14132      * _.camelCase('__FOO_BAR__');
14133      * // => 'fooBar'
14134      */
14135     var camelCase = createCompounder(function(result, word, index) {
14136       word = word.toLowerCase();
14137       return result + (index ? capitalize(word) : word);
14138     });
14139
14140     /**
14141      * Converts the first character of `string` to upper case and the remaining
14142      * to lower case.
14143      *
14144      * @static
14145      * @memberOf _
14146      * @since 3.0.0
14147      * @category String
14148      * @param {string} [string=''] The string to capitalize.
14149      * @returns {string} Returns the capitalized string.
14150      * @example
14151      *
14152      * _.capitalize('FRED');
14153      * // => 'Fred'
14154      */
14155     function capitalize(string) {
14156       return upperFirst(toString(string).toLowerCase());
14157     }
14158
14159     /**
14160      * Deburrs `string` by converting
14161      * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
14162      * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
14163      * letters to basic Latin letters and removing
14164      * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
14165      *
14166      * @static
14167      * @memberOf _
14168      * @since 3.0.0
14169      * @category String
14170      * @param {string} [string=''] The string to deburr.
14171      * @returns {string} Returns the deburred string.
14172      * @example
14173      *
14174      * _.deburr('déjà vu');
14175      * // => 'deja vu'
14176      */
14177     function deburr(string) {
14178       string = toString(string);
14179       return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
14180     }
14181
14182     /**
14183      * Checks if `string` ends with the given target string.
14184      *
14185      * @static
14186      * @memberOf _
14187      * @since 3.0.0
14188      * @category String
14189      * @param {string} [string=''] The string to inspect.
14190      * @param {string} [target] The string to search for.
14191      * @param {number} [position=string.length] The position to search up to.
14192      * @returns {boolean} Returns `true` if `string` ends with `target`,
14193      *  else `false`.
14194      * @example
14195      *
14196      * _.endsWith('abc', 'c');
14197      * // => true
14198      *
14199      * _.endsWith('abc', 'b');
14200      * // => false
14201      *
14202      * _.endsWith('abc', 'b', 2);
14203      * // => true
14204      */
14205     function endsWith(string, target, position) {
14206       string = toString(string);
14207       target = baseToString(target);
14208
14209       var length = string.length;
14210       position = position === undefined
14211         ? length
14212         : baseClamp(toInteger(position), 0, length);
14213
14214       var end = position;
14215       position -= target.length;
14216       return position >= 0 && string.slice(position, end) == target;
14217     }
14218
14219     /**
14220      * Converts the characters "&", "<", ">", '"', and "'" in `string` to their
14221      * corresponding HTML entities.
14222      *
14223      * **Note:** No other characters are escaped. To escape additional
14224      * characters use a third-party library like [_he_](https://mths.be/he).
14225      *
14226      * Though the ">" character is escaped for symmetry, characters like
14227      * ">" and "/" don't need escaping in HTML and have no special meaning
14228      * unless they're part of a tag or unquoted attribute value. See
14229      * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
14230      * (under "semi-related fun fact") for more details.
14231      *
14232      * When working with HTML you should always
14233      * [quote attribute values](http://wonko.com/post/html-escaping) to reduce
14234      * XSS vectors.
14235      *
14236      * @static
14237      * @since 0.1.0
14238      * @memberOf _
14239      * @category String
14240      * @param {string} [string=''] The string to escape.
14241      * @returns {string} Returns the escaped string.
14242      * @example
14243      *
14244      * _.escape('fred, barney, & pebbles');
14245      * // => 'fred, barney, &amp; pebbles'
14246      */
14247     function escape(string) {
14248       string = toString(string);
14249       return (string && reHasUnescapedHtml.test(string))
14250         ? string.replace(reUnescapedHtml, escapeHtmlChar)
14251         : string;
14252     }
14253
14254     /**
14255      * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
14256      * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
14257      *
14258      * @static
14259      * @memberOf _
14260      * @since 3.0.0
14261      * @category String
14262      * @param {string} [string=''] The string to escape.
14263      * @returns {string} Returns the escaped string.
14264      * @example
14265      *
14266      * _.escapeRegExp('[lodash](https://lodash.com/)');
14267      * // => '\[lodash\]\(https://lodash\.com/\)'
14268      */
14269     function escapeRegExp(string) {
14270       string = toString(string);
14271       return (string && reHasRegExpChar.test(string))
14272         ? string.replace(reRegExpChar, '\\$&')
14273         : string;
14274     }
14275
14276     /**
14277      * Converts `string` to
14278      * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
14279      *
14280      * @static
14281      * @memberOf _
14282      * @since 3.0.0
14283      * @category String
14284      * @param {string} [string=''] The string to convert.
14285      * @returns {string} Returns the kebab cased string.
14286      * @example
14287      *
14288      * _.kebabCase('Foo Bar');
14289      * // => 'foo-bar'
14290      *
14291      * _.kebabCase('fooBar');
14292      * // => 'foo-bar'
14293      *
14294      * _.kebabCase('__FOO_BAR__');
14295      * // => 'foo-bar'
14296      */
14297     var kebabCase = createCompounder(function(result, word, index) {
14298       return result + (index ? '-' : '') + word.toLowerCase();
14299     });
14300
14301     /**
14302      * Converts `string`, as space separated words, to lower case.
14303      *
14304      * @static
14305      * @memberOf _
14306      * @since 4.0.0
14307      * @category String
14308      * @param {string} [string=''] The string to convert.
14309      * @returns {string} Returns the lower cased string.
14310      * @example
14311      *
14312      * _.lowerCase('--Foo-Bar--');
14313      * // => 'foo bar'
14314      *
14315      * _.lowerCase('fooBar');
14316      * // => 'foo bar'
14317      *
14318      * _.lowerCase('__FOO_BAR__');
14319      * // => 'foo bar'
14320      */
14321     var lowerCase = createCompounder(function(result, word, index) {
14322       return result + (index ? ' ' : '') + word.toLowerCase();
14323     });
14324
14325     /**
14326      * Converts the first character of `string` to lower case.
14327      *
14328      * @static
14329      * @memberOf _
14330      * @since 4.0.0
14331      * @category String
14332      * @param {string} [string=''] The string to convert.
14333      * @returns {string} Returns the converted string.
14334      * @example
14335      *
14336      * _.lowerFirst('Fred');
14337      * // => 'fred'
14338      *
14339      * _.lowerFirst('FRED');
14340      * // => 'fRED'
14341      */
14342     var lowerFirst = createCaseFirst('toLowerCase');
14343
14344     /**
14345      * Pads `string` on the left and right sides if it's shorter than `length`.
14346      * Padding characters are truncated if they can't be evenly divided by `length`.
14347      *
14348      * @static
14349      * @memberOf _
14350      * @since 3.0.0
14351      * @category String
14352      * @param {string} [string=''] The string to pad.
14353      * @param {number} [length=0] The padding length.
14354      * @param {string} [chars=' '] The string used as padding.
14355      * @returns {string} Returns the padded string.
14356      * @example
14357      *
14358      * _.pad('abc', 8);
14359      * // => '  abc   '
14360      *
14361      * _.pad('abc', 8, '_-');
14362      * // => '_-abc_-_'
14363      *
14364      * _.pad('abc', 3);
14365      * // => 'abc'
14366      */
14367     function pad(string, length, chars) {
14368       string = toString(string);
14369       length = toInteger(length);
14370
14371       var strLength = length ? stringSize(string) : 0;
14372       if (!length || strLength >= length) {
14373         return string;
14374       }
14375       var mid = (length - strLength) / 2;
14376       return (
14377         createPadding(nativeFloor(mid), chars) +
14378         string +
14379         createPadding(nativeCeil(mid), chars)
14380       );
14381     }
14382
14383     /**
14384      * Pads `string` on the right side if it's shorter than `length`. Padding
14385      * characters are truncated if they exceed `length`.
14386      *
14387      * @static
14388      * @memberOf _
14389      * @since 4.0.0
14390      * @category String
14391      * @param {string} [string=''] The string to pad.
14392      * @param {number} [length=0] The padding length.
14393      * @param {string} [chars=' '] The string used as padding.
14394      * @returns {string} Returns the padded string.
14395      * @example
14396      *
14397      * _.padEnd('abc', 6);
14398      * // => 'abc   '
14399      *
14400      * _.padEnd('abc', 6, '_-');
14401      * // => 'abc_-_'
14402      *
14403      * _.padEnd('abc', 3);
14404      * // => 'abc'
14405      */
14406     function padEnd(string, length, chars) {
14407       string = toString(string);
14408       length = toInteger(length);
14409
14410       var strLength = length ? stringSize(string) : 0;
14411       return (length && strLength < length)
14412         ? (string + createPadding(length - strLength, chars))
14413         : string;
14414     }
14415
14416     /**
14417      * Pads `string` on the left side if it's shorter than `length`. Padding
14418      * characters are truncated if they exceed `length`.
14419      *
14420      * @static
14421      * @memberOf _
14422      * @since 4.0.0
14423      * @category String
14424      * @param {string} [string=''] The string to pad.
14425      * @param {number} [length=0] The padding length.
14426      * @param {string} [chars=' '] The string used as padding.
14427      * @returns {string} Returns the padded string.
14428      * @example
14429      *
14430      * _.padStart('abc', 6);
14431      * // => '   abc'
14432      *
14433      * _.padStart('abc', 6, '_-');
14434      * // => '_-_abc'
14435      *
14436      * _.padStart('abc', 3);
14437      * // => 'abc'
14438      */
14439     function padStart(string, length, chars) {
14440       string = toString(string);
14441       length = toInteger(length);
14442
14443       var strLength = length ? stringSize(string) : 0;
14444       return (length && strLength < length)
14445         ? (createPadding(length - strLength, chars) + string)
14446         : string;
14447     }
14448
14449     /**
14450      * Converts `string` to an integer of the specified radix. If `radix` is
14451      * `undefined` or `0`, a `radix` of `10` is used unless `value` is a
14452      * hexadecimal, in which case a `radix` of `16` is used.
14453      *
14454      * **Note:** This method aligns with the
14455      * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
14456      *
14457      * @static
14458      * @memberOf _
14459      * @since 1.1.0
14460      * @category String
14461      * @param {string} string The string to convert.
14462      * @param {number} [radix=10] The radix to interpret `value` by.
14463      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14464      * @returns {number} Returns the converted integer.
14465      * @example
14466      *
14467      * _.parseInt('08');
14468      * // => 8
14469      *
14470      * _.map(['6', '08', '10'], _.parseInt);
14471      * // => [6, 8, 10]
14472      */
14473     function parseInt(string, radix, guard) {
14474       if (guard || radix == null) {
14475         radix = 0;
14476       } else if (radix) {
14477         radix = +radix;
14478       }
14479       return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);
14480     }
14481
14482     /**
14483      * Repeats the given string `n` times.
14484      *
14485      * @static
14486      * @memberOf _
14487      * @since 3.0.0
14488      * @category String
14489      * @param {string} [string=''] The string to repeat.
14490      * @param {number} [n=1] The number of times to repeat the string.
14491      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14492      * @returns {string} Returns the repeated string.
14493      * @example
14494      *
14495      * _.repeat('*', 3);
14496      * // => '***'
14497      *
14498      * _.repeat('abc', 2);
14499      * // => 'abcabc'
14500      *
14501      * _.repeat('abc', 0);
14502      * // => ''
14503      */
14504     function repeat(string, n, guard) {
14505       if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {
14506         n = 1;
14507       } else {
14508         n = toInteger(n);
14509       }
14510       return baseRepeat(toString(string), n);
14511     }
14512
14513     /**
14514      * Replaces matches for `pattern` in `string` with `replacement`.
14515      *
14516      * **Note:** This method is based on
14517      * [`String#replace`](https://mdn.io/String/replace).
14518      *
14519      * @static
14520      * @memberOf _
14521      * @since 4.0.0
14522      * @category String
14523      * @param {string} [string=''] The string to modify.
14524      * @param {RegExp|string} pattern The pattern to replace.
14525      * @param {Function|string} replacement The match replacement.
14526      * @returns {string} Returns the modified string.
14527      * @example
14528      *
14529      * _.replace('Hi Fred', 'Fred', 'Barney');
14530      * // => 'Hi Barney'
14531      */
14532     function replace() {
14533       var args = arguments,
14534           string = toString(args[0]);
14535
14536       return args.length < 3 ? string : string.replace(args[1], args[2]);
14537     }
14538
14539     /**
14540      * Converts `string` to
14541      * [snake case](https://en.wikipedia.org/wiki/Snake_case).
14542      *
14543      * @static
14544      * @memberOf _
14545      * @since 3.0.0
14546      * @category String
14547      * @param {string} [string=''] The string to convert.
14548      * @returns {string} Returns the snake cased string.
14549      * @example
14550      *
14551      * _.snakeCase('Foo Bar');
14552      * // => 'foo_bar'
14553      *
14554      * _.snakeCase('fooBar');
14555      * // => 'foo_bar'
14556      *
14557      * _.snakeCase('--FOO-BAR--');
14558      * // => 'foo_bar'
14559      */
14560     var snakeCase = createCompounder(function(result, word, index) {
14561       return result + (index ? '_' : '') + word.toLowerCase();
14562     });
14563
14564     /**
14565      * Splits `string` by `separator`.
14566      *
14567      * **Note:** This method is based on
14568      * [`String#split`](https://mdn.io/String/split).
14569      *
14570      * @static
14571      * @memberOf _
14572      * @since 4.0.0
14573      * @category String
14574      * @param {string} [string=''] The string to split.
14575      * @param {RegExp|string} separator The separator pattern to split by.
14576      * @param {number} [limit] The length to truncate results to.
14577      * @returns {Array} Returns the string segments.
14578      * @example
14579      *
14580      * _.split('a-b-c', '-', 2);
14581      * // => ['a', 'b']
14582      */
14583     function split(string, separator, limit) {
14584       if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
14585         separator = limit = undefined;
14586       }
14587       limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
14588       if (!limit) {
14589         return [];
14590       }
14591       string = toString(string);
14592       if (string && (
14593             typeof separator == 'string' ||
14594             (separator != null && !isRegExp(separator))
14595           )) {
14596         separator = baseToString(separator);
14597         if (!separator && hasUnicode(string)) {
14598           return castSlice(stringToArray(string), 0, limit);
14599         }
14600       }
14601       return string.split(separator, limit);
14602     }
14603
14604     /**
14605      * Converts `string` to
14606      * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
14607      *
14608      * @static
14609      * @memberOf _
14610      * @since 3.1.0
14611      * @category String
14612      * @param {string} [string=''] The string to convert.
14613      * @returns {string} Returns the start cased string.
14614      * @example
14615      *
14616      * _.startCase('--foo-bar--');
14617      * // => 'Foo Bar'
14618      *
14619      * _.startCase('fooBar');
14620      * // => 'Foo Bar'
14621      *
14622      * _.startCase('__FOO_BAR__');
14623      * // => 'FOO BAR'
14624      */
14625     var startCase = createCompounder(function(result, word, index) {
14626       return result + (index ? ' ' : '') + upperFirst(word);
14627     });
14628
14629     /**
14630      * Checks if `string` starts with the given target string.
14631      *
14632      * @static
14633      * @memberOf _
14634      * @since 3.0.0
14635      * @category String
14636      * @param {string} [string=''] The string to inspect.
14637      * @param {string} [target] The string to search for.
14638      * @param {number} [position=0] The position to search from.
14639      * @returns {boolean} Returns `true` if `string` starts with `target`,
14640      *  else `false`.
14641      * @example
14642      *
14643      * _.startsWith('abc', 'a');
14644      * // => true
14645      *
14646      * _.startsWith('abc', 'b');
14647      * // => false
14648      *
14649      * _.startsWith('abc', 'b', 1);
14650      * // => true
14651      */
14652     function startsWith(string, target, position) {
14653       string = toString(string);
14654       position = position == null
14655         ? 0
14656         : baseClamp(toInteger(position), 0, string.length);
14657
14658       target = baseToString(target);
14659       return string.slice(position, position + target.length) == target;
14660     }
14661
14662     /**
14663      * Creates a compiled template function that can interpolate data properties
14664      * in "interpolate" delimiters, HTML-escape interpolated data properties in
14665      * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
14666      * properties may be accessed as free variables in the template. If a setting
14667      * object is given, it takes precedence over `_.templateSettings` values.
14668      *
14669      * **Note:** In the development build `_.template` utilizes
14670      * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
14671      * for easier debugging.
14672      *
14673      * For more information on precompiling templates see
14674      * [lodash's custom builds documentation](https://lodash.com/custom-builds).
14675      *
14676      * For more information on Chrome extension sandboxes see
14677      * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
14678      *
14679      * @static
14680      * @since 0.1.0
14681      * @memberOf _
14682      * @category String
14683      * @param {string} [string=''] The template string.
14684      * @param {Object} [options={}] The options object.
14685      * @param {RegExp} [options.escape=_.templateSettings.escape]
14686      *  The HTML "escape" delimiter.
14687      * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
14688      *  The "evaluate" delimiter.
14689      * @param {Object} [options.imports=_.templateSettings.imports]
14690      *  An object to import into the template as free variables.
14691      * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
14692      *  The "interpolate" delimiter.
14693      * @param {string} [options.sourceURL='lodash.templateSources[n]']
14694      *  The sourceURL of the compiled template.
14695      * @param {string} [options.variable='obj']
14696      *  The data object variable name.
14697      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14698      * @returns {Function} Returns the compiled template function.
14699      * @example
14700      *
14701      * // Use the "interpolate" delimiter to create a compiled template.
14702      * var compiled = _.template('hello <%= user %>!');
14703      * compiled({ 'user': 'fred' });
14704      * // => 'hello fred!'
14705      *
14706      * // Use the HTML "escape" delimiter to escape data property values.
14707      * var compiled = _.template('<b><%- value %></b>');
14708      * compiled({ 'value': '<script>' });
14709      * // => '<b>&lt;script&gt;</b>'
14710      *
14711      * // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
14712      * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
14713      * compiled({ 'users': ['fred', 'barney'] });
14714      * // => '<li>fred</li><li>barney</li>'
14715      *
14716      * // Use the internal `print` function in "evaluate" delimiters.
14717      * var compiled = _.template('<% print("hello " + user); %>!');
14718      * compiled({ 'user': 'barney' });
14719      * // => 'hello barney!'
14720      *
14721      * // Use the ES template literal delimiter as an "interpolate" delimiter.
14722      * // Disable support by replacing the "interpolate" delimiter.
14723      * var compiled = _.template('hello ${ user }!');
14724      * compiled({ 'user': 'pebbles' });
14725      * // => 'hello pebbles!'
14726      *
14727      * // Use backslashes to treat delimiters as plain text.
14728      * var compiled = _.template('<%= "\\<%- value %\\>" %>');
14729      * compiled({ 'value': 'ignored' });
14730      * // => '<%- value %>'
14731      *
14732      * // Use the `imports` option to import `jQuery` as `jq`.
14733      * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
14734      * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
14735      * compiled({ 'users': ['fred', 'barney'] });
14736      * // => '<li>fred</li><li>barney</li>'
14737      *
14738      * // Use the `sourceURL` option to specify a custom sourceURL for the template.
14739      * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
14740      * compiled(data);
14741      * // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
14742      *
14743      * // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
14744      * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
14745      * compiled.source;
14746      * // => function(data) {
14747      * //   var __t, __p = '';
14748      * //   __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
14749      * //   return __p;
14750      * // }
14751      *
14752      * // Use custom template delimiters.
14753      * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
14754      * var compiled = _.template('hello {{ user }}!');
14755      * compiled({ 'user': 'mustache' });
14756      * // => 'hello mustache!'
14757      *
14758      * // Use the `source` property to inline compiled templates for meaningful
14759      * // line numbers in error messages and stack traces.
14760      * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
14761      *   var JST = {\
14762      *     "main": ' + _.template(mainText).source + '\
14763      *   };\
14764      * ');
14765      */
14766     function template(string, options, guard) {
14767       // Based on John Resig's `tmpl` implementation
14768       // (http://ejohn.org/blog/javascript-micro-templating/)
14769       // and Laura Doktorova's doT.js (https://github.com/olado/doT).
14770       var settings = lodash.templateSettings;
14771
14772       if (guard && isIterateeCall(string, options, guard)) {
14773         options = undefined;
14774       }
14775       string = toString(string);
14776       options = assignInWith({}, options, settings, customDefaultsAssignIn);
14777
14778       var imports = assignInWith({}, options.imports, settings.imports, customDefaultsAssignIn),
14779           importsKeys = keys(imports),
14780           importsValues = baseValues(imports, importsKeys);
14781
14782       var isEscaping,
14783           isEvaluating,
14784           index = 0,
14785           interpolate = options.interpolate || reNoMatch,
14786           source = "__p += '";
14787
14788       // Compile the regexp to match each delimiter.
14789       var reDelimiters = RegExp(
14790         (options.escape || reNoMatch).source + '|' +
14791         interpolate.source + '|' +
14792         (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
14793         (options.evaluate || reNoMatch).source + '|$'
14794       , 'g');
14795
14796       // Use a sourceURL for easier debugging.
14797       var sourceURL = '//# sourceURL=' +
14798         ('sourceURL' in options
14799           ? options.sourceURL
14800           : ('lodash.templateSources[' + (++templateCounter) + ']')
14801         ) + '\n';
14802
14803       string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
14804         interpolateValue || (interpolateValue = esTemplateValue);
14805
14806         // Escape characters that can't be included in string literals.
14807         source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
14808
14809         // Replace delimiters with snippets.
14810         if (escapeValue) {
14811           isEscaping = true;
14812           source += "' +\n__e(" + escapeValue + ") +\n'";
14813         }
14814         if (evaluateValue) {
14815           isEvaluating = true;
14816           source += "';\n" + evaluateValue + ";\n__p += '";
14817         }
14818         if (interpolateValue) {
14819           source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
14820         }
14821         index = offset + match.length;
14822
14823         // The JS engine embedded in Adobe products needs `match` returned in
14824         // order to produce the correct `offset` value.
14825         return match;
14826       });
14827
14828       source += "';\n";
14829
14830       // If `variable` is not specified wrap a with-statement around the generated
14831       // code to add the data object to the top of the scope chain.
14832       var variable = options.variable;
14833       if (!variable) {
14834         source = 'with (obj) {\n' + source + '\n}\n';
14835       }
14836       // Cleanup code by stripping empty strings.
14837       source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
14838         .replace(reEmptyStringMiddle, '$1')
14839         .replace(reEmptyStringTrailing, '$1;');
14840
14841       // Frame code as the function body.
14842       source = 'function(' + (variable || 'obj') + ') {\n' +
14843         (variable
14844           ? ''
14845           : 'obj || (obj = {});\n'
14846         ) +
14847         "var __t, __p = ''" +
14848         (isEscaping
14849            ? ', __e = _.escape'
14850            : ''
14851         ) +
14852         (isEvaluating
14853           ? ', __j = Array.prototype.join;\n' +
14854             "function print() { __p += __j.call(arguments, '') }\n"
14855           : ';\n'
14856         ) +
14857         source +
14858         'return __p\n}';
14859
14860       var result = attempt(function() {
14861         return Function(importsKeys, sourceURL + 'return ' + source)
14862           .apply(undefined, importsValues);
14863       });
14864
14865       // Provide the compiled function's source by its `toString` method or
14866       // the `source` property as a convenience for inlining compiled templates.
14867       result.source = source;
14868       if (isError(result)) {
14869         throw result;
14870       }
14871       return result;
14872     }
14873
14874     /**
14875      * Converts `string`, as a whole, to lower case just like
14876      * [String#toLowerCase](https://mdn.io/toLowerCase).
14877      *
14878      * @static
14879      * @memberOf _
14880      * @since 4.0.0
14881      * @category String
14882      * @param {string} [string=''] The string to convert.
14883      * @returns {string} Returns the lower cased string.
14884      * @example
14885      *
14886      * _.toLower('--Foo-Bar--');
14887      * // => '--foo-bar--'
14888      *
14889      * _.toLower('fooBar');
14890      * // => 'foobar'
14891      *
14892      * _.toLower('__FOO_BAR__');
14893      * // => '__foo_bar__'
14894      */
14895     function toLower(value) {
14896       return toString(value).toLowerCase();
14897     }
14898
14899     /**
14900      * Converts `string`, as a whole, to upper case just like
14901      * [String#toUpperCase](https://mdn.io/toUpperCase).
14902      *
14903      * @static
14904      * @memberOf _
14905      * @since 4.0.0
14906      * @category String
14907      * @param {string} [string=''] The string to convert.
14908      * @returns {string} Returns the upper cased string.
14909      * @example
14910      *
14911      * _.toUpper('--foo-bar--');
14912      * // => '--FOO-BAR--'
14913      *
14914      * _.toUpper('fooBar');
14915      * // => 'FOOBAR'
14916      *
14917      * _.toUpper('__foo_bar__');
14918      * // => '__FOO_BAR__'
14919      */
14920     function toUpper(value) {
14921       return toString(value).toUpperCase();
14922     }
14923
14924     /**
14925      * Removes leading and trailing whitespace or specified characters from `string`.
14926      *
14927      * @static
14928      * @memberOf _
14929      * @since 3.0.0
14930      * @category String
14931      * @param {string} [string=''] The string to trim.
14932      * @param {string} [chars=whitespace] The characters to trim.
14933      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14934      * @returns {string} Returns the trimmed string.
14935      * @example
14936      *
14937      * _.trim('  abc  ');
14938      * // => 'abc'
14939      *
14940      * _.trim('-_-abc-_-', '_-');
14941      * // => 'abc'
14942      *
14943      * _.map(['  foo  ', '  bar  '], _.trim);
14944      * // => ['foo', 'bar']
14945      */
14946     function trim(string, chars, guard) {
14947       string = toString(string);
14948       if (string && (guard || chars === undefined)) {
14949         return string.replace(reTrim, '');
14950       }
14951       if (!string || !(chars = baseToString(chars))) {
14952         return string;
14953       }
14954       var strSymbols = stringToArray(string),
14955           chrSymbols = stringToArray(chars),
14956           start = charsStartIndex(strSymbols, chrSymbols),
14957           end = charsEndIndex(strSymbols, chrSymbols) + 1;
14958
14959       return castSlice(strSymbols, start, end).join('');
14960     }
14961
14962     /**
14963      * Removes trailing whitespace or specified characters from `string`.
14964      *
14965      * @static
14966      * @memberOf _
14967      * @since 4.0.0
14968      * @category String
14969      * @param {string} [string=''] The string to trim.
14970      * @param {string} [chars=whitespace] The characters to trim.
14971      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14972      * @returns {string} Returns the trimmed string.
14973      * @example
14974      *
14975      * _.trimEnd('  abc  ');
14976      * // => '  abc'
14977      *
14978      * _.trimEnd('-_-abc-_-', '_-');
14979      * // => '-_-abc'
14980      */
14981     function trimEnd(string, chars, guard) {
14982       string = toString(string);
14983       if (string && (guard || chars === undefined)) {
14984         return string.replace(reTrimEnd, '');
14985       }
14986       if (!string || !(chars = baseToString(chars))) {
14987         return string;
14988       }
14989       var strSymbols = stringToArray(string),
14990           end = charsEndIndex(strSymbols, stringToArray(chars)) + 1;
14991
14992       return castSlice(strSymbols, 0, end).join('');
14993     }
14994
14995     /**
14996      * Removes leading whitespace or specified characters from `string`.
14997      *
14998      * @static
14999      * @memberOf _
15000      * @since 4.0.0
15001      * @category String
15002      * @param {string} [string=''] The string to trim.
15003      * @param {string} [chars=whitespace] The characters to trim.
15004      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
15005      * @returns {string} Returns the trimmed string.
15006      * @example
15007      *
15008      * _.trimStart('  abc  ');
15009      * // => 'abc  '
15010      *
15011      * _.trimStart('-_-abc-_-', '_-');
15012      * // => 'abc-_-'
15013      */
15014     function trimStart(string, chars, guard) {
15015       string = toString(string);
15016       if (string && (guard || chars === undefined)) {
15017         return string.replace(reTrimStart, '');
15018       }
15019       if (!string || !(chars = baseToString(chars))) {
15020         return string;
15021       }
15022       var strSymbols = stringToArray(string),
15023           start = charsStartIndex(strSymbols, stringToArray(chars));
15024
15025       return castSlice(strSymbols, start).join('');
15026     }
15027
15028     /**
15029      * Truncates `string` if it's longer than the given maximum string length.
15030      * The last characters of the truncated string are replaced with the omission
15031      * string which defaults to "...".
15032      *
15033      * @static
15034      * @memberOf _
15035      * @since 4.0.0
15036      * @category String
15037      * @param {string} [string=''] The string to truncate.
15038      * @param {Object} [options={}] The options object.
15039      * @param {number} [options.length=30] The maximum string length.
15040      * @param {string} [options.omission='...'] The string to indicate text is omitted.
15041      * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
15042      * @returns {string} Returns the truncated string.
15043      * @example
15044      *
15045      * _.truncate('hi-diddly-ho there, neighborino');
15046      * // => 'hi-diddly-ho there, neighbo...'
15047      *
15048      * _.truncate('hi-diddly-ho there, neighborino', {
15049      *   'length': 24,
15050      *   'separator': ' '
15051      * });
15052      * // => 'hi-diddly-ho there,...'
15053      *
15054      * _.truncate('hi-diddly-ho there, neighborino', {
15055      *   'length': 24,
15056      *   'separator': /,? +/
15057      * });
15058      * // => 'hi-diddly-ho there...'
15059      *
15060      * _.truncate('hi-diddly-ho there, neighborino', {
15061      *   'omission': ' [...]'
15062      * });
15063      * // => 'hi-diddly-ho there, neig [...]'
15064      */
15065     function truncate(string, options) {
15066       var length = DEFAULT_TRUNC_LENGTH,
15067           omission = DEFAULT_TRUNC_OMISSION;
15068
15069       if (isObject(options)) {
15070         var separator = 'separator' in options ? options.separator : separator;
15071         length = 'length' in options ? toInteger(options.length) : length;
15072         omission = 'omission' in options ? baseToString(options.omission) : omission;
15073       }
15074       string = toString(string);
15075
15076       var strLength = string.length;
15077       if (hasUnicode(string)) {
15078         var strSymbols = stringToArray(string);
15079         strLength = strSymbols.length;
15080       }
15081       if (length >= strLength) {
15082         return string;
15083       }
15084       var end = length - stringSize(omission);
15085       if (end < 1) {
15086         return omission;
15087       }
15088       var result = strSymbols
15089         ? castSlice(strSymbols, 0, end).join('')
15090         : string.slice(0, end);
15091
15092       if (separator === undefined) {
15093         return result + omission;
15094       }
15095       if (strSymbols) {
15096         end += (result.length - end);
15097       }
15098       if (isRegExp(separator)) {
15099         if (string.slice(end).search(separator)) {
15100           var match,
15101               substring = result;
15102
15103           if (!separator.global) {
15104             separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
15105           }
15106           separator.lastIndex = 0;
15107           while ((match = separator.exec(substring))) {
15108             var newEnd = match.index;
15109           }
15110           result = result.slice(0, newEnd === undefined ? end : newEnd);
15111         }
15112       } else if (string.indexOf(baseToString(separator), end) != end) {
15113         var index = result.lastIndexOf(separator);
15114         if (index > -1) {
15115           result = result.slice(0, index);
15116         }
15117       }
15118       return result + omission;
15119     }
15120
15121     /**
15122      * The inverse of `_.escape`; this method converts the HTML entities
15123      * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to
15124      * their corresponding characters.
15125      *
15126      * **Note:** No other HTML entities are unescaped. To unescape additional
15127      * HTML entities use a third-party library like [_he_](https://mths.be/he).
15128      *
15129      * @static
15130      * @memberOf _
15131      * @since 0.6.0
15132      * @category String
15133      * @param {string} [string=''] The string to unescape.
15134      * @returns {string} Returns the unescaped string.
15135      * @example
15136      *
15137      * _.unescape('fred, barney, &amp; pebbles');
15138      * // => 'fred, barney, & pebbles'
15139      */
15140     function unescape(string) {
15141       string = toString(string);
15142       return (string && reHasEscapedHtml.test(string))
15143         ? string.replace(reEscapedHtml, unescapeHtmlChar)
15144         : string;
15145     }
15146
15147     /**
15148      * Converts `string`, as space separated words, to upper case.
15149      *
15150      * @static
15151      * @memberOf _
15152      * @since 4.0.0
15153      * @category String
15154      * @param {string} [string=''] The string to convert.
15155      * @returns {string} Returns the upper cased string.
15156      * @example
15157      *
15158      * _.upperCase('--foo-bar');
15159      * // => 'FOO BAR'
15160      *
15161      * _.upperCase('fooBar');
15162      * // => 'FOO BAR'
15163      *
15164      * _.upperCase('__foo_bar__');
15165      * // => 'FOO BAR'
15166      */
15167     var upperCase = createCompounder(function(result, word, index) {
15168       return result + (index ? ' ' : '') + word.toUpperCase();
15169     });
15170
15171     /**
15172      * Converts the first character of `string` to upper case.
15173      *
15174      * @static
15175      * @memberOf _
15176      * @since 4.0.0
15177      * @category String
15178      * @param {string} [string=''] The string to convert.
15179      * @returns {string} Returns the converted string.
15180      * @example
15181      *
15182      * _.upperFirst('fred');
15183      * // => 'Fred'
15184      *
15185      * _.upperFirst('FRED');
15186      * // => 'FRED'
15187      */
15188     var upperFirst = createCaseFirst('toUpperCase');
15189
15190     /**
15191      * Splits `string` into an array of its words.
15192      *
15193      * @static
15194      * @memberOf _
15195      * @since 3.0.0
15196      * @category String
15197      * @param {string} [string=''] The string to inspect.
15198      * @param {RegExp|string} [pattern] The pattern to match words.
15199      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
15200      * @returns {Array} Returns the words of `string`.
15201      * @example
15202      *
15203      * _.words('fred, barney, & pebbles');
15204      * // => ['fred', 'barney', 'pebbles']
15205      *
15206      * _.words('fred, barney, & pebbles', /[^, ]+/g);
15207      * // => ['fred', 'barney', '&', 'pebbles']
15208      */
15209     function words(string, pattern, guard) {
15210       string = toString(string);
15211       pattern = guard ? undefined : pattern;
15212
15213       if (pattern === undefined) {
15214         return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
15215       }
15216       return string.match(pattern) || [];
15217     }
15218
15219     /*------------------------------------------------------------------------*/
15220
15221     /**
15222      * Attempts to invoke `func`, returning either the result or the caught error
15223      * object. Any additional arguments are provided to `func` when it's invoked.
15224      *
15225      * @static
15226      * @memberOf _
15227      * @since 3.0.0
15228      * @category Util
15229      * @param {Function} func The function to attempt.
15230      * @param {...*} [args] The arguments to invoke `func` with.
15231      * @returns {*} Returns the `func` result or error object.
15232      * @example
15233      *
15234      * // Avoid throwing errors for invalid selectors.
15235      * var elements = _.attempt(function(selector) {
15236      *   return document.querySelectorAll(selector);
15237      * }, '>_>');
15238      *
15239      * if (_.isError(elements)) {
15240      *   elements = [];
15241      * }
15242      */
15243     var attempt = baseRest(function(func, args) {
15244       try {
15245         return apply(func, undefined, args);
15246       } catch (e) {
15247         return isError(e) ? e : new Error(e);
15248       }
15249     });
15250
15251     /**
15252      * Binds methods of an object to the object itself, overwriting the existing
15253      * method.
15254      *
15255      * **Note:** This method doesn't set the "length" property of bound functions.
15256      *
15257      * @static
15258      * @since 0.1.0
15259      * @memberOf _
15260      * @category Util
15261      * @param {Object} object The object to bind and assign the bound methods to.
15262      * @param {...(string|string[])} methodNames The object method names to bind.
15263      * @returns {Object} Returns `object`.
15264      * @example
15265      *
15266      * var view = {
15267      *   'label': 'docs',
15268      *   'click': function() {
15269      *     console.log('clicked ' + this.label);
15270      *   }
15271      * };
15272      *
15273      * _.bindAll(view, ['click']);
15274      * jQuery(element).on('click', view.click);
15275      * // => Logs 'clicked docs' when clicked.
15276      */
15277     var bindAll = flatRest(function(object, methodNames) {
15278       arrayEach(methodNames, function(key) {
15279         key = toKey(key);
15280         baseAssignValue(object, key, bind(object[key], object));
15281       });
15282       return object;
15283     });
15284
15285     /**
15286      * Creates a function that iterates over `pairs` and invokes the corresponding
15287      * function of the first predicate to return truthy. The predicate-function
15288      * pairs are invoked with the `this` binding and arguments of the created
15289      * function.
15290      *
15291      * @static
15292      * @memberOf _
15293      * @since 4.0.0
15294      * @category Util
15295      * @param {Array} pairs The predicate-function pairs.
15296      * @returns {Function} Returns the new composite function.
15297      * @example
15298      *
15299      * var func = _.cond([
15300      *   [_.matches({ 'a': 1 }),           _.constant('matches A')],
15301      *   [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
15302      *   [_.stubTrue,                      _.constant('no match')]
15303      * ]);
15304      *
15305      * func({ 'a': 1, 'b': 2 });
15306      * // => 'matches A'
15307      *
15308      * func({ 'a': 0, 'b': 1 });
15309      * // => 'matches B'
15310      *
15311      * func({ 'a': '1', 'b': '2' });
15312      * // => 'no match'
15313      */
15314     function cond(pairs) {
15315       var length = pairs == null ? 0 : pairs.length,
15316           toIteratee = getIteratee();
15317
15318       pairs = !length ? [] : arrayMap(pairs, function(pair) {
15319         if (typeof pair[1] != 'function') {
15320           throw new TypeError(FUNC_ERROR_TEXT);
15321         }
15322         return [toIteratee(pair[0]), pair[1]];
15323       });
15324
15325       return baseRest(function(args) {
15326         var index = -1;
15327         while (++index < length) {
15328           var pair = pairs[index];
15329           if (apply(pair[0], this, args)) {
15330             return apply(pair[1], this, args);
15331           }
15332         }
15333       });
15334     }
15335
15336     /**
15337      * Creates a function that invokes the predicate properties of `source` with
15338      * the corresponding property values of a given object, returning `true` if
15339      * all predicates return truthy, else `false`.
15340      *
15341      * **Note:** The created function is equivalent to `_.conformsTo` with
15342      * `source` partially applied.
15343      *
15344      * @static
15345      * @memberOf _
15346      * @since 4.0.0
15347      * @category Util
15348      * @param {Object} source The object of property predicates to conform to.
15349      * @returns {Function} Returns the new spec function.
15350      * @example
15351      *
15352      * var objects = [
15353      *   { 'a': 2, 'b': 1 },
15354      *   { 'a': 1, 'b': 2 }
15355      * ];
15356      *
15357      * _.filter(objects, _.conforms({ 'b': function(n) { return n > 1; } }));
15358      * // => [{ 'a': 1, 'b': 2 }]
15359      */
15360     function conforms(source) {
15361       return baseConforms(baseClone(source, CLONE_DEEP_FLAG));
15362     }
15363
15364     /**
15365      * Creates a function that returns `value`.
15366      *
15367      * @static
15368      * @memberOf _
15369      * @since 2.4.0
15370      * @category Util
15371      * @param {*} value The value to return from the new function.
15372      * @returns {Function} Returns the new constant function.
15373      * @example
15374      *
15375      * var objects = _.times(2, _.constant({ 'a': 1 }));
15376      *
15377      * console.log(objects);
15378      * // => [{ 'a': 1 }, { 'a': 1 }]
15379      *
15380      * console.log(objects[0] === objects[1]);
15381      * // => true
15382      */
15383     function constant(value) {
15384       return function() {
15385         return value;
15386       };
15387     }
15388
15389     /**
15390      * Checks `value` to determine whether a default value should be returned in
15391      * its place. The `defaultValue` is returned if `value` is `NaN`, `null`,
15392      * or `undefined`.
15393      *
15394      * @static
15395      * @memberOf _
15396      * @since 4.14.0
15397      * @category Util
15398      * @param {*} value The value to check.
15399      * @param {*} defaultValue The default value.
15400      * @returns {*} Returns the resolved value.
15401      * @example
15402      *
15403      * _.defaultTo(1, 10);
15404      * // => 1
15405      *
15406      * _.defaultTo(undefined, 10);
15407      * // => 10
15408      */
15409     function defaultTo(value, defaultValue) {
15410       return (value == null || value !== value) ? defaultValue : value;
15411     }
15412
15413     /**
15414      * Creates a function that returns the result of invoking the given functions
15415      * with the `this` binding of the created function, where each successive
15416      * invocation is supplied the return value of the previous.
15417      *
15418      * @static
15419      * @memberOf _
15420      * @since 3.0.0
15421      * @category Util
15422      * @param {...(Function|Function[])} [funcs] The functions to invoke.
15423      * @returns {Function} Returns the new composite function.
15424      * @see _.flowRight
15425      * @example
15426      *
15427      * function square(n) {
15428      *   return n * n;
15429      * }
15430      *
15431      * var addSquare = _.flow([_.add, square]);
15432      * addSquare(1, 2);
15433      * // => 9
15434      */
15435     var flow = createFlow();
15436
15437     /**
15438      * This method is like `_.flow` except that it creates a function that
15439      * invokes the given functions from right to left.
15440      *
15441      * @static
15442      * @since 3.0.0
15443      * @memberOf _
15444      * @category Util
15445      * @param {...(Function|Function[])} [funcs] The functions to invoke.
15446      * @returns {Function} Returns the new composite function.
15447      * @see _.flow
15448      * @example
15449      *
15450      * function square(n) {
15451      *   return n * n;
15452      * }
15453      *
15454      * var addSquare = _.flowRight([square, _.add]);
15455      * addSquare(1, 2);
15456      * // => 9
15457      */
15458     var flowRight = createFlow(true);
15459
15460     /**
15461      * This method returns the first argument it receives.
15462      *
15463      * @static
15464      * @since 0.1.0
15465      * @memberOf _
15466      * @category Util
15467      * @param {*} value Any value.
15468      * @returns {*} Returns `value`.
15469      * @example
15470      *
15471      * var object = { 'a': 1 };
15472      *
15473      * console.log(_.identity(object) === object);
15474      * // => true
15475      */
15476     function identity(value) {
15477       return value;
15478     }
15479
15480     /**
15481      * Creates a function that invokes `func` with the arguments of the created
15482      * function. If `func` is a property name, the created function returns the
15483      * property value for a given element. If `func` is an array or object, the
15484      * created function returns `true` for elements that contain the equivalent
15485      * source properties, otherwise it returns `false`.
15486      *
15487      * @static
15488      * @since 4.0.0
15489      * @memberOf _
15490      * @category Util
15491      * @param {*} [func=_.identity] The value to convert to a callback.
15492      * @returns {Function} Returns the callback.
15493      * @example
15494      *
15495      * var users = [
15496      *   { 'user': 'barney', 'age': 36, 'active': true },
15497      *   { 'user': 'fred',   'age': 40, 'active': false }
15498      * ];
15499      *
15500      * // The `_.matches` iteratee shorthand.
15501      * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
15502      * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
15503      *
15504      * // The `_.matchesProperty` iteratee shorthand.
15505      * _.filter(users, _.iteratee(['user', 'fred']));
15506      * // => [{ 'user': 'fred', 'age': 40 }]
15507      *
15508      * // The `_.property` iteratee shorthand.
15509      * _.map(users, _.iteratee('user'));
15510      * // => ['barney', 'fred']
15511      *
15512      * // Create custom iteratee shorthands.
15513      * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
15514      *   return !_.isRegExp(func) ? iteratee(func) : function(string) {
15515      *     return func.test(string);
15516      *   };
15517      * });
15518      *
15519      * _.filter(['abc', 'def'], /ef/);
15520      * // => ['def']
15521      */
15522     function iteratee(func) {
15523       return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG));
15524     }
15525
15526     /**
15527      * Creates a function that performs a partial deep comparison between a given
15528      * object and `source`, returning `true` if the given object has equivalent
15529      * property values, else `false`.
15530      *
15531      * **Note:** The created function is equivalent to `_.isMatch` with `source`
15532      * partially applied.
15533      *
15534      * Partial comparisons will match empty array and empty object `source`
15535      * values against any array or object value, respectively. See `_.isEqual`
15536      * for a list of supported value comparisons.
15537      *
15538      * @static
15539      * @memberOf _
15540      * @since 3.0.0
15541      * @category Util
15542      * @param {Object} source The object of property values to match.
15543      * @returns {Function} Returns the new spec function.
15544      * @example
15545      *
15546      * var objects = [
15547      *   { 'a': 1, 'b': 2, 'c': 3 },
15548      *   { 'a': 4, 'b': 5, 'c': 6 }
15549      * ];
15550      *
15551      * _.filter(objects, _.matches({ 'a': 4, 'c': 6 }));
15552      * // => [{ 'a': 4, 'b': 5, 'c': 6 }]
15553      */
15554     function matches(source) {
15555       return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
15556     }
15557
15558     /**
15559      * Creates a function that performs a partial deep comparison between the
15560      * value at `path` of a given object to `srcValue`, returning `true` if the
15561      * object value is equivalent, else `false`.
15562      *
15563      * **Note:** Partial comparisons will match empty array and empty object
15564      * `srcValue` values against any array or object value, respectively. See
15565      * `_.isEqual` for a list of supported value comparisons.
15566      *
15567      * @static
15568      * @memberOf _
15569      * @since 3.2.0
15570      * @category Util
15571      * @param {Array|string} path The path of the property to get.
15572      * @param {*} srcValue The value to match.
15573      * @returns {Function} Returns the new spec function.
15574      * @example
15575      *
15576      * var objects = [
15577      *   { 'a': 1, 'b': 2, 'c': 3 },
15578      *   { 'a': 4, 'b': 5, 'c': 6 }
15579      * ];
15580      *
15581      * _.find(objects, _.matchesProperty('a', 4));
15582      * // => { 'a': 4, 'b': 5, 'c': 6 }
15583      */
15584     function matchesProperty(path, srcValue) {
15585       return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG));
15586     }
15587
15588     /**
15589      * Creates a function that invokes the method at `path` of a given object.
15590      * Any additional arguments are provided to the invoked method.
15591      *
15592      * @static
15593      * @memberOf _
15594      * @since 3.7.0
15595      * @category Util
15596      * @param {Array|string} path The path of the method to invoke.
15597      * @param {...*} [args] The arguments to invoke the method with.
15598      * @returns {Function} Returns the new invoker function.
15599      * @example
15600      *
15601      * var objects = [
15602      *   { 'a': { 'b': _.constant(2) } },
15603      *   { 'a': { 'b': _.constant(1) } }
15604      * ];
15605      *
15606      * _.map(objects, _.method('a.b'));
15607      * // => [2, 1]
15608      *
15609      * _.map(objects, _.method(['a', 'b']));
15610      * // => [2, 1]
15611      */
15612     var method = baseRest(function(path, args) {
15613       return function(object) {
15614         return baseInvoke(object, path, args);
15615       };
15616     });
15617
15618     /**
15619      * The opposite of `_.method`; this method creates a function that invokes
15620      * the method at a given path of `object`. Any additional arguments are
15621      * provided to the invoked method.
15622      *
15623      * @static
15624      * @memberOf _
15625      * @since 3.7.0
15626      * @category Util
15627      * @param {Object} object The object to query.
15628      * @param {...*} [args] The arguments to invoke the method with.
15629      * @returns {Function} Returns the new invoker function.
15630      * @example
15631      *
15632      * var array = _.times(3, _.constant),
15633      *     object = { 'a': array, 'b': array, 'c': array };
15634      *
15635      * _.map(['a[2]', 'c[0]'], _.methodOf(object));
15636      * // => [2, 0]
15637      *
15638      * _.map([['a', '2'], ['c', '0']], _.methodOf(object));
15639      * // => [2, 0]
15640      */
15641     var methodOf = baseRest(function(object, args) {
15642       return function(path) {
15643         return baseInvoke(object, path, args);
15644       };
15645     });
15646
15647     /**
15648      * Adds all own enumerable string keyed function properties of a source
15649      * object to the destination object. If `object` is a function, then methods
15650      * are added to its prototype as well.
15651      *
15652      * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
15653      * avoid conflicts caused by modifying the original.
15654      *
15655      * @static
15656      * @since 0.1.0
15657      * @memberOf _
15658      * @category Util
15659      * @param {Function|Object} [object=lodash] The destination object.
15660      * @param {Object} source The object of functions to add.
15661      * @param {Object} [options={}] The options object.
15662      * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
15663      * @returns {Function|Object} Returns `object`.
15664      * @example
15665      *
15666      * function vowels(string) {
15667      *   return _.filter(string, function(v) {
15668      *     return /[aeiou]/i.test(v);
15669      *   });
15670      * }
15671      *
15672      * _.mixin({ 'vowels': vowels });
15673      * _.vowels('fred');
15674      * // => ['e']
15675      *
15676      * _('fred').vowels().value();
15677      * // => ['e']
15678      *
15679      * _.mixin({ 'vowels': vowels }, { 'chain': false });
15680      * _('fred').vowels();
15681      * // => ['e']
15682      */
15683     function mixin(object, source, options) {
15684       var props = keys(source),
15685           methodNames = baseFunctions(source, props);
15686
15687       if (options == null &&
15688           !(isObject(source) && (methodNames.length || !props.length))) {
15689         options = source;
15690         source = object;
15691         object = this;
15692         methodNames = baseFunctions(source, keys(source));
15693       }
15694       var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
15695           isFunc = isFunction(object);
15696
15697       arrayEach(methodNames, function(methodName) {
15698         var func = source[methodName];
15699         object[methodName] = func;
15700         if (isFunc) {
15701           object.prototype[methodName] = function() {
15702             var chainAll = this.__chain__;
15703             if (chain || chainAll) {
15704               var result = object(this.__wrapped__),
15705                   actions = result.__actions__ = copyArray(this.__actions__);
15706
15707               actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
15708               result.__chain__ = chainAll;
15709               return result;
15710             }
15711             return func.apply(object, arrayPush([this.value()], arguments));
15712           };
15713         }
15714       });
15715
15716       return object;
15717     }
15718
15719     /**
15720      * Reverts the `_` variable to its previous value and returns a reference to
15721      * the `lodash` function.
15722      *
15723      * @static
15724      * @since 0.1.0
15725      * @memberOf _
15726      * @category Util
15727      * @returns {Function} Returns the `lodash` function.
15728      * @example
15729      *
15730      * var lodash = _.noConflict();
15731      */
15732     function noConflict() {
15733       if (root._ === this) {
15734         root._ = oldDash;
15735       }
15736       return this;
15737     }
15738
15739     /**
15740      * This method returns `undefined`.
15741      *
15742      * @static
15743      * @memberOf _
15744      * @since 2.3.0
15745      * @category Util
15746      * @example
15747      *
15748      * _.times(2, _.noop);
15749      * // => [undefined, undefined]
15750      */
15751     function noop() {
15752       // No operation performed.
15753     }
15754
15755     /**
15756      * Creates a function that gets the argument at index `n`. If `n` is negative,
15757      * the nth argument from the end is returned.
15758      *
15759      * @static
15760      * @memberOf _
15761      * @since 4.0.0
15762      * @category Util
15763      * @param {number} [n=0] The index of the argument to return.
15764      * @returns {Function} Returns the new pass-thru function.
15765      * @example
15766      *
15767      * var func = _.nthArg(1);
15768      * func('a', 'b', 'c', 'd');
15769      * // => 'b'
15770      *
15771      * var func = _.nthArg(-2);
15772      * func('a', 'b', 'c', 'd');
15773      * // => 'c'
15774      */
15775     function nthArg(n) {
15776       n = toInteger(n);
15777       return baseRest(function(args) {
15778         return baseNth(args, n);
15779       });
15780     }
15781
15782     /**
15783      * Creates a function that invokes `iteratees` with the arguments it receives
15784      * and returns their results.
15785      *
15786      * @static
15787      * @memberOf _
15788      * @since 4.0.0
15789      * @category Util
15790      * @param {...(Function|Function[])} [iteratees=[_.identity]]
15791      *  The iteratees to invoke.
15792      * @returns {Function} Returns the new function.
15793      * @example
15794      *
15795      * var func = _.over([Math.max, Math.min]);
15796      *
15797      * func(1, 2, 3, 4);
15798      * // => [4, 1]
15799      */
15800     var over = createOver(arrayMap);
15801
15802     /**
15803      * Creates a function that checks if **all** of the `predicates` return
15804      * truthy when invoked with the arguments it receives.
15805      *
15806      * @static
15807      * @memberOf _
15808      * @since 4.0.0
15809      * @category Util
15810      * @param {...(Function|Function[])} [predicates=[_.identity]]
15811      *  The predicates to check.
15812      * @returns {Function} Returns the new function.
15813      * @example
15814      *
15815      * var func = _.overEvery([Boolean, isFinite]);
15816      *
15817      * func('1');
15818      * // => true
15819      *
15820      * func(null);
15821      * // => false
15822      *
15823      * func(NaN);
15824      * // => false
15825      */
15826     var overEvery = createOver(arrayEvery);
15827
15828     /**
15829      * Creates a function that checks if **any** of the `predicates` return
15830      * truthy when invoked with the arguments it receives.
15831      *
15832      * @static
15833      * @memberOf _
15834      * @since 4.0.0
15835      * @category Util
15836      * @param {...(Function|Function[])} [predicates=[_.identity]]
15837      *  The predicates to check.
15838      * @returns {Function} Returns the new function.
15839      * @example
15840      *
15841      * var func = _.overSome([Boolean, isFinite]);
15842      *
15843      * func('1');
15844      * // => true
15845      *
15846      * func(null);
15847      * // => true
15848      *
15849      * func(NaN);
15850      * // => false
15851      */
15852     var overSome = createOver(arraySome);
15853
15854     /**
15855      * Creates a function that returns the value at `path` of a given object.
15856      *
15857      * @static
15858      * @memberOf _
15859      * @since 2.4.0
15860      * @category Util
15861      * @param {Array|string} path The path of the property to get.
15862      * @returns {Function} Returns the new accessor function.
15863      * @example
15864      *
15865      * var objects = [
15866      *   { 'a': { 'b': 2 } },
15867      *   { 'a': { 'b': 1 } }
15868      * ];
15869      *
15870      * _.map(objects, _.property('a.b'));
15871      * // => [2, 1]
15872      *
15873      * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
15874      * // => [1, 2]
15875      */
15876     function property(path) {
15877       return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
15878     }
15879
15880     /**
15881      * The opposite of `_.property`; this method creates a function that returns
15882      * the value at a given path of `object`.
15883      *
15884      * @static
15885      * @memberOf _
15886      * @since 3.0.0
15887      * @category Util
15888      * @param {Object} object The object to query.
15889      * @returns {Function} Returns the new accessor function.
15890      * @example
15891      *
15892      * var array = [0, 1, 2],
15893      *     object = { 'a': array, 'b': array, 'c': array };
15894      *
15895      * _.map(['a[2]', 'c[0]'], _.propertyOf(object));
15896      * // => [2, 0]
15897      *
15898      * _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
15899      * // => [2, 0]
15900      */
15901     function propertyOf(object) {
15902       return function(path) {
15903         return object == null ? undefined : baseGet(object, path);
15904       };
15905     }
15906
15907     /**
15908      * Creates an array of numbers (positive and/or negative) progressing from
15909      * `start` up to, but not including, `end`. A step of `-1` is used if a negative
15910      * `start` is specified without an `end` or `step`. If `end` is not specified,
15911      * it's set to `start` with `start` then set to `0`.
15912      *
15913      * **Note:** JavaScript follows the IEEE-754 standard for resolving
15914      * floating-point values which can produce unexpected results.
15915      *
15916      * @static
15917      * @since 0.1.0
15918      * @memberOf _
15919      * @category Util
15920      * @param {number} [start=0] The start of the range.
15921      * @param {number} end The end of the range.
15922      * @param {number} [step=1] The value to increment or decrement by.
15923      * @returns {Array} Returns the range of numbers.
15924      * @see _.inRange, _.rangeRight
15925      * @example
15926      *
15927      * _.range(4);
15928      * // => [0, 1, 2, 3]
15929      *
15930      * _.range(-4);
15931      * // => [0, -1, -2, -3]
15932      *
15933      * _.range(1, 5);
15934      * // => [1, 2, 3, 4]
15935      *
15936      * _.range(0, 20, 5);
15937      * // => [0, 5, 10, 15]
15938      *
15939      * _.range(0, -4, -1);
15940      * // => [0, -1, -2, -3]
15941      *
15942      * _.range(1, 4, 0);
15943      * // => [1, 1, 1]
15944      *
15945      * _.range(0);
15946      * // => []
15947      */
15948     var range = createRange();
15949
15950     /**
15951      * This method is like `_.range` except that it populates values in
15952      * descending order.
15953      *
15954      * @static
15955      * @memberOf _
15956      * @since 4.0.0
15957      * @category Util
15958      * @param {number} [start=0] The start of the range.
15959      * @param {number} end The end of the range.
15960      * @param {number} [step=1] The value to increment or decrement by.
15961      * @returns {Array} Returns the range of numbers.
15962      * @see _.inRange, _.range
15963      * @example
15964      *
15965      * _.rangeRight(4);
15966      * // => [3, 2, 1, 0]
15967      *
15968      * _.rangeRight(-4);
15969      * // => [-3, -2, -1, 0]
15970      *
15971      * _.rangeRight(1, 5);
15972      * // => [4, 3, 2, 1]
15973      *
15974      * _.rangeRight(0, 20, 5);
15975      * // => [15, 10, 5, 0]
15976      *
15977      * _.rangeRight(0, -4, -1);
15978      * // => [-3, -2, -1, 0]
15979      *
15980      * _.rangeRight(1, 4, 0);
15981      * // => [1, 1, 1]
15982      *
15983      * _.rangeRight(0);
15984      * // => []
15985      */
15986     var rangeRight = createRange(true);
15987
15988     /**
15989      * This method returns a new empty array.
15990      *
15991      * @static
15992      * @memberOf _
15993      * @since 4.13.0
15994      * @category Util
15995      * @returns {Array} Returns the new empty array.
15996      * @example
15997      *
15998      * var arrays = _.times(2, _.stubArray);
15999      *
16000      * console.log(arrays);
16001      * // => [[], []]
16002      *
16003      * console.log(arrays[0] === arrays[1]);
16004      * // => false
16005      */
16006     function stubArray() {
16007       return [];
16008     }
16009
16010     /**
16011      * This method returns `false`.
16012      *
16013      * @static
16014      * @memberOf _
16015      * @since 4.13.0
16016      * @category Util
16017      * @returns {boolean} Returns `false`.
16018      * @example
16019      *
16020      * _.times(2, _.stubFalse);
16021      * // => [false, false]
16022      */
16023     function stubFalse() {
16024       return false;
16025     }
16026
16027     /**
16028      * This method returns a new empty object.
16029      *
16030      * @static
16031      * @memberOf _
16032      * @since 4.13.0
16033      * @category Util
16034      * @returns {Object} Returns the new empty object.
16035      * @example
16036      *
16037      * var objects = _.times(2, _.stubObject);
16038      *
16039      * console.log(objects);
16040      * // => [{}, {}]
16041      *
16042      * console.log(objects[0] === objects[1]);
16043      * // => false
16044      */
16045     function stubObject() {
16046       return {};
16047     }
16048
16049     /**
16050      * This method returns an empty string.
16051      *
16052      * @static
16053      * @memberOf _
16054      * @since 4.13.0
16055      * @category Util
16056      * @returns {string} Returns the empty string.
16057      * @example
16058      *
16059      * _.times(2, _.stubString);
16060      * // => ['', '']
16061      */
16062     function stubString() {
16063       return '';
16064     }
16065
16066     /**
16067      * This method returns `true`.
16068      *
16069      * @static
16070      * @memberOf _
16071      * @since 4.13.0
16072      * @category Util
16073      * @returns {boolean} Returns `true`.
16074      * @example
16075      *
16076      * _.times(2, _.stubTrue);
16077      * // => [true, true]
16078      */
16079     function stubTrue() {
16080       return true;
16081     }
16082
16083     /**
16084      * Invokes the iteratee `n` times, returning an array of the results of
16085      * each invocation. The iteratee is invoked with one argument; (index).
16086      *
16087      * @static
16088      * @since 0.1.0
16089      * @memberOf _
16090      * @category Util
16091      * @param {number} n The number of times to invoke `iteratee`.
16092      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
16093      * @returns {Array} Returns the array of results.
16094      * @example
16095      *
16096      * _.times(3, String);
16097      * // => ['0', '1', '2']
16098      *
16099      *  _.times(4, _.constant(0));
16100      * // => [0, 0, 0, 0]
16101      */
16102     function times(n, iteratee) {
16103       n = toInteger(n);
16104       if (n < 1 || n > MAX_SAFE_INTEGER) {
16105         return [];
16106       }
16107       var index = MAX_ARRAY_LENGTH,
16108           length = nativeMin(n, MAX_ARRAY_LENGTH);
16109
16110       iteratee = getIteratee(iteratee);
16111       n -= MAX_ARRAY_LENGTH;
16112
16113       var result = baseTimes(length, iteratee);
16114       while (++index < n) {
16115         iteratee(index);
16116       }
16117       return result;
16118     }
16119
16120     /**
16121      * Converts `value` to a property path array.
16122      *
16123      * @static
16124      * @memberOf _
16125      * @since 4.0.0
16126      * @category Util
16127      * @param {*} value The value to convert.
16128      * @returns {Array} Returns the new property path array.
16129      * @example
16130      *
16131      * _.toPath('a.b.c');
16132      * // => ['a', 'b', 'c']
16133      *
16134      * _.toPath('a[0].b.c');
16135      * // => ['a', '0', 'b', 'c']
16136      */
16137     function toPath(value) {
16138       if (isArray(value)) {
16139         return arrayMap(value, toKey);
16140       }
16141       return isSymbol(value) ? [value] : copyArray(stringToPath(toString(value)));
16142     }
16143
16144     /**
16145      * Generates a unique ID. If `prefix` is given, the ID is appended to it.
16146      *
16147      * @static
16148      * @since 0.1.0
16149      * @memberOf _
16150      * @category Util
16151      * @param {string} [prefix=''] The value to prefix the ID with.
16152      * @returns {string} Returns the unique ID.
16153      * @example
16154      *
16155      * _.uniqueId('contact_');
16156      * // => 'contact_104'
16157      *
16158      * _.uniqueId();
16159      * // => '105'
16160      */
16161     function uniqueId(prefix) {
16162       var id = ++idCounter;
16163       return toString(prefix) + id;
16164     }
16165
16166     /*------------------------------------------------------------------------*/
16167
16168     /**
16169      * Adds two numbers.
16170      *
16171      * @static
16172      * @memberOf _
16173      * @since 3.4.0
16174      * @category Math
16175      * @param {number} augend The first number in an addition.
16176      * @param {number} addend The second number in an addition.
16177      * @returns {number} Returns the total.
16178      * @example
16179      *
16180      * _.add(6, 4);
16181      * // => 10
16182      */
16183     var add = createMathOperation(function(augend, addend) {
16184       return augend + addend;
16185     }, 0);
16186
16187     /**
16188      * Computes `number` rounded up to `precision`.
16189      *
16190      * @static
16191      * @memberOf _
16192      * @since 3.10.0
16193      * @category Math
16194      * @param {number} number The number to round up.
16195      * @param {number} [precision=0] The precision to round up to.
16196      * @returns {number} Returns the rounded up number.
16197      * @example
16198      *
16199      * _.ceil(4.006);
16200      * // => 5
16201      *
16202      * _.ceil(6.004, 2);
16203      * // => 6.01
16204      *
16205      * _.ceil(6040, -2);
16206      * // => 6100
16207      */
16208     var ceil = createRound('ceil');
16209
16210     /**
16211      * Divide two numbers.
16212      *
16213      * @static
16214      * @memberOf _
16215      * @since 4.7.0
16216      * @category Math
16217      * @param {number} dividend The first number in a division.
16218      * @param {number} divisor The second number in a division.
16219      * @returns {number} Returns the quotient.
16220      * @example
16221      *
16222      * _.divide(6, 4);
16223      * // => 1.5
16224      */
16225     var divide = createMathOperation(function(dividend, divisor) {
16226       return dividend / divisor;
16227     }, 1);
16228
16229     /**
16230      * Computes `number` rounded down to `precision`.
16231      *
16232      * @static
16233      * @memberOf _
16234      * @since 3.10.0
16235      * @category Math
16236      * @param {number} number The number to round down.
16237      * @param {number} [precision=0] The precision to round down to.
16238      * @returns {number} Returns the rounded down number.
16239      * @example
16240      *
16241      * _.floor(4.006);
16242      * // => 4
16243      *
16244      * _.floor(0.046, 2);
16245      * // => 0.04
16246      *
16247      * _.floor(4060, -2);
16248      * // => 4000
16249      */
16250     var floor = createRound('floor');
16251
16252     /**
16253      * Computes the maximum value of `array`. If `array` is empty or falsey,
16254      * `undefined` is returned.
16255      *
16256      * @static
16257      * @since 0.1.0
16258      * @memberOf _
16259      * @category Math
16260      * @param {Array} array The array to iterate over.
16261      * @returns {*} Returns the maximum value.
16262      * @example
16263      *
16264      * _.max([4, 2, 8, 6]);
16265      * // => 8
16266      *
16267      * _.max([]);
16268      * // => undefined
16269      */
16270     function max(array) {
16271       return (array && array.length)
16272         ? baseExtremum(array, identity, baseGt)
16273         : undefined;
16274     }
16275
16276     /**
16277      * This method is like `_.max` except that it accepts `iteratee` which is
16278      * invoked for each element in `array` to generate the criterion by which
16279      * the value is ranked. The iteratee is invoked with one argument: (value).
16280      *
16281      * @static
16282      * @memberOf _
16283      * @since 4.0.0
16284      * @category Math
16285      * @param {Array} array The array to iterate over.
16286      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16287      * @returns {*} Returns the maximum value.
16288      * @example
16289      *
16290      * var objects = [{ 'n': 1 }, { 'n': 2 }];
16291      *
16292      * _.maxBy(objects, function(o) { return o.n; });
16293      * // => { 'n': 2 }
16294      *
16295      * // The `_.property` iteratee shorthand.
16296      * _.maxBy(objects, 'n');
16297      * // => { 'n': 2 }
16298      */
16299     function maxBy(array, iteratee) {
16300       return (array && array.length)
16301         ? baseExtremum(array, getIteratee(iteratee, 2), baseGt)
16302         : undefined;
16303     }
16304
16305     /**
16306      * Computes the mean of the values in `array`.
16307      *
16308      * @static
16309      * @memberOf _
16310      * @since 4.0.0
16311      * @category Math
16312      * @param {Array} array The array to iterate over.
16313      * @returns {number} Returns the mean.
16314      * @example
16315      *
16316      * _.mean([4, 2, 8, 6]);
16317      * // => 5
16318      */
16319     function mean(array) {
16320       return baseMean(array, identity);
16321     }
16322
16323     /**
16324      * This method is like `_.mean` except that it accepts `iteratee` which is
16325      * invoked for each element in `array` to generate the value to be averaged.
16326      * The iteratee is invoked with one argument: (value).
16327      *
16328      * @static
16329      * @memberOf _
16330      * @since 4.7.0
16331      * @category Math
16332      * @param {Array} array The array to iterate over.
16333      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16334      * @returns {number} Returns the mean.
16335      * @example
16336      *
16337      * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
16338      *
16339      * _.meanBy(objects, function(o) { return o.n; });
16340      * // => 5
16341      *
16342      * // The `_.property` iteratee shorthand.
16343      * _.meanBy(objects, 'n');
16344      * // => 5
16345      */
16346     function meanBy(array, iteratee) {
16347       return baseMean(array, getIteratee(iteratee, 2));
16348     }
16349
16350     /**
16351      * Computes the minimum value of `array`. If `array` is empty or falsey,
16352      * `undefined` is returned.
16353      *
16354      * @static
16355      * @since 0.1.0
16356      * @memberOf _
16357      * @category Math
16358      * @param {Array} array The array to iterate over.
16359      * @returns {*} Returns the minimum value.
16360      * @example
16361      *
16362      * _.min([4, 2, 8, 6]);
16363      * // => 2
16364      *
16365      * _.min([]);
16366      * // => undefined
16367      */
16368     function min(array) {
16369       return (array && array.length)
16370         ? baseExtremum(array, identity, baseLt)
16371         : undefined;
16372     }
16373
16374     /**
16375      * This method is like `_.min` except that it accepts `iteratee` which is
16376      * invoked for each element in `array` to generate the criterion by which
16377      * the value is ranked. The iteratee is invoked with one argument: (value).
16378      *
16379      * @static
16380      * @memberOf _
16381      * @since 4.0.0
16382      * @category Math
16383      * @param {Array} array The array to iterate over.
16384      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16385      * @returns {*} Returns the minimum value.
16386      * @example
16387      *
16388      * var objects = [{ 'n': 1 }, { 'n': 2 }];
16389      *
16390      * _.minBy(objects, function(o) { return o.n; });
16391      * // => { 'n': 1 }
16392      *
16393      * // The `_.property` iteratee shorthand.
16394      * _.minBy(objects, 'n');
16395      * // => { 'n': 1 }
16396      */
16397     function minBy(array, iteratee) {
16398       return (array && array.length)
16399         ? baseExtremum(array, getIteratee(iteratee, 2), baseLt)
16400         : undefined;
16401     }
16402
16403     /**
16404      * Multiply two numbers.
16405      *
16406      * @static
16407      * @memberOf _
16408      * @since 4.7.0
16409      * @category Math
16410      * @param {number} multiplier The first number in a multiplication.
16411      * @param {number} multiplicand The second number in a multiplication.
16412      * @returns {number} Returns the product.
16413      * @example
16414      *
16415      * _.multiply(6, 4);
16416      * // => 24
16417      */
16418     var multiply = createMathOperation(function(multiplier, multiplicand) {
16419       return multiplier * multiplicand;
16420     }, 1);
16421
16422     /**
16423      * Computes `number` rounded to `precision`.
16424      *
16425      * @static
16426      * @memberOf _
16427      * @since 3.10.0
16428      * @category Math
16429      * @param {number} number The number to round.
16430      * @param {number} [precision=0] The precision to round to.
16431      * @returns {number} Returns the rounded number.
16432      * @example
16433      *
16434      * _.round(4.006);
16435      * // => 4
16436      *
16437      * _.round(4.006, 2);
16438      * // => 4.01
16439      *
16440      * _.round(4060, -2);
16441      * // => 4100
16442      */
16443     var round = createRound('round');
16444
16445     /**
16446      * Subtract two numbers.
16447      *
16448      * @static
16449      * @memberOf _
16450      * @since 4.0.0
16451      * @category Math
16452      * @param {number} minuend The first number in a subtraction.
16453      * @param {number} subtrahend The second number in a subtraction.
16454      * @returns {number} Returns the difference.
16455      * @example
16456      *
16457      * _.subtract(6, 4);
16458      * // => 2
16459      */
16460     var subtract = createMathOperation(function(minuend, subtrahend) {
16461       return minuend - subtrahend;
16462     }, 0);
16463
16464     /**
16465      * Computes the sum of the values in `array`.
16466      *
16467      * @static
16468      * @memberOf _
16469      * @since 3.4.0
16470      * @category Math
16471      * @param {Array} array The array to iterate over.
16472      * @returns {number} Returns the sum.
16473      * @example
16474      *
16475      * _.sum([4, 2, 8, 6]);
16476      * // => 20
16477      */
16478     function sum(array) {
16479       return (array && array.length)
16480         ? baseSum(array, identity)
16481         : 0;
16482     }
16483
16484     /**
16485      * This method is like `_.sum` except that it accepts `iteratee` which is
16486      * invoked for each element in `array` to generate the value to be summed.
16487      * The iteratee is invoked with one argument: (value).
16488      *
16489      * @static
16490      * @memberOf _
16491      * @since 4.0.0
16492      * @category Math
16493      * @param {Array} array The array to iterate over.
16494      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16495      * @returns {number} Returns the sum.
16496      * @example
16497      *
16498      * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
16499      *
16500      * _.sumBy(objects, function(o) { return o.n; });
16501      * // => 20
16502      *
16503      * // The `_.property` iteratee shorthand.
16504      * _.sumBy(objects, 'n');
16505      * // => 20
16506      */
16507     function sumBy(array, iteratee) {
16508       return (array && array.length)
16509         ? baseSum(array, getIteratee(iteratee, 2))
16510         : 0;
16511     }
16512
16513     /*------------------------------------------------------------------------*/
16514
16515     // Add methods that return wrapped values in chain sequences.
16516     lodash.after = after;
16517     lodash.ary = ary;
16518     lodash.assign = assign;
16519     lodash.assignIn = assignIn;
16520     lodash.assignInWith = assignInWith;
16521     lodash.assignWith = assignWith;
16522     lodash.at = at;
16523     lodash.before = before;
16524     lodash.bind = bind;
16525     lodash.bindAll = bindAll;
16526     lodash.bindKey = bindKey;
16527     lodash.castArray = castArray;
16528     lodash.chain = chain;
16529     lodash.chunk = chunk;
16530     lodash.compact = compact;
16531     lodash.concat = concat;
16532     lodash.cond = cond;
16533     lodash.conforms = conforms;
16534     lodash.constant = constant;
16535     lodash.countBy = countBy;
16536     lodash.create = create;
16537     lodash.curry = curry;
16538     lodash.curryRight = curryRight;
16539     lodash.debounce = debounce;
16540     lodash.defaults = defaults;
16541     lodash.defaultsDeep = defaultsDeep;
16542     lodash.defer = defer;
16543     lodash.delay = delay;
16544     lodash.difference = difference;
16545     lodash.differenceBy = differenceBy;
16546     lodash.differenceWith = differenceWith;
16547     lodash.drop = drop;
16548     lodash.dropRight = dropRight;
16549     lodash.dropRightWhile = dropRightWhile;
16550     lodash.dropWhile = dropWhile;
16551     lodash.fill = fill;
16552     lodash.filter = filter;
16553     lodash.flatMap = flatMap;
16554     lodash.flatMapDeep = flatMapDeep;
16555     lodash.flatMapDepth = flatMapDepth;
16556     lodash.flatten = flatten;
16557     lodash.flattenDeep = flattenDeep;
16558     lodash.flattenDepth = flattenDepth;
16559     lodash.flip = flip;
16560     lodash.flow = flow;
16561     lodash.flowRight = flowRight;
16562     lodash.fromPairs = fromPairs;
16563     lodash.functions = functions;
16564     lodash.functionsIn = functionsIn;
16565     lodash.groupBy = groupBy;
16566     lodash.initial = initial;
16567     lodash.intersection = intersection;
16568     lodash.intersectionBy = intersectionBy;
16569     lodash.intersectionWith = intersectionWith;
16570     lodash.invert = invert;
16571     lodash.invertBy = invertBy;
16572     lodash.invokeMap = invokeMap;
16573     lodash.iteratee = iteratee;
16574     lodash.keyBy = keyBy;
16575     lodash.keys = keys;
16576     lodash.keysIn = keysIn;
16577     lodash.map = map;
16578     lodash.mapKeys = mapKeys;
16579     lodash.mapValues = mapValues;
16580     lodash.matches = matches;
16581     lodash.matchesProperty = matchesProperty;
16582     lodash.memoize = memoize;
16583     lodash.merge = merge;
16584     lodash.mergeWith = mergeWith;
16585     lodash.method = method;
16586     lodash.methodOf = methodOf;
16587     lodash.mixin = mixin;
16588     lodash.negate = negate;
16589     lodash.nthArg = nthArg;
16590     lodash.omit = omit;
16591     lodash.omitBy = omitBy;
16592     lodash.once = once;
16593     lodash.orderBy = orderBy;
16594     lodash.over = over;
16595     lodash.overArgs = overArgs;
16596     lodash.overEvery = overEvery;
16597     lodash.overSome = overSome;
16598     lodash.partial = partial;
16599     lodash.partialRight = partialRight;
16600     lodash.partition = partition;
16601     lodash.pick = pick;
16602     lodash.pickBy = pickBy;
16603     lodash.property = property;
16604     lodash.propertyOf = propertyOf;
16605     lodash.pull = pull;
16606     lodash.pullAll = pullAll;
16607     lodash.pullAllBy = pullAllBy;
16608     lodash.pullAllWith = pullAllWith;
16609     lodash.pullAt = pullAt;
16610     lodash.range = range;
16611     lodash.rangeRight = rangeRight;
16612     lodash.rearg = rearg;
16613     lodash.reject = reject;
16614     lodash.remove = remove;
16615     lodash.rest = rest;
16616     lodash.reverse = reverse;
16617     lodash.sampleSize = sampleSize;
16618     lodash.set = set;
16619     lodash.setWith = setWith;
16620     lodash.shuffle = shuffle;
16621     lodash.slice = slice;
16622     lodash.sortBy = sortBy;
16623     lodash.sortedUniq = sortedUniq;
16624     lodash.sortedUniqBy = sortedUniqBy;
16625     lodash.split = split;
16626     lodash.spread = spread;
16627     lodash.tail = tail;
16628     lodash.take = take;
16629     lodash.takeRight = takeRight;
16630     lodash.takeRightWhile = takeRightWhile;
16631     lodash.takeWhile = takeWhile;
16632     lodash.tap = tap;
16633     lodash.throttle = throttle;
16634     lodash.thru = thru;
16635     lodash.toArray = toArray;
16636     lodash.toPairs = toPairs;
16637     lodash.toPairsIn = toPairsIn;
16638     lodash.toPath = toPath;
16639     lodash.toPlainObject = toPlainObject;
16640     lodash.transform = transform;
16641     lodash.unary = unary;
16642     lodash.union = union;
16643     lodash.unionBy = unionBy;
16644     lodash.unionWith = unionWith;
16645     lodash.uniq = uniq;
16646     lodash.uniqBy = uniqBy;
16647     lodash.uniqWith = uniqWith;
16648     lodash.unset = unset;
16649     lodash.unzip = unzip;
16650     lodash.unzipWith = unzipWith;
16651     lodash.update = update;
16652     lodash.updateWith = updateWith;
16653     lodash.values = values;
16654     lodash.valuesIn = valuesIn;
16655     lodash.without = without;
16656     lodash.words = words;
16657     lodash.wrap = wrap;
16658     lodash.xor = xor;
16659     lodash.xorBy = xorBy;
16660     lodash.xorWith = xorWith;
16661     lodash.zip = zip;
16662     lodash.zipObject = zipObject;
16663     lodash.zipObjectDeep = zipObjectDeep;
16664     lodash.zipWith = zipWith;
16665
16666     // Add aliases.
16667     lodash.entries = toPairs;
16668     lodash.entriesIn = toPairsIn;
16669     lodash.extend = assignIn;
16670     lodash.extendWith = assignInWith;
16671
16672     // Add methods to `lodash.prototype`.
16673     mixin(lodash, lodash);
16674
16675     /*------------------------------------------------------------------------*/
16676
16677     // Add methods that return unwrapped values in chain sequences.
16678     lodash.add = add;
16679     lodash.attempt = attempt;
16680     lodash.camelCase = camelCase;
16681     lodash.capitalize = capitalize;
16682     lodash.ceil = ceil;
16683     lodash.clamp = clamp;
16684     lodash.clone = clone;
16685     lodash.cloneDeep = cloneDeep;
16686     lodash.cloneDeepWith = cloneDeepWith;
16687     lodash.cloneWith = cloneWith;
16688     lodash.conformsTo = conformsTo;
16689     lodash.deburr = deburr;
16690     lodash.defaultTo = defaultTo;
16691     lodash.divide = divide;
16692     lodash.endsWith = endsWith;
16693     lodash.eq = eq;
16694     lodash.escape = escape;
16695     lodash.escapeRegExp = escapeRegExp;
16696     lodash.every = every;
16697     lodash.find = find;
16698     lodash.findIndex = findIndex;
16699     lodash.findKey = findKey;
16700     lodash.findLast = findLast;
16701     lodash.findLastIndex = findLastIndex;
16702     lodash.findLastKey = findLastKey;
16703     lodash.floor = floor;
16704     lodash.forEach = forEach;
16705     lodash.forEachRight = forEachRight;
16706     lodash.forIn = forIn;
16707     lodash.forInRight = forInRight;
16708     lodash.forOwn = forOwn;
16709     lodash.forOwnRight = forOwnRight;
16710     lodash.get = get;
16711     lodash.gt = gt;
16712     lodash.gte = gte;
16713     lodash.has = has;
16714     lodash.hasIn = hasIn;
16715     lodash.head = head;
16716     lodash.identity = identity;
16717     lodash.includes = includes;
16718     lodash.indexOf = indexOf;
16719     lodash.inRange = inRange;
16720     lodash.invoke = invoke;
16721     lodash.isArguments = isArguments;
16722     lodash.isArray = isArray;
16723     lodash.isArrayBuffer = isArrayBuffer;
16724     lodash.isArrayLike = isArrayLike;
16725     lodash.isArrayLikeObject = isArrayLikeObject;
16726     lodash.isBoolean = isBoolean;
16727     lodash.isBuffer = isBuffer;
16728     lodash.isDate = isDate;
16729     lodash.isElement = isElement;
16730     lodash.isEmpty = isEmpty;
16731     lodash.isEqual = isEqual;
16732     lodash.isEqualWith = isEqualWith;
16733     lodash.isError = isError;
16734     lodash.isFinite = isFinite;
16735     lodash.isFunction = isFunction;
16736     lodash.isInteger = isInteger;
16737     lodash.isLength = isLength;
16738     lodash.isMap = isMap;
16739     lodash.isMatch = isMatch;
16740     lodash.isMatchWith = isMatchWith;
16741     lodash.isNaN = isNaN;
16742     lodash.isNative = isNative;
16743     lodash.isNil = isNil;
16744     lodash.isNull = isNull;
16745     lodash.isNumber = isNumber;
16746     lodash.isObject = isObject;
16747     lodash.isObjectLike = isObjectLike;
16748     lodash.isPlainObject = isPlainObject;
16749     lodash.isRegExp = isRegExp;
16750     lodash.isSafeInteger = isSafeInteger;
16751     lodash.isSet = isSet;
16752     lodash.isString = isString;
16753     lodash.isSymbol = isSymbol;
16754     lodash.isTypedArray = isTypedArray;
16755     lodash.isUndefined = isUndefined;
16756     lodash.isWeakMap = isWeakMap;
16757     lodash.isWeakSet = isWeakSet;
16758     lodash.join = join;
16759     lodash.kebabCase = kebabCase;
16760     lodash.last = last;
16761     lodash.lastIndexOf = lastIndexOf;
16762     lodash.lowerCase = lowerCase;
16763     lodash.lowerFirst = lowerFirst;
16764     lodash.lt = lt;
16765     lodash.lte = lte;
16766     lodash.max = max;
16767     lodash.maxBy = maxBy;
16768     lodash.mean = mean;
16769     lodash.meanBy = meanBy;
16770     lodash.min = min;
16771     lodash.minBy = minBy;
16772     lodash.stubArray = stubArray;
16773     lodash.stubFalse = stubFalse;
16774     lodash.stubObject = stubObject;
16775     lodash.stubString = stubString;
16776     lodash.stubTrue = stubTrue;
16777     lodash.multiply = multiply;
16778     lodash.nth = nth;
16779     lodash.noConflict = noConflict;
16780     lodash.noop = noop;
16781     lodash.now = now;
16782     lodash.pad = pad;
16783     lodash.padEnd = padEnd;
16784     lodash.padStart = padStart;
16785     lodash.parseInt = parseInt;
16786     lodash.random = random;
16787     lodash.reduce = reduce;
16788     lodash.reduceRight = reduceRight;
16789     lodash.repeat = repeat;
16790     lodash.replace = replace;
16791     lodash.result = result;
16792     lodash.round = round;
16793     lodash.runInContext = runInContext;
16794     lodash.sample = sample;
16795     lodash.size = size;
16796     lodash.snakeCase = snakeCase;
16797     lodash.some = some;
16798     lodash.sortedIndex = sortedIndex;
16799     lodash.sortedIndexBy = sortedIndexBy;
16800     lodash.sortedIndexOf = sortedIndexOf;
16801     lodash.sortedLastIndex = sortedLastIndex;
16802     lodash.sortedLastIndexBy = sortedLastIndexBy;
16803     lodash.sortedLastIndexOf = sortedLastIndexOf;
16804     lodash.startCase = startCase;
16805     lodash.startsWith = startsWith;
16806     lodash.subtract = subtract;
16807     lodash.sum = sum;
16808     lodash.sumBy = sumBy;
16809     lodash.template = template;
16810     lodash.times = times;
16811     lodash.toFinite = toFinite;
16812     lodash.toInteger = toInteger;
16813     lodash.toLength = toLength;
16814     lodash.toLower = toLower;
16815     lodash.toNumber = toNumber;
16816     lodash.toSafeInteger = toSafeInteger;
16817     lodash.toString = toString;
16818     lodash.toUpper = toUpper;
16819     lodash.trim = trim;
16820     lodash.trimEnd = trimEnd;
16821     lodash.trimStart = trimStart;
16822     lodash.truncate = truncate;
16823     lodash.unescape = unescape;
16824     lodash.uniqueId = uniqueId;
16825     lodash.upperCase = upperCase;
16826     lodash.upperFirst = upperFirst;
16827
16828     // Add aliases.
16829     lodash.each = forEach;
16830     lodash.eachRight = forEachRight;
16831     lodash.first = head;
16832
16833     mixin(lodash, (function() {
16834       var source = {};
16835       baseForOwn(lodash, function(func, methodName) {
16836         if (!hasOwnProperty.call(lodash.prototype, methodName)) {
16837           source[methodName] = func;
16838         }
16839       });
16840       return source;
16841     }()), { 'chain': false });
16842
16843     /*------------------------------------------------------------------------*/
16844
16845     /**
16846      * The semantic version number.
16847      *
16848      * @static
16849      * @memberOf _
16850      * @type {string}
16851      */
16852     lodash.VERSION = VERSION;
16853
16854     // Assign default placeholders.
16855     arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
16856       lodash[methodName].placeholder = lodash;
16857     });
16858
16859     // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
16860     arrayEach(['drop', 'take'], function(methodName, index) {
16861       LazyWrapper.prototype[methodName] = function(n) {
16862         n = n === undefined ? 1 : nativeMax(toInteger(n), 0);
16863
16864         var result = (this.__filtered__ && !index)
16865           ? new LazyWrapper(this)
16866           : this.clone();
16867
16868         if (result.__filtered__) {
16869           result.__takeCount__ = nativeMin(n, result.__takeCount__);
16870         } else {
16871           result.__views__.push({
16872             'size': nativeMin(n, MAX_ARRAY_LENGTH),
16873             'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
16874           });
16875         }
16876         return result;
16877       };
16878
16879       LazyWrapper.prototype[methodName + 'Right'] = function(n) {
16880         return this.reverse()[methodName](n).reverse();
16881       };
16882     });
16883
16884     // Add `LazyWrapper` methods that accept an `iteratee` value.
16885     arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
16886       var type = index + 1,
16887           isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;
16888
16889       LazyWrapper.prototype[methodName] = function(iteratee) {
16890         var result = this.clone();
16891         result.__iteratees__.push({
16892           'iteratee': getIteratee(iteratee, 3),
16893           'type': type
16894         });
16895         result.__filtered__ = result.__filtered__ || isFilter;
16896         return result;
16897       };
16898     });
16899
16900     // Add `LazyWrapper` methods for `_.head` and `_.last`.
16901     arrayEach(['head', 'last'], function(methodName, index) {
16902       var takeName = 'take' + (index ? 'Right' : '');
16903
16904       LazyWrapper.prototype[methodName] = function() {
16905         return this[takeName](1).value()[0];
16906       };
16907     });
16908
16909     // Add `LazyWrapper` methods for `_.initial` and `_.tail`.
16910     arrayEach(['initial', 'tail'], function(methodName, index) {
16911       var dropName = 'drop' + (index ? '' : 'Right');
16912
16913       LazyWrapper.prototype[methodName] = function() {
16914         return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
16915       };
16916     });
16917
16918     LazyWrapper.prototype.compact = function() {
16919       return this.filter(identity);
16920     };
16921
16922     LazyWrapper.prototype.find = function(predicate) {
16923       return this.filter(predicate).head();
16924     };
16925
16926     LazyWrapper.prototype.findLast = function(predicate) {
16927       return this.reverse().find(predicate);
16928     };
16929
16930     LazyWrapper.prototype.invokeMap = baseRest(function(path, args) {
16931       if (typeof path == 'function') {
16932         return new LazyWrapper(this);
16933       }
16934       return this.map(function(value) {
16935         return baseInvoke(value, path, args);
16936       });
16937     });
16938
16939     LazyWrapper.prototype.reject = function(predicate) {
16940       return this.filter(negate(getIteratee(predicate)));
16941     };
16942
16943     LazyWrapper.prototype.slice = function(start, end) {
16944       start = toInteger(start);
16945
16946       var result = this;
16947       if (result.__filtered__ && (start > 0 || end < 0)) {
16948         return new LazyWrapper(result);
16949       }
16950       if (start < 0) {
16951         result = result.takeRight(-start);
16952       } else if (start) {
16953         result = result.drop(start);
16954       }
16955       if (end !== undefined) {
16956         end = toInteger(end);
16957         result = end < 0 ? result.dropRight(-end) : result.take(end - start);
16958       }
16959       return result;
16960     };
16961
16962     LazyWrapper.prototype.takeRightWhile = function(predicate) {
16963       return this.reverse().takeWhile(predicate).reverse();
16964     };
16965
16966     LazyWrapper.prototype.toArray = function() {
16967       return this.take(MAX_ARRAY_LENGTH);
16968     };
16969
16970     // Add `LazyWrapper` methods to `lodash.prototype`.
16971     baseForOwn(LazyWrapper.prototype, function(func, methodName) {
16972       var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
16973           isTaker = /^(?:head|last)$/.test(methodName),
16974           lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
16975           retUnwrapped = isTaker || /^find/.test(methodName);
16976
16977       if (!lodashFunc) {
16978         return;
16979       }
16980       lodash.prototype[methodName] = function() {
16981         var value = this.__wrapped__,
16982             args = isTaker ? [1] : arguments,
16983             isLazy = value instanceof LazyWrapper,
16984             iteratee = args[0],
16985             useLazy = isLazy || isArray(value);
16986
16987         var interceptor = function(value) {
16988           var result = lodashFunc.apply(lodash, arrayPush([value], args));
16989           return (isTaker && chainAll) ? result[0] : result;
16990         };
16991
16992         if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
16993           // Avoid lazy use if the iteratee has a "length" value other than `1`.
16994           isLazy = useLazy = false;
16995         }
16996         var chainAll = this.__chain__,
16997             isHybrid = !!this.__actions__.length,
16998             isUnwrapped = retUnwrapped && !chainAll,
16999             onlyLazy = isLazy && !isHybrid;
17000
17001         if (!retUnwrapped && useLazy) {
17002           value = onlyLazy ? value : new LazyWrapper(this);
17003           var result = func.apply(value, args);
17004           result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
17005           return new LodashWrapper(result, chainAll);
17006         }
17007         if (isUnwrapped && onlyLazy) {
17008           return func.apply(this, args);
17009         }
17010         result = this.thru(interceptor);
17011         return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
17012       };
17013     });
17014
17015     // Add `Array` methods to `lodash.prototype`.
17016     arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
17017       var func = arrayProto[methodName],
17018           chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
17019           retUnwrapped = /^(?:pop|shift)$/.test(methodName);
17020
17021       lodash.prototype[methodName] = function() {
17022         var args = arguments;
17023         if (retUnwrapped && !this.__chain__) {
17024           var value = this.value();
17025           return func.apply(isArray(value) ? value : [], args);
17026         }
17027         return this[chainName](function(value) {
17028           return func.apply(isArray(value) ? value : [], args);
17029         });
17030       };
17031     });
17032
17033     // Map minified method names to their real names.
17034     baseForOwn(LazyWrapper.prototype, function(func, methodName) {
17035       var lodashFunc = lodash[methodName];
17036       if (lodashFunc) {
17037         var key = (lodashFunc.name + ''),
17038             names = realNames[key] || (realNames[key] = []);
17039
17040         names.push({ 'name': methodName, 'func': lodashFunc });
17041       }
17042     });
17043
17044     realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{
17045       'name': 'wrapper',
17046       'func': undefined
17047     }];
17048
17049     // Add methods to `LazyWrapper`.
17050     LazyWrapper.prototype.clone = lazyClone;
17051     LazyWrapper.prototype.reverse = lazyReverse;
17052     LazyWrapper.prototype.value = lazyValue;
17053
17054     // Add chain sequence methods to the `lodash` wrapper.
17055     lodash.prototype.at = wrapperAt;
17056     lodash.prototype.chain = wrapperChain;
17057     lodash.prototype.commit = wrapperCommit;
17058     lodash.prototype.next = wrapperNext;
17059     lodash.prototype.plant = wrapperPlant;
17060     lodash.prototype.reverse = wrapperReverse;
17061     lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
17062
17063     // Add lazy aliases.
17064     lodash.prototype.first = lodash.prototype.head;
17065
17066     if (symIterator) {
17067       lodash.prototype[symIterator] = wrapperToIterator;
17068     }
17069     return lodash;
17070   });
17071
17072   /*--------------------------------------------------------------------------*/
17073
17074   // Export lodash.
17075   var _ = runInContext();
17076
17077   // Some AMD build optimizers, like r.js, check for condition patterns like:
17078   if (typeof undefined == 'function' && typeof undefined.amd == 'object' && undefined.amd) {
17079     // Expose Lodash on the global object to prevent errors when Lodash is
17080     // loaded by a script tag in the presence of an AMD loader.
17081     // See http://requirejs.org/docs/errors.html#mismatch for more details.
17082     // Use `_.noConflict` to remove Lodash from the global object.
17083     root._ = _;
17084
17085     // Define as an anonymous module so, through path mapping, it can be
17086     // referenced as the "underscore" module.
17087     undefined(function() {
17088       return _;
17089     });
17090   }
17091   // Check for `exports` after `define` in case a build optimizer adds it.
17092   else if (freeModule) {
17093     // Export for Node.js.
17094     (freeModule.exports = _)._ = _;
17095     // Export for CommonJS support.
17096     freeExports._ = _;
17097   }
17098   else {
17099     // Export to the global object.
17100     root._ = _;
17101   }
17102 }.call(commonjsGlobal));
17103 });
17104
17105
17106
17107 var lodash$1 = Object.freeze({
17108         default: lodash,
17109         __moduleExports: lodash
17110 });
17111
17112 function osmIsInterestingTag(key) {
17113     return key !== 'attribution' &&
17114         key !== 'created_by' &&
17115         key !== 'source' &&
17116         key !== 'odbl' &&
17117         key.indexOf('tiger:') !== 0;
17118
17119 }
17120
17121
17122 var osmOneWayTags = {
17123     'aerialway': {
17124         'chair_lift': true,
17125         'mixed_lift': true,
17126         't-bar': true,
17127         'j-bar': true,
17128         'platter': true,
17129         'rope_tow': true,
17130         'magic_carpet': true,
17131         'yes': true
17132     },
17133     'highway': {
17134         'motorway': true,
17135         'motorway_link': true
17136     },
17137     'junction': {
17138         'roundabout': true
17139     },
17140     'man_made': {
17141         'piste:halfpipe': true
17142     },
17143     'piste:type': {
17144         'downhill': true,
17145         'sled': true,
17146         'yes': true
17147     },
17148     'waterway': {
17149         'canal': true,
17150         'ditch': true,
17151         'drain': true,
17152         'river': true,
17153         'stream': true
17154     }
17155 };
17156
17157
17158 var osmPavedTags = {
17159     'surface': {
17160         'paved': true,
17161         'asphalt': true,
17162         'concrete': true
17163     },
17164     'tracktype': {
17165         'grade1': true
17166     }
17167 };
17168
17169 var dataWikipedia = [
17170     [
17171         "Abkhazian",
17172         "Аҧсшәа",
17173         "ab"
17174     ],
17175     [
17176         "Achinese",
17177         "Acèh",
17178         "ace"
17179     ],
17180     [
17181         "Adyghe",
17182         "адыгабзэ",
17183         "ady"
17184     ],
17185     [
17186         "Afrikaans",
17187         "Afrikaans",
17188         "af"
17189     ],
17190     [
17191         "Akan",
17192         "Akan",
17193         "ak"
17194     ],
17195     [
17196         "Alemannisch",
17197         "Alemannisch",
17198         "als"
17199     ],
17200     [
17201         "Amharic",
17202         "አማርኛ",
17203         "am"
17204     ],
17205     [
17206         "Aragonese",
17207         "aragonés",
17208         "an"
17209     ],
17210     [
17211         "Old English",
17212         "Ænglisc",
17213         "ang"
17214     ],
17215     [
17216         "Arabic",
17217         "العربية",
17218         "ar"
17219     ],
17220     [
17221         "Aramaic",
17222         "ܐܪܡܝܐ",
17223         "arc"
17224     ],
17225     [
17226         "Egyptian Arabic",
17227         "مصرى",
17228         "arz"
17229     ],
17230     [
17231         "Assamese",
17232         "অসমীয়া",
17233         "as"
17234     ],
17235     [
17236         "Asturian",
17237         "asturianu",
17238         "ast"
17239     ],
17240     [
17241         "Avaric",
17242         "авар",
17243         "av"
17244     ],
17245     [
17246         "Aymara",
17247         "Aymar aru",
17248         "ay"
17249     ],
17250     [
17251         "Azerbaijani",
17252         "azərbaycanca",
17253         "az"
17254     ],
17255     [
17256         "تۆرکجه",
17257         "تۆرکجه",
17258         "azb"
17259     ],
17260     [
17261         "Bashkir",
17262         "башҡортса",
17263         "ba"
17264     ],
17265     [
17266         "Bavarian",
17267         "Boarisch",
17268         "bar"
17269     ],
17270     [
17271         "Samogitian",
17272         "žemaitėška",
17273         "bat-smg"
17274     ],
17275     [
17276         "Bikol Central",
17277         "Bikol Central",
17278         "bcl"
17279     ],
17280     [
17281         "Belarusian",
17282         "беларуская",
17283         "be"
17284     ],
17285     [
17286         "беларуская (тарашкевіца)‎",
17287         "беларуская (тарашкевіца)‎",
17288         "be-x-old"
17289     ],
17290     [
17291         "Bulgarian",
17292         "български",
17293         "bg"
17294     ],
17295     [
17296         "भोजपुरी",
17297         "भोजपुरी",
17298         "bh"
17299     ],
17300     [
17301         "Bislama",
17302         "Bislama",
17303         "bi"
17304     ],
17305     [
17306         "Banjar",
17307         "Bahasa Banjar",
17308         "bjn"
17309     ],
17310     [
17311         "Bambara",
17312         "bamanankan",
17313         "bm"
17314     ],
17315     [
17316         "Bangla",
17317         "বাংলা",
17318         "bn"
17319     ],
17320     [
17321         "Tibetan",
17322         "བོད་ཡིག",
17323         "bo"
17324     ],
17325     [
17326         "Bishnupriya",
17327         "বিষ্ণুপ্রিয়া মণিপুরী",
17328         "bpy"
17329     ],
17330     [
17331         "Breton",
17332         "brezhoneg",
17333         "br"
17334     ],
17335     [
17336         "Bosnian",
17337         "bosanski",
17338         "bs"
17339     ],
17340     [
17341         "Buginese",
17342         "ᨅᨔ ᨕᨘᨁᨗ",
17343         "bug"
17344     ],
17345     [
17346         "буряад",
17347         "буряад",
17348         "bxr"
17349     ],
17350     [
17351         "Catalan",
17352         "català",
17353         "ca"
17354     ],
17355     [
17356         "Chavacano de Zamboanga",
17357         "Chavacano de Zamboanga",
17358         "cbk-zam"
17359     ],
17360     [
17361         "Min Dong Chinese",
17362         "Mìng-dĕ̤ng-ngṳ̄",
17363         "cdo"
17364     ],
17365     [
17366         "Chechen",
17367         "нохчийн",
17368         "ce"
17369     ],
17370     [
17371         "Cebuano",
17372         "Cebuano",
17373         "ceb"
17374     ],
17375     [
17376         "Chamorro",
17377         "Chamoru",
17378         "ch"
17379     ],
17380     [
17381         "Cherokee",
17382         "ᏣᎳᎩ",
17383         "chr"
17384     ],
17385     [
17386         "Cheyenne",
17387         "Tsetsêhestâhese",
17388         "chy"
17389     ],
17390     [
17391         "Central Kurdish",
17392         "کوردیی ناوەندی",
17393         "ckb"
17394     ],
17395     [
17396         "Corsican",
17397         "corsu",
17398         "co"
17399     ],
17400     [
17401         "Cree",
17402         "Nēhiyawēwin / ᓀᐦᐃᔭᐍᐏᐣ",
17403         "cr"
17404     ],
17405     [
17406         "Crimean Turkish",
17407         "qırımtatarca",
17408         "crh"
17409     ],
17410     [
17411         "Czech",
17412         "čeština",
17413         "cs"
17414     ],
17415     [
17416         "Kashubian",
17417         "kaszëbsczi",
17418         "csb"
17419     ],
17420     [
17421         "Church Slavic",
17422         "словѣньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ",
17423         "cu"
17424     ],
17425     [
17426         "Chuvash",
17427         "Чӑвашла",
17428         "cv"
17429     ],
17430     [
17431         "Welsh",
17432         "Cymraeg",
17433         "cy"
17434     ],
17435     [
17436         "Danish",
17437         "dansk",
17438         "da"
17439     ],
17440     [
17441         "German",
17442         "Deutsch",
17443         "de"
17444     ],
17445     [
17446         "Zazaki",
17447         "Zazaki",
17448         "diq"
17449     ],
17450     [
17451         "Lower Sorbian",
17452         "dolnoserbski",
17453         "dsb"
17454     ],
17455     [
17456         "Divehi",
17457         "ދިވެހިބަސް",
17458         "dv"
17459     ],
17460     [
17461         "Dzongkha",
17462         "ཇོང་ཁ",
17463         "dz"
17464     ],
17465     [
17466         "Ewe",
17467         "eʋegbe",
17468         "ee"
17469     ],
17470     [
17471         "Greek",
17472         "Ελληνικά",
17473         "el"
17474     ],
17475     [
17476         "Emiliano-Romagnolo",
17477         "emiliàn e rumagnòl",
17478         "eml"
17479     ],
17480     [
17481         "English",
17482         "English",
17483         "en"
17484     ],
17485     [
17486         "Esperanto",
17487         "Esperanto",
17488         "eo"
17489     ],
17490     [
17491         "Spanish",
17492         "español",
17493         "es"
17494     ],
17495     [
17496         "Estonian",
17497         "eesti",
17498         "et"
17499     ],
17500     [
17501         "Basque",
17502         "euskara",
17503         "eu"
17504     ],
17505     [
17506         "Extremaduran",
17507         "estremeñu",
17508         "ext"
17509     ],
17510     [
17511         "Persian",
17512         "فارسی",
17513         "fa"
17514     ],
17515     [
17516         "Fulah",
17517         "Fulfulde",
17518         "ff"
17519     ],
17520     [
17521         "Finnish",
17522         "suomi",
17523         "fi"
17524     ],
17525     [
17526         "Võro",
17527         "Võro",
17528         "fiu-vro"
17529     ],
17530     [
17531         "Fijian",
17532         "Na Vosa Vakaviti",
17533         "fj"
17534     ],
17535     [
17536         "Faroese",
17537         "føroyskt",
17538         "fo"
17539     ],
17540     [
17541         "French",
17542         "français",
17543         "fr"
17544     ],
17545     [
17546         "Arpitan",
17547         "arpetan",
17548         "frp"
17549     ],
17550     [
17551         "Northern Frisian",
17552         "Nordfriisk",
17553         "frr"
17554     ],
17555     [
17556         "Friulian",
17557         "furlan",
17558         "fur"
17559     ],
17560     [
17561         "Western Frisian",
17562         "Frysk",
17563         "fy"
17564     ],
17565     [
17566         "Irish",
17567         "Gaeilge",
17568         "ga"
17569     ],
17570     [
17571         "Gagauz",
17572         "Gagauz",
17573         "gag"
17574     ],
17575     [
17576         "Gan Chinese",
17577         "贛語",
17578         "gan"
17579     ],
17580     [
17581         "Scottish Gaelic",
17582         "Gàidhlig",
17583         "gd"
17584     ],
17585     [
17586         "Galician",
17587         "galego",
17588         "gl"
17589     ],
17590     [
17591         "Gilaki",
17592         "گیلکی",
17593         "glk"
17594     ],
17595     [
17596         "Guarani",
17597         "Avañe'ẽ",
17598         "gn"
17599     ],
17600     [
17601         "Goan Konkani",
17602         "गोंयची कोंकणी / Gõychi Konknni",
17603         "gom"
17604     ],
17605     [
17606         "Gothic",
17607         "𐌲𐌿𐍄𐌹𐍃𐌺",
17608         "got"
17609     ],
17610     [
17611         "Gujarati",
17612         "ગુજરાતી",
17613         "gu"
17614     ],
17615     [
17616         "Manx",
17617         "Gaelg",
17618         "gv"
17619     ],
17620     [
17621         "Hausa",
17622         "Hausa",
17623         "ha"
17624     ],
17625     [
17626         "Hakka Chinese",
17627         "客家語/Hak-kâ-ngî",
17628         "hak"
17629     ],
17630     [
17631         "Hawaiian",
17632         "Hawaiʻi",
17633         "haw"
17634     ],
17635     [
17636         "Hebrew",
17637         "עברית",
17638         "he"
17639     ],
17640     [
17641         "Hindi",
17642         "हिन्दी",
17643         "hi"
17644     ],
17645     [
17646         "Fiji Hindi",
17647         "Fiji Hindi",
17648         "hif"
17649     ],
17650     [
17651         "Croatian",
17652         "hrvatski",
17653         "hr"
17654     ],
17655     [
17656         "Upper Sorbian",
17657         "hornjoserbsce",
17658         "hsb"
17659     ],
17660     [
17661         "Haitian Creole",
17662         "Kreyòl ayisyen",
17663         "ht"
17664     ],
17665     [
17666         "Hungarian",
17667         "magyar",
17668         "hu"
17669     ],
17670     [
17671         "Armenian",
17672         "Հայերեն",
17673         "hy"
17674     ],
17675     [
17676         "Interlingua",
17677         "interlingua",
17678         "ia"
17679     ],
17680     [
17681         "Indonesian",
17682         "Bahasa Indonesia",
17683         "id"
17684     ],
17685     [
17686         "Interlingue",
17687         "Interlingue",
17688         "ie"
17689     ],
17690     [
17691         "Igbo",
17692         "Igbo",
17693         "ig"
17694     ],
17695     [
17696         "Inupiaq",
17697         "Iñupiak",
17698         "ik"
17699     ],
17700     [
17701         "Iloko",
17702         "Ilokano",
17703         "ilo"
17704     ],
17705     [
17706         "Ido",
17707         "Ido",
17708         "io"
17709     ],
17710     [
17711         "Icelandic",
17712         "íslenska",
17713         "is"
17714     ],
17715     [
17716         "Italian",
17717         "italiano",
17718         "it"
17719     ],
17720     [
17721         "Inuktitut",
17722         "ᐃᓄᒃᑎᑐᑦ/inuktitut",
17723         "iu"
17724     ],
17725     [
17726         "Japanese",
17727         "日本語",
17728         "ja"
17729     ],
17730     [
17731         "Jamaican Creole English",
17732         "Patois",
17733         "jam"
17734     ],
17735     [
17736         "Lojban",
17737         "la .lojban.",
17738         "jbo"
17739     ],
17740     [
17741         "Javanese",
17742         "Basa Jawa",
17743         "jv"
17744     ],
17745     [
17746         "Georgian",
17747         "ქართული",
17748         "ka"
17749     ],
17750     [
17751         "Kara-Kalpak",
17752         "Qaraqalpaqsha",
17753         "kaa"
17754     ],
17755     [
17756         "Kabyle",
17757         "Taqbaylit",
17758         "kab"
17759     ],
17760     [
17761         "Kabardian",
17762         "Адыгэбзэ",
17763         "kbd"
17764     ],
17765     [
17766         "Kongo",
17767         "Kongo",
17768         "kg"
17769     ],
17770     [
17771         "Kikuyu",
17772         "Gĩkũyũ",
17773         "ki"
17774     ],
17775     [
17776         "Kazakh",
17777         "қазақша",
17778         "kk"
17779     ],
17780     [
17781         "Kalaallisut",
17782         "kalaallisut",
17783         "kl"
17784     ],
17785     [
17786         "Khmer",
17787         "ភាសាខ្មែរ",
17788         "km"
17789     ],
17790     [
17791         "Kannada",
17792         "ಕನ್ನಡ",
17793         "kn"
17794     ],
17795     [
17796         "Korean",
17797         "한국어",
17798         "ko"
17799     ],
17800     [
17801         "Komi-Permyak",
17802         "Перем Коми",
17803         "koi"
17804     ],
17805     [
17806         "Karachay-Balkar",
17807         "къарачай-малкъар",
17808         "krc"
17809     ],
17810     [
17811         "Kashmiri",
17812         "कॉशुर / کٲشُر",
17813         "ks"
17814     ],
17815     [
17816         "Colognian",
17817         "Ripoarisch",
17818         "ksh"
17819     ],
17820     [
17821         "Kurdish",
17822         "Kurdî",
17823         "ku"
17824     ],
17825     [
17826         "Komi",
17827         "коми",
17828         "kv"
17829     ],
17830     [
17831         "Cornish",
17832         "kernowek",
17833         "kw"
17834     ],
17835     [
17836         "Kyrgyz",
17837         "Кыргызча",
17838         "ky"
17839     ],
17840     [
17841         "Latin",
17842         "Latina",
17843         "la"
17844     ],
17845     [
17846         "Ladino",
17847         "Ladino",
17848         "lad"
17849     ],
17850     [
17851         "Luxembourgish",
17852         "Lëtzebuergesch",
17853         "lb"
17854     ],
17855     [
17856         "лакку",
17857         "лакку",
17858         "lbe"
17859     ],
17860     [
17861         "Lezghian",
17862         "лезги",
17863         "lez"
17864     ],
17865     [
17866         "Ganda",
17867         "Luganda",
17868         "lg"
17869     ],
17870     [
17871         "Limburgish",
17872         "Limburgs",
17873         "li"
17874     ],
17875     [
17876         "Ligurian",
17877         "Ligure",
17878         "lij"
17879     ],
17880     [
17881         "Lombard",
17882         "lumbaart",
17883         "lmo"
17884     ],
17885     [
17886         "Lingala",
17887         "lingála",
17888         "ln"
17889     ],
17890     [
17891         "Lao",
17892         "ລາວ",
17893         "lo"
17894     ],
17895     [
17896         "Northern Luri",
17897         "لۊری شومالی",
17898         "lrc"
17899     ],
17900     [
17901         "Lithuanian",
17902         "lietuvių",
17903         "lt"
17904     ],
17905     [
17906         "Latgalian",
17907         "latgaļu",
17908         "ltg"
17909     ],
17910     [
17911         "Latvian",
17912         "latviešu",
17913         "lv"
17914     ],
17915     [
17916         "Maithili",
17917         "मैथिली",
17918         "mai"
17919     ],
17920     [
17921         "Basa Banyumasan",
17922         "Basa Banyumasan",
17923         "map-bms"
17924     ],
17925     [
17926         "Moksha",
17927         "мокшень",
17928         "mdf"
17929     ],
17930     [
17931         "Malagasy",
17932         "Malagasy",
17933         "mg"
17934     ],
17935     [
17936         "Eastern Mari",
17937         "олык марий",
17938         "mhr"
17939     ],
17940     [
17941         "Maori",
17942         "Māori",
17943         "mi"
17944     ],
17945     [
17946         "Minangkabau",
17947         "Baso Minangkabau",
17948         "min"
17949     ],
17950     [
17951         "Macedonian",
17952         "македонски",
17953         "mk"
17954     ],
17955     [
17956         "Malayalam",
17957         "മലയാളം",
17958         "ml"
17959     ],
17960     [
17961         "Mongolian",
17962         "монгол",
17963         "mn"
17964     ],
17965     [
17966         "Marathi",
17967         "मराठी",
17968         "mr"
17969     ],
17970     [
17971         "Western Mari",
17972         "кырык мары",
17973         "mrj"
17974     ],
17975     [
17976         "Malay",
17977         "Bahasa Melayu",
17978         "ms"
17979     ],
17980     [
17981         "Maltese",
17982         "Malti",
17983         "mt"
17984     ],
17985     [
17986         "Mirandese",
17987         "Mirandés",
17988         "mwl"
17989     ],
17990     [
17991         "Burmese",
17992         "မြန်မာဘာသာ",
17993         "my"
17994     ],
17995     [
17996         "Erzya",
17997         "эрзянь",
17998         "myv"
17999     ],
18000     [
18001         "Mazanderani",
18002         "مازِرونی",
18003         "mzn"
18004     ],
18005     [
18006         "Nauru",
18007         "Dorerin Naoero",
18008         "na"
18009     ],
18010     [
18011         "Nāhuatl",
18012         "Nāhuatl",
18013         "nah"
18014     ],
18015     [
18016         "Neapolitan",
18017         "Napulitano",
18018         "nap"
18019     ],
18020     [
18021         "Low German",
18022         "Plattdüütsch",
18023         "nds"
18024     ],
18025     [
18026         "Low Saxon",
18027         "Nedersaksies",
18028         "nds-nl"
18029     ],
18030     [
18031         "Nepali",
18032         "नेपाली",
18033         "ne"
18034     ],
18035     [
18036         "Newari",
18037         "नेपाल भाषा",
18038         "new"
18039     ],
18040     [
18041         "Dutch",
18042         "Nederlands",
18043         "nl"
18044     ],
18045     [
18046         "Norwegian Nynorsk",
18047         "norsk nynorsk",
18048         "nn"
18049     ],
18050     [
18051         "Norwegian",
18052         "norsk bokmål",
18053         "no"
18054     ],
18055     [
18056         "Novial",
18057         "Novial",
18058         "nov"
18059     ],
18060     [
18061         "Nouormand",
18062         "Nouormand",
18063         "nrm"
18064     ],
18065     [
18066         "Northern Sotho",
18067         "Sesotho sa Leboa",
18068         "nso"
18069     ],
18070     [
18071         "Navajo",
18072         "Diné bizaad",
18073         "nv"
18074     ],
18075     [
18076         "Nyanja",
18077         "Chi-Chewa",
18078         "ny"
18079     ],
18080     [
18081         "Occitan",
18082         "occitan",
18083         "oc"
18084     ],
18085     [
18086         "Livvi-Karelian",
18087         "Livvinkarjala",
18088         "olo"
18089     ],
18090     [
18091         "Oromo",
18092         "Oromoo",
18093         "om"
18094     ],
18095     [
18096         "Odia",
18097         "ଓଡ଼ିଆ",
18098         "or"
18099     ],
18100     [
18101         "Ossetic",
18102         "Ирон",
18103         "os"
18104     ],
18105     [
18106         "Punjabi",
18107         "ਪੰਜਾਬੀ",
18108         "pa"
18109     ],
18110     [
18111         "Pangasinan",
18112         "Pangasinan",
18113         "pag"
18114     ],
18115     [
18116         "Pampanga",
18117         "Kapampangan",
18118         "pam"
18119     ],
18120     [
18121         "Papiamento",
18122         "Papiamentu",
18123         "pap"
18124     ],
18125     [
18126         "Picard",
18127         "Picard",
18128         "pcd"
18129     ],
18130     [
18131         "Pennsylvania German",
18132         "Deitsch",
18133         "pdc"
18134     ],
18135     [
18136         "Palatine German",
18137         "Pälzisch",
18138         "pfl"
18139     ],
18140     [
18141         "Pali",
18142         "पालि",
18143         "pi"
18144     ],
18145     [
18146         "Norfuk / Pitkern",
18147         "Norfuk / Pitkern",
18148         "pih"
18149     ],
18150     [
18151         "Polish",
18152         "polski",
18153         "pl"
18154     ],
18155     [
18156         "Piedmontese",
18157         "Piemontèis",
18158         "pms"
18159     ],
18160     [
18161         "Western Punjabi",
18162         "پنجابی",
18163         "pnb"
18164     ],
18165     [
18166         "Pontic",
18167         "Ποντιακά",
18168         "pnt"
18169     ],
18170     [
18171         "Pashto",
18172         "پښتو",
18173         "ps"
18174     ],
18175     [
18176         "Portuguese",
18177         "português",
18178         "pt"
18179     ],
18180     [
18181         "Quechua",
18182         "Runa Simi",
18183         "qu"
18184     ],
18185     [
18186         "Romansh",
18187         "rumantsch",
18188         "rm"
18189     ],
18190     [
18191         "Romani",
18192         "Romani",
18193         "rmy"
18194     ],
18195     [
18196         "Rundi",
18197         "Kirundi",
18198         "rn"
18199     ],
18200     [
18201         "Romanian",
18202         "română",
18203         "ro"
18204     ],
18205     [
18206         "Aromanian",
18207         "armãneashti",
18208         "roa-rup"
18209     ],
18210     [
18211         "tarandíne",
18212         "tarandíne",
18213         "roa-tara"
18214     ],
18215     [
18216         "Russian",
18217         "русский",
18218         "ru"
18219     ],
18220     [
18221         "Rusyn",
18222         "русиньскый",
18223         "rue"
18224     ],
18225     [
18226         "Kinyarwanda",
18227         "Kinyarwanda",
18228         "rw"
18229     ],
18230     [
18231         "Sanskrit",
18232         "संस्कृतम्",
18233         "sa"
18234     ],
18235     [
18236         "Sakha",
18237         "саха тыла",
18238         "sah"
18239     ],
18240     [
18241         "Sardinian",
18242         "sardu",
18243         "sc"
18244     ],
18245     [
18246         "Sicilian",
18247         "sicilianu",
18248         "scn"
18249     ],
18250     [
18251         "Scots",
18252         "Scots",
18253         "sco"
18254     ],
18255     [
18256         "Sindhi",
18257         "سنڌي",
18258         "sd"
18259     ],
18260     [
18261         "Northern Sami",
18262         "sámegiella",
18263         "se"
18264     ],
18265     [
18266         "Sango",
18267         "Sängö",
18268         "sg"
18269     ],
18270     [
18271         "Serbo-Croatian",
18272         "srpskohrvatski / српскохрватски",
18273         "sh"
18274     ],
18275     [
18276         "Sinhala",
18277         "සිංහල",
18278         "si"
18279     ],
18280     [
18281         "Simple English",
18282         "Simple English",
18283         "simple"
18284     ],
18285     [
18286         "Slovak",
18287         "slovenčina",
18288         "sk"
18289     ],
18290     [
18291         "Slovenian",
18292         "slovenščina",
18293         "sl"
18294     ],
18295     [
18296         "Samoan",
18297         "Gagana Samoa",
18298         "sm"
18299     ],
18300     [
18301         "Shona",
18302         "chiShona",
18303         "sn"
18304     ],
18305     [
18306         "Somali",
18307         "Soomaaliga",
18308         "so"
18309     ],
18310     [
18311         "Albanian",
18312         "shqip",
18313         "sq"
18314     ],
18315     [
18316         "Serbian",
18317         "српски / srpski",
18318         "sr"
18319     ],
18320     [
18321         "Sranan Tongo",
18322         "Sranantongo",
18323         "srn"
18324     ],
18325     [
18326         "Swati",
18327         "SiSwati",
18328         "ss"
18329     ],
18330     [
18331         "Southern Sotho",
18332         "Sesotho",
18333         "st"
18334     ],
18335     [
18336         "Saterland Frisian",
18337         "Seeltersk",
18338         "stq"
18339     ],
18340     [
18341         "Sundanese",
18342         "Basa Sunda",
18343         "su"
18344     ],
18345     [
18346         "Swedish",
18347         "svenska",
18348         "sv"
18349     ],
18350     [
18351         "Swahili",
18352         "Kiswahili",
18353         "sw"
18354     ],
18355     [
18356         "Silesian",
18357         "ślůnski",
18358         "szl"
18359     ],
18360     [
18361         "Tamil",
18362         "தமிழ்",
18363         "ta"
18364     ],
18365     [
18366         "Tulu",
18367         "ತುಳು",
18368         "tcy"
18369     ],
18370     [
18371         "Telugu",
18372         "తెలుగు",
18373         "te"
18374     ],
18375     [
18376         "Tetum",
18377         "tetun",
18378         "tet"
18379     ],
18380     [
18381         "Tajik",
18382         "тоҷикӣ",
18383         "tg"
18384     ],
18385     [
18386         "Thai",
18387         "ไทย",
18388         "th"
18389     ],
18390     [
18391         "Tigrinya",
18392         "ትግርኛ",
18393         "ti"
18394     ],
18395     [
18396         "Turkmen",
18397         "Türkmençe",
18398         "tk"
18399     ],
18400     [
18401         "Tagalog",
18402         "Tagalog",
18403         "tl"
18404     ],
18405     [
18406         "Tswana",
18407         "Setswana",
18408         "tn"
18409     ],
18410     [
18411         "Tongan",
18412         "lea faka-Tonga",
18413         "to"
18414     ],
18415     [
18416         "Tok Pisin",
18417         "Tok Pisin",
18418         "tpi"
18419     ],
18420     [
18421         "Turkish",
18422         "Türkçe",
18423         "tr"
18424     ],
18425     [
18426         "Tsonga",
18427         "Xitsonga",
18428         "ts"
18429     ],
18430     [
18431         "Tatar",
18432         "татарча/tatarça",
18433         "tt"
18434     ],
18435     [
18436         "Tumbuka",
18437         "chiTumbuka",
18438         "tum"
18439     ],
18440     [
18441         "Twi",
18442         "Twi",
18443         "tw"
18444     ],
18445     [
18446         "Tahitian",
18447         "reo tahiti",
18448         "ty"
18449     ],
18450     [
18451         "Tuvinian",
18452         "тыва дыл",
18453         "tyv"
18454     ],
18455     [
18456         "Udmurt",
18457         "удмурт",
18458         "udm"
18459     ],
18460     [
18461         "Uyghur",
18462         "ئۇيغۇرچە / Uyghurche",
18463         "ug"
18464     ],
18465     [
18466         "Ukrainian",
18467         "українська",
18468         "uk"
18469     ],
18470     [
18471         "Urdu",
18472         "اردو",
18473         "ur"
18474     ],
18475     [
18476         "Uzbek",
18477         "oʻzbekcha/ўзбекча",
18478         "uz"
18479     ],
18480     [
18481         "Venda",
18482         "Tshivenda",
18483         "ve"
18484     ],
18485     [
18486         "Venetian",
18487         "vèneto",
18488         "vec"
18489     ],
18490     [
18491         "Veps",
18492         "vepsän kel’",
18493         "vep"
18494     ],
18495     [
18496         "Vietnamese",
18497         "Tiếng Việt",
18498         "vi"
18499     ],
18500     [
18501         "West Flemish",
18502         "West-Vlams",
18503         "vls"
18504     ],
18505     [
18506         "Volapük",
18507         "Volapük",
18508         "vo"
18509     ],
18510     [
18511         "Walloon",
18512         "walon",
18513         "wa"
18514     ],
18515     [
18516         "Waray",
18517         "Winaray",
18518         "war"
18519     ],
18520     [
18521         "Wolof",
18522         "Wolof",
18523         "wo"
18524     ],
18525     [
18526         "Wu Chinese",
18527         "吴语",
18528         "wuu"
18529     ],
18530     [
18531         "Kalmyk",
18532         "хальмг",
18533         "xal"
18534     ],
18535     [
18536         "Xhosa",
18537         "isiXhosa",
18538         "xh"
18539     ],
18540     [
18541         "Mingrelian",
18542         "მარგალური",
18543         "xmf"
18544     ],
18545     [
18546         "Yiddish",
18547         "ייִדיש",
18548         "yi"
18549     ],
18550     [
18551         "Yoruba",
18552         "Yorùbá",
18553         "yo"
18554     ],
18555     [
18556         "Zhuang",
18557         "Vahcuengh",
18558         "za"
18559     ],
18560     [
18561         "Zeelandic",
18562         "Zeêuws",
18563         "zea"
18564     ],
18565     [
18566         "Chinese",
18567         "中文",
18568         "zh"
18569     ],
18570     [
18571         "Classical Chinese",
18572         "文言",
18573         "zh-classical"
18574     ],
18575     [
18576         "Chinese (Min Nan)",
18577         "Bân-lâm-gú",
18578         "zh-min-nan"
18579     ],
18580     [
18581         "Cantonese",
18582         "粵語",
18583         "zh-yue"
18584     ],
18585     [
18586         "Zulu",
18587         "isiZulu",
18588         "zu"
18589     ]
18590 ];
18591
18592 var amenity = {"fuel":{"76":{"count":314},"Neste":{"count":189},"BP":{"count":2511},"Shell":{"count":8380},"Agip":{"count":2651},"Migrol":{"count":65},"Avia":{"count":897},"Texaco":{"count":680},"Total":{"count":2607},"Statoil":{"count":596},"Esso":{"count":3652},"Jet":{"count":441},"Avanti":{"count":90},"Sainsbury's":{"count":58},"OMV":{"count":701},"Aral":{"count":1339},"Tesco":{"count":197},"JET":{"count":180},"Morrisons":{"count":111},"United":{"count":91},"Canadian Tire":{"count":66},"Mobil":{"count":613},"Caltex":{"count":1001},"Sunoco":{"count":355},"Q8":{"count":1161},"ABC":{"count":79},"ARAL":{"count":375},"CEPSA":{"count":1018},"BFT":{"count":89},"Petron":{"count":878},"Intermarché":{"count":434},"Total Access":{"count":51},"Super U":{"count":124},"Auchan":{"count":53},"Elf":{"count":129},"Carrefour":{"count":205},"Station Service E. Leclerc":{"count":530},"Shell Express":{"count":131},"Hess":{"count":127},"Flying V":{"count":129},"bft":{"count":168},"Gulf":{"count":199},"PTT":{"count":191},"St1":{"count":100},"Teboil":{"count":115},"HEM":{"count":212},"GALP":{"count":626},"OK":{"count":163},"ÖMV":{"count":101},"Tinq":{"count":215},"OKQ8":{"count":186},"Repsol":{"count":424},"Westfalen":{"count":96},"Esso Express":{"count":98},"Raiffeisenbank":{"count":117},"Tamoil":{"count":866},"Engen":{"count":241},"Sasol":{"count":59},"Topaz":{"count":78},"LPG":{"count":174},"Coop":{"count":62},"Orlen":{"count":598},"Oilibya":{"count":68},"Tango":{"count":122},"Star":{"count":319},"Петрол":{"count":84},"Cepsa":{"count":96},"OIL!":{"count":63},"Ultramar":{"count":125},"Irving":{"count":87},"Lukoil":{"count":701},"Petro-Canada":{"count":489},"7-Eleven":{"count":488},"Agrola":{"count":69},"Husky":{"count":126},"Slovnaft":{"count":219},"Sheetz":{"count":134},"Mol":{"count":61},"Petronas":{"count":159},"Газпромнефть":{"count":748},"Лукойл":{"count":1477},"Elan":{"count":112},"Роснефть":{"count":638},"Turmöl":{"count":57},"Neste A24":{"count":55},"Marathon":{"count":189},"Valero":{"count":366},"Eni":{"count":236},"Chevron":{"count":954},"ТНК":{"count":520},"REPSOL":{"count":1603},"MOL":{"count":228},"Bliska":{"count":150},"Api":{"count":302},"Arco":{"count":179},"Pemex":{"count":423},"Exxon":{"count":506},"Coles Express":{"count":115},"Petrom":{"count":259},"PETRONOR":{"count":207},"Rompetrol":{"count":174},"Lotos":{"count":178},"ОМВ":{"count":60},"BR":{"count":129},"Copec":{"count":505},"Petrobras":{"count":270},"Liberty":{"count":55},"IP":{"count":871},"Erg":{"count":596},"Eneos":{"count":97},"Citgo":{"count":279},"Metano":{"count":208},"Сургутнефтегаз":{"count":61},"EKO":{"count":59},"Eko":{"count":58},"Indipend.":{"count":172},"IES":{"count":63},"TotalErg":{"count":89},"Cenex":{"count":115},"ПТК":{"count":82},"HP":{"count":79},"Phillips 66":{"count":216},"CARREFOUR":{"count":74},"ERG":{"count":76},"Speedway":{"count":148},"Benzina":{"count":96},"Татнефть":{"count":264},"Terpel":{"count":259},"WOG":{"count":189},"Seaoil":{"count":54},"АЗС":{"count":1077},"Kwik Trip":{"count":108},"Wawa":{"count":89},"Pertamina":{"count":186},"COSMO":{"count":64},"Z":{"count":76},"Indian Oil":{"count":183},"АГЗС":{"count":494},"INA":{"count":121},"JOMO":{"count":62},"Holiday":{"count":97},"YPF":{"count":70},"IDEMITSU":{"count":87},"ENEOS":{"count":736},"Bharat Petroleum":{"count":64},"CAMPSA":{"count":615},"Casey's General Store":{"count":190},"Башнефть":{"count":60},"Kangaroo":{"count":60},"コスモ石油 (COSMO)":{"count":136},"MEROIL":{"count":77},"1-2-3":{"count":71},"出光":{"count":228,"tags":{"name:en":"IDEMITSU"}},"НК Альянс":{"count":88},"Sinclair":{"count":100},"Conoco":{"count":189},"SPBU":{"count":54},"Макпетрол":{"count":109},"Circle K":{"count":166},"Posto Ipiranga":{"count":70},"Posto Shell":{"count":54},"Phoenix":{"count":144},"Ipiranga":{"count":119},"OKKO":{"count":85},"ОККО":{"count":119},"บางจาก":{"count":60},"QuikTrip":{"count":105},"Stewart's":{"count":63},"Posto BR":{"count":68},"ป ต ท":{"count":152},"ปตท":{"count":88},"ANP":{"count":80},"Kum & Go":{"count":80},"Petrolimex":{"count":55},"Sokimex":{"count":66},"Tela":{"count":154},"Posto":{"count":71},"H-E-B":{"count":182},"Укрнафта":{"count":58},"Татнефтепродукт":{"count":54},"Afriquia":{"count":88},"Murphy USA":{"count":67},"昭和シェル (Showa-shell)":{"count":94},"エネオス":{"count":53},"CNG":{"count":94}},"pub":{"Kings Arms":{"count":67},"The Ship":{"count":89},"The White Horse":{"count":204},"The White Hart":{"count":226},"Royal Oak":{"count":150},"The Red Lion":{"count":233},"The Kings Arms":{"count":58},"The Star":{"count":73},"The Anchor":{"count":64},"The Cross Keys":{"count":55},"The Wheatsheaf":{"count":117},"The Crown Inn":{"count":67},"The Kings Head":{"count":53},"The Castle":{"count":62},"The Railway":{"count":102},"The White Lion":{"count":118},"The Bell":{"count":121},"The Bull":{"count":68},"The Plough":{"count":179},"The George":{"count":110},"The Royal Oak":{"count":209},"The Fox":{"count":74},"Prince of Wales":{"count":77},"The Rising Sun":{"count":71},"The Prince of Wales":{"count":51},"The Crown":{"count":244},"The Chequers":{"count":66},"The Swan":{"count":152},"Rose and Crown":{"count":79},"The Victoria":{"count":67},"New Inn":{"count":90},"Royal Hotel":{"count":57},"Red Lion":{"count":207},"Cross Keys":{"count":61},"The Greyhound":{"count":96},"The Black Horse":{"count":94},"The New Inn":{"count":105},"Kings Head":{"count":59},"The Albion":{"count":51},"The Angel":{"count":52},"The Queens Head":{"count":52},"The Ship Inn":{"count":83},"Rose & Crown":{"count":51},"Queens Head":{"count":52},"Irish Pub":{"count":76}},"fast_food":{"Quick":{"count":484},"McDonald's":{"count":12376,"tags":{"cuisine":"burger"}},"Subway":{"count":5576,"tags":{"cuisine":"sandwich"}},"Burger King":{"count":3734,"tags":{"cuisine":"burger"}},"Ali Baba":{"count":61},"Hungry Jacks":{"count":173,"tags":{"cuisine":"burger"}},"Red Rooster":{"count":148},"KFC":{"count":3198,"tags":{"cuisine":"chicken"}},"Domino's Pizza":{"count":985,"tags":{"cuisine":"pizza"}},"Chowking":{"count":142},"Jollibee":{"count":396},"Hesburger":{"count":102},"肯德基":{"count":86},"Wendy's":{"count":1621,"tags":{"cuisine":"burger"}},"Tim Hortons":{"count":323},"Steers":{"count":151},"Hardee's":{"count":268,"tags":{"cuisine":"burger"}},"Arby's":{"count":782},"A&W":{"count":283},"Dairy Queen":{"count":791},"Hallo Pizza":{"count":76},"Fish & Chips":{"count":93},"Harvey's":{"count":90},"麥當勞":{"count":65},"Pizza Pizza":{"count":215},"Kotipizza":{"count":74},"Jack in the Box":{"count":546,"tags":{"cuisine":"burger"}},"Istanbul":{"count":56},"Kochlöffel":{"count":68},"Döner":{"count":228},"Telepizza":{"count":201},"Sibylla":{"count":61},"Carl's Jr.":{"count":298,"tags":{"cuisine":"burger"}},"Quiznos":{"count":266,"tags":{"cuisine":"sandwich"}},"Wimpy":{"count":141},"Sonic":{"count":566,"tags":{"cuisine":"burger"}},"Taco Bell":{"count":1423,"tags":{"cuisine":"mexican"}},"Pizza Nova":{"count":63},"Papa John's":{"count":304,"tags":{"cuisine":"pizza"}},"Nordsee":{"count":159},"Mr. Sub":{"count":103},"Макдоналдс":{"count":324,"tags":{"name:en":"McDonald's"}},"Asia Imbiss":{"count":111},"Chipotle":{"count":290,"tags":{"cuisine":"mexican"}},"マクドナルド":{"count":692,"tags":{"name:en":"McDonald's","cuisine":"burger"}},"In-N-Out Burger":{"count":65},"Jimmy John's":{"count":141},"Jamba Juice":{"count":68},"Робин Сдобин":{"count":82},"Baskin Robbins":{"count":74},"ケンタッキーフライドチキン":{"count":164,"tags":{"name:en":"KFC","cuisine":"chicken"}},"吉野家":{"count":191},"Taco Time":{"count":88},"松屋":{"count":281,"tags":{"name:en":"Matsuya"}},"Little Caesars":{"count":81},"El Pollo Loco":{"count":63},"Del Taco":{"count":141},"White Castle":{"count":80},"Boston Market":{"count":66},"Chick-fil-A":{"count":257,"tags":{"cuisine":"chicken"}},"Panda Express":{"count":238,"tags":{"cuisine":"chinese"}},"Whataburger":{"count":364},"Taco John's":{"count":78},"Теремок":{"count":68},"Culver's":{"count":425},"Five Guys":{"count":141},"Church's Chicken":{"count":95},"Popeye's":{"count":167,"tags":{"cuisine":"chicken"}},"Long John Silver's":{"count":93},"Pollo Campero":{"count":62},"Zaxby's":{"count":51},"すき家":{"count":276,"tags":{"name:en":"SUKIYA"}},"モスバーガー":{"count":257,"tags":{"name:en":"MOS BURGER"}},"Русский Аппетит":{"count":69},"なか卯":{"count":63}},"restaurant":{"Pizza Hut":{"count":1180,"tags":{"cuisine":"pizza"}},"Little Chef":{"count":64},"Adler":{"count":158},"Zur Krone":{"count":90},"Deutsches Haus":{"count":90},"Krone":{"count":171},"Akropolis":{"count":152},"Schützenhaus":{"count":124},"Kreuz":{"count":74},"Waldschänke":{"count":55},"La Piazza":{"count":69},"Lamm":{"count":66},"Zur Sonne":{"count":73},"Zur Linde":{"count":204},"Poseidon":{"count":110},"Shanghai":{"count":82},"Red Lobster":{"count":235},"Zum Löwen":{"count":84},"Swiss Chalet":{"count":107},"Olympia":{"count":74},"Wagamama":{"count":64},"Frankie & Benny's":{"count":66},"Hooters":{"count":103},"Sternen":{"count":78},"Hirschen":{"count":79},"Denny's":{"count":450},"Athen":{"count":68},"Sonne":{"count":126},"Hirsch":{"count":79},"Ratskeller":{"count":150},"La Cantina":{"count":56},"Gasthaus Krone":{"count":56},"El Greco":{"count":86},"Gasthof zur Post":{"count":79},"Nando's":{"count":246},"Löwen":{"count":112},"La Pataterie":{"count":51},"Bella Napoli":{"count":53},"Pizza Express":{"count":262},"Mandarin":{"count":65},"Hong Kong":{"count":83},"Zizzi":{"count":68},"Cracker Barrel":{"count":183},"Rhodos":{"count":81},"Lindenhof":{"count":79},"Milano":{"count":54},"Dolce Vita":{"count":77},"Kirchenwirt":{"count":81},"Kantine":{"count":52},"Ochsen":{"count":95},"Spur":{"count":62},"Mykonos":{"count":59},"Lotus":{"count":66},"Applebee's":{"count":531},"Flunch":{"count":72},"Zur Post":{"count":116},"China Town":{"count":76},"La Dolce Vita":{"count":73},"Waffle House":{"count":207},"Delphi":{"count":88},"Linde":{"count":103},"Outback Steakhouse":{"count":218},"Dionysos":{"count":69},"Kelsey's":{"count":57},"Boston Pizza":{"count":165},"Bella Italia":{"count":132},"Sizzler":{"count":53},"Grüner Baum":{"count":116},"Taj Mahal":{"count":104},"Rössli":{"count":68},"Wimpy":{"count":51},"Traube":{"count":65},"Adria":{"count":52},"Red Robin":{"count":185},"Roma":{"count":61},"San Marco":{"count":67},"Hellas":{"count":55},"La Perla":{"count":67},"Vips":{"count":53},"Panera Bread":{"count":218},"Da Vinci":{"count":54},"Hippopotamus":{"count":96},"Prezzo":{"count":75},"Courtepaille":{"count":106},"Hard Rock Cafe":{"count":70},"Panorama":{"count":61},"デニーズ":{"count":82},"Sportheim":{"count":65},"餃子の王将":{"count":57},"Bären":{"count":60},"Alte Post":{"count":60},"Pizzeria Roma":{"count":51},"China Garden":{"count":66},"Vapiano":{"count":82},"Mamma Mia":{"count":64},"Schwarzer Adler":{"count":57},"IHOP":{"count":317},"Chili's":{"count":328},"Asia":{"count":51},"Olive Garden":{"count":279},"TGI Friday's":{"count":159},"Friendly's":{"count":78},"Buffalo Grill":{"count":202},"Texas Roadhouse":{"count":110},"ガスト":{"count":230,"tags":{"name:en":"Gusto"}},"Sakura":{"count":75},"Mensa":{"count":99},"The Keg":{"count":53},"サイゼリヤ":{"count":93},"La Strada":{"count":52},"Village Inn":{"count":92},"Buffalo Wild Wings":{"count":176},"Peking":{"count":59},"Boston Market":{"count":61},"Round Table Pizza":{"count":53},"Jimmy John's":{"count":69},"California Pizza Kitchen":{"count":61},"Якитория":{"count":77},"Golden Corral":{"count":101},"Perkins":{"count":105},"Ruby Tuesday":{"count":162},"Shari's":{"count":65},"Bob Evans":{"count":129},"바다횟집 (Bada Fish Restaurant)":{"count":55},"Mang Inasal":{"count":84},"Евразия":{"count":102},"ジョナサン":{"count":59},"Longhorn Steakhouse":{"count":66}},"bank":{"Chase":{"count":721},"Commonwealth Bank":{"count":232},"Citibank":{"count":277},"HSBC":{"count":1102},"Barclays":{"count":965},"Westpac":{"count":208},"NAB":{"count":131},"ANZ":{"count":218},"Lloyds Bank":{"count":547},"Landbank":{"count":81},"Sparkasse":{"count":4555},"UCPB":{"count":92},"PNB":{"count":244},"Metrobank":{"count":269},"BDO":{"count":290},"Volksbank":{"count":2591},"BPI":{"count":415},"Postbank":{"count":443},"NatWest":{"count":628},"Raiffeisenbank":{"count":2119},"Yorkshire Bank":{"count":63},"ABSA":{"count":95},"Standard Bank":{"count":109},"FNB":{"count":97},"Deutsche Bank":{"count":855},"SEB":{"count":133},"Commerzbank":{"count":806},"Targobank":{"count":166},"ABN AMRO":{"count":130},"Handelsbanken":{"count":184},"Swedbank":{"count":223},"Kreissparkasse":{"count":600},"UniCredit Bank":{"count":408},"Monte dei Paschi di Siena":{"count":132},"Caja Rural":{"count":99},"Dresdner Bank":{"count":66},"Sparda-Bank":{"count":320},"VÚB":{"count":107},"Slovenská sporiteľňa":{"count":134},"Bank of Montreal":{"count":118},"KBC":{"count":203},"Royal Bank of Scotland":{"count":111},"TSB":{"count":80},"US Bank":{"count":256},"HypoVereinsbank":{"count":561},"Bank Austria":{"count":176},"ING":{"count":496},"Erste Bank":{"count":180},"CIBC":{"count":326},"Scotiabank":{"count":413},"Caisse d'Épargne":{"count":882},"Santander":{"count":1323},"Bank of Scotland":{"count":89},"TD Canada Trust":{"count":450},"BMO":{"count":169},"Danske Bank":{"count":131},"OTP":{"count":192},"Crédit Agricole":{"count":1239},"LCL":{"count":553},"VR-Bank":{"count":430},"ČSOB":{"count":160},"Česká spořitelna":{"count":212},"BNP":{"count":112},"Royal Bank":{"count":65},"Nationwide":{"count":209},"Halifax":{"count":225},"BAWAG PSK":{"count":102},"National Bank":{"count":84},"Nedbank":{"count":80},"First National Bank":{"count":85},"Nordea":{"count":319},"Rabobank":{"count":609},"Sparkasse KölnBonn":{"count":69},"Tatra banka":{"count":67},"Berliner Sparkasse":{"count":62},"Berliner Volksbank":{"count":77},"Wells Fargo":{"count":874},"Credit Suisse":{"count":71},"Société Générale":{"count":634},"Osuuspankki":{"count":75},"Sparkasse Aachen":{"count":56},"Hamburger Sparkasse":{"count":156},"Cassa di Risparmio del Veneto":{"count":68},"BNP Paribas":{"count":617},"Banque Populaire":{"count":433},"BNP Paribas Fortis":{"count":209},"Banco Popular":{"count":291},"Bancaja":{"count":55},"Banesto":{"count":208},"La Caixa":{"count":583},"Santander Consumer Bank":{"count":88},"BRD":{"count":191},"BCR":{"count":143},"Banca Transilvania":{"count":141},"BW-Bank":{"count":97},"Komerční banka":{"count":132},"Banco Pastor":{"count":64},"Stadtsparkasse":{"count":86},"Ulster Bank":{"count":86},"Sberbank":{"count":58},"CIC":{"count":427},"Bancpost":{"count":56},"Caja Madrid":{"count":115},"Maybank":{"count":94},"中国银行":{"count":85},"Unicredit Banca":{"count":243},"Crédit Mutuel":{"count":690},"BBVA":{"count":647},"Intesa San Paolo":{"count":69},"TD Bank":{"count":206},"Belfius":{"count":231},"Bank of America":{"count":924},"RBC":{"count":230},"Alpha Bank":{"count":123},"Сбербанк":{"count":4794},"Россельхозбанк":{"count":201},"Crédit du Nord":{"count":96},"BancoEstado":{"count":80},"Millennium Bank":{"count":414},"State Bank of India":{"count":151},"Беларусбанк":{"count":242},"ING Bank Śląski":{"count":67},"Caixa Geral de Depósitos":{"count":129},"Kreissparkasse Köln":{"count":65},"Banco BCI":{"count":51},"Banco de Chile":{"count":98},"ВТБ24":{"count":326},"UBS":{"count":134},"PKO BP":{"count":265},"Chinabank":{"count":55},"PSBank":{"count":59},"Union Bank":{"count":124},"China Bank":{"count":66},"RCBC":{"count":122},"Unicaja":{"count":83},"BBK":{"count":79},"Ibercaja":{"count":69},"RBS":{"count":143},"Commercial Bank of Ceylon PLC":{"count":79},"Bank of Ireland":{"count":109},"BNL":{"count":87},"Banco Santander":{"count":138},"Banco Itaú":{"count":111},"AIB":{"count":72},"BZ WBK":{"count":77},"Banco do Brasil":{"count":557},"Caixa Econômica Federal":{"count":184},"Fifth Third Bank":{"count":84},"Banca Popolare di Vicenza":{"count":81},"Wachovia":{"count":58},"OLB":{"count":53},"みずほ銀行":{"count":78},"BES":{"count":72},"ICICI Bank":{"count":91},"HDFC Bank":{"count":91},"La Banque Postale":{"count":67},"Pekao SA":{"count":56},"Oberbank":{"count":90},"Bradesco":{"count":295},"Oldenburgische Landesbank":{"count":56},"Bendigo Bank":{"count":93},"Argenta":{"count":86},"AXA":{"count":68},"Axis Bank":{"count":61},"Banco Nación":{"count":67},"GE Money Bank":{"count":72},"Альфа-Банк":{"count":185},"Белагропромбанк":{"count":70},"Caja Círculo":{"count":65},"Banco Galicia":{"count":51},"Eurobank":{"count":97},"Banca Intesa":{"count":62},"Canara Bank":{"count":92},"Cajamar":{"count":77},"Banamex":{"count":149},"Crédit Mutuel de Bretagne":{"count":335},"Davivienda":{"count":83},"Bank Spółdzielczy":{"count":159},"Credit Agricole":{"count":157},"Bankinter":{"count":59},"Banque Nationale":{"count":63},"Bank of the West":{"count":96},"Key Bank":{"count":155},"Western Union":{"count":88},"Citizens Bank":{"count":115},"ПриватБанк":{"count":513},"Security Bank":{"count":78},"Millenium":{"count":60},"Bankia":{"count":149},"三菱東京UFJ銀行":{"count":159},"Caixa":{"count":117},"Banco de Costa Rica":{"count":63},"SunTrust Bank":{"count":73},"Itaú":{"count":338},"PBZ":{"count":52},"中国工商银行":{"count":51},"Bancolombia":{"count":89},"Райффайзен Банк Аваль":{"count":64},"Bancomer":{"count":115},"Banorte":{"count":80},"Alior Bank":{"count":81},"BOC":{"count":51},"Банк Москвы":{"count":118},"ВТБ":{"count":59},"Getin Bank":{"count":55},"Caja Duero":{"count":57},"Regions Bank":{"count":62},"Росбанк":{"count":177},"Banco Estado":{"count":72},"BCI":{"count":68},"SunTrust":{"count":68},"PNC Bank":{"count":254},"신한은행":{"count":217,"tags":{"name:en":"Sinhan Bank"}},"우리은행":{"count":291,"tags":{"name:en":"Uri Bank"}},"국민은행":{"count":165,"tags":{"name:en":"Gungmin Bank"}},"중소기업은행":{"count":52,"tags":{"name:en":"Industrial Bank of Korea"}},"광주은행":{"count":51,"tags":{"name:en":"Gwangju Bank"}},"Газпромбанк":{"count":100},"M&T Bank":{"count":92},"Caja de Burgos":{"count":51},"Santander Totta":{"count":69},"УкрСиббанк":{"count":192},"Ощадбанк":{"count":364},"Уралсиб":{"count":85},"りそな銀行":{"count":225,"tags":{"name:en":"Mizuho Bank"}},"Ecobank":{"count":66},"Cajero Automatico Bancared":{"count":145},"Промсвязьбанк":{"count":93},"三井住友銀行":{"count":129},"Banco Provincia":{"count":67},"BB&T":{"count":147},"Возрождение":{"count":59},"Capital One":{"count":59},"横浜銀行":{"count":51},"Bank Mandiri":{"count":62},"Banco de la Nación":{"count":92},"Banco G&T Continental":{"count":62},"Peoples Bank":{"count":60},"工商银行":{"count":51},"Совкомбанк":{"count":55},"Provincial":{"count":56},"Banco de Desarrollo Banrural":{"count":73},"Banco Bradesco":{"count":65},"Bicentenario":{"count":182},"ლიბერთი ბანკი":{"count":54,"tags":{"name:en":"Liberty Bank"}},"Banesco":{"count":108},"Mercantil":{"count":75},"Bank BRI":{"count":53},"Del Tesoro":{"count":91},"하나은행":{"count":77},"CityCommerce Bank":{"count":71},"De Venezuela":{"count":117}},"car_rental":{"Europcar":{"count":291},"Budget":{"count":92},"Sixt":{"count":161},"Avis":{"count":282},"Hertz":{"count":293},"Enterprise":{"count":199},"stadtmobil CarSharing-Station":{"count":148}},"pharmacy":{"Rowlands Pharmacy":{"count":71},"Boots":{"count":840},"Marien-Apotheke":{"count":314},"Mercury Drug":{"count":426},"Löwen-Apotheke":{"count":356},"Superdrug":{"count":117},"Sonnen-Apotheke":{"count":311},"Rathaus-Apotheke":{"count":132},"Engel-Apotheke":{"count":123},"Hirsch-Apotheke":{"count":83},"Stern-Apotheke":{"count":67},"Lloyds Pharmacy":{"count":295},"Rosen-Apotheke":{"count":208},"Stadt-Apotheke":{"count":302},"Markt-Apotheke":{"count":164},"Аптека":{"count":1989},"Pharmasave":{"count":64},"Brunnen-Apotheke":{"count":53},"Shoppers Drug Mart":{"count":430},"Apotheke am Markt":{"count":60},"Alte Apotheke":{"count":88},"Neue Apotheke":{"count":109},"Gintarinė vaistinė":{"count":101},"Rats-Apotheke":{"count":84},"Adler Apotheke":{"count":313},"Pharmacie Centrale":{"count":64},"Walgreens":{"count":1619},"Rite Aid":{"count":745},"Apotheke":{"count":165},"Linden-Apotheke":{"count":211},"Bahnhof-Apotheke":{"count":66},"Burg-Apotheke":{"count":55},"Jean Coutu":{"count":62},"Pharmaprix":{"count":60},"Farmacias Ahumada":{"count":104},"Farmacia Comunale":{"count":113},"Farmacias Cruz Verde":{"count":86},"Cruz Verde":{"count":99},"Hubertus Apotheke":{"count":52},"CVS":{"count":1560},"Farmacias SalcoBrand":{"count":133},"Фармация":{"count":120},"Bären-Apotheke":{"count":74},"Clicks":{"count":113},"セイジョー":{"count":53},"マツモトキヨシ":{"count":115},"Dr. Max":{"count":51},"Вита":{"count":106},"Радуга":{"count":70},"サンドラッグ":{"count":61},"Apteka":{"count":366},"Первая помощь":{"count":74},"Ригла":{"count":113},"Имплозия":{"count":63},"Kinney Drugs":{"count":68},"Классика":{"count":67},"Ljekarna":{"count":53},"SalcoBrand":{"count":88},"Аптека 36,6":{"count":224},"Фармакор":{"count":75},"スギ薬局":{"count":84},"Аптечный пункт":{"count":148},"Невис":{"count":60},"トモズ (Tomod's)":{"count":83},"Eurovaistinė":{"count":65},"Farmacity":{"count":68},"аптека":{"count":96},"The Generics Pharmacy":{"count":95},"Farmatodo":{"count":123},"Duane Reade":{"count":61},"H-E-B":{"count":262},"Фармленд":{"count":82},"ドラッグてらしま (Drug Terashima)":{"count":96},"Арніка":{"count":125},"ავერსი (Aversi)":{"count":62},"Farmahorro":{"count":58}},"cafe":{"Starbucks":{"count":4238,"tags":{"cuisine":"coffee_shop"}},"Cafeteria":{"count":115},"Costa":{"count":618},"Caffè Nero":{"count":169},"Кафе":{"count":226},"Café Central":{"count":61},"Second Cup":{"count":193},"Dunkin Donuts":{"count":428,"tags":{"cuisine":"donut"}},"Espresso House":{"count":53},"Segafredo":{"count":69},"Coffee Time":{"count":94},"Cafe Coffee Day":{"count":120},"Eiscafe Venezia":{"count":180},"スターバックス":{"count":251,"tags":{"name:en":"Starbucks"}},"Шоколадница":{"count":145},"Pret A Manger":{"count":119},"Столовая":{"count":391},"Jamba Juice":{"count":53},"ドトール":{"count":164,"tags":{"name:en":"DOUTOR"}},"Tchibo":{"count":100},"Кофе Хауз":{"count":104},"Caribou Coffee":{"count":100},"Уют":{"count":51},"Шашлычная":{"count":58},"คาเฟ่ อเมซอน":{"count":62},"Traveler's Coffee":{"count":60},"カフェ・ド・クリエ":{"count":67,"tags":{"name:en":"Cafe de CRIE"}},"Cafe Amazon":{"count":65}}};
18593 var shop = {"supermarket":{"Budgens":{"count":88},"Morrisons":{"count":411},"Interspar":{"count":142},"Merkur":{"count":107},"Sainsbury's":{"count":547},"Lidl":{"count":7130},"Edeka":{"count":2293},"Coles":{"count":400},"Iceland":{"count":315},"Coop":{"count":2100},"Tesco":{"count":1297},"Woolworths":{"count":541},"Zielpunkt":{"count":239},"Nahkauf":{"count":170},"Billa":{"count":1432},"Kaufland":{"count":1004},"Plus":{"count":120},"ALDI":{"count":5172},"Checkers":{"count":128},"Tesco Metro":{"count":137},"NP":{"count":153},"Penny":{"count":1759},"Norma":{"count":1068},"Asda":{"count":225},"Netto":{"count":4379},"Rewe":{"count":2645},"Aldi Süd":{"count":594},"Real":{"count":246},"Tesco Express":{"count":406},"King Soopers":{"count":72},"Kiwi":{"count":167},"Pick n Pay":{"count":241},"ICA":{"count":192},"Tengelmann":{"count":188},"Carrefour":{"count":1640},"Waitrose":{"count":258},"Spar":{"count":2386},"Hofer":{"count":442},"M-Preis":{"count":76},"tegut":{"count":210},"Sainsbury's Local":{"count":118},"E-Center":{"count":66},"Aldi Nord":{"count":210},"nahkauf":{"count":84},"Meijer":{"count":76},"Safeway":{"count":410},"Costco":{"count":152},"Albert":{"count":185},"Jumbo":{"count":194},"Shoprite":{"count":244},"MPreis":{"count":54},"Penny Market":{"count":429},"Tesco Extra":{"count":123},"Albert Heijn":{"count":476},"IGA":{"count":363},"Super U":{"count":488},"Metro":{"count":260},"Neukauf":{"count":77},"Migros":{"count":459},"Marktkauf":{"count":121},"Delikatesy Centrum":{"count":59},"C1000":{"count":307},"Hoogvliet":{"count":53},"Food Basics":{"count":75},"Casino":{"count":264},"Penny Markt":{"count":466},"Giant":{"count":191},"COOP Jednota":{"count":73},"Rema 1000":{"count":368},"Kaufpark":{"count":96},"ALDI SÜD":{"count":113},"Simply Market":{"count":330},"Konzum":{"count":230},"Carrefour Express":{"count":353},"Eurospar":{"count":270},"Mercator":{"count":125},"Famila":{"count":130},"Hemköp":{"count":82},"real,-":{"count":81},"Markant":{"count":88},"Volg":{"count":135},"Leader Price":{"count":267},"Treff 3000":{"count":94},"SuperBrugsen":{"count":67},"Kaiser's":{"count":256},"K+K":{"count":106},"Unimarkt":{"count":86},"Carrefour City":{"count":126},"Sobeys":{"count":122},"S-Market":{"count":109},"Combi":{"count":55},"Denner":{"count":276},"Konsum":{"count":133},"Franprix":{"count":312},"Monoprix":{"count":198},"Diska":{"count":69},"PENNY":{"count":79},"Dia":{"count":835},"Giant Eagle":{"count":85},"NORMA":{"count":115},"AD Delhaize":{"count":63},"Auchan":{"count":152},"Mercadona":{"count":769},"Consum":{"count":130},"Carrefour Market":{"count":80},"Whole Foods":{"count":210,"tags":{"shop":"supermarket"}},"Pam":{"count":56},"sky":{"count":105},"Despar":{"count":146},"Eroski":{"count":208},"Costcutter":{"count":63},"Maxi":{"count":108},"Colruyt":{"count":180},"The Co-operative":{"count":64},"Intermarché":{"count":1210},"Delhaize":{"count":207},"CBA":{"count":176},"Shopi":{"count":53},"Walmart":{"count":644},"Kroger":{"count":317},"Albertsons":{"count":242},"Trader Joe's":{"count":235},"Feneberg":{"count":58},"denn's Biomarkt":{"count":52},"dm":{"count":114},"Kvickly":{"count":55},"Makro":{"count":140},"Dico":{"count":53},"Nah & Frisch":{"count":73},"Champion":{"count":59},"ICA Supermarket":{"count":51},"Fakta":{"count":235},"Магнит":{"count":1760},"Caprabo":{"count":103},"Famiglia Cooperativa":{"count":64},"Народная 7Я семьЯ":{"count":154},"Esselunga":{"count":85},"Maxima":{"count":102},"Petit Casino":{"count":111},"Wasgau":{"count":60},"Pingo Doce":{"count":253},"Match":{"count":140},"Profi":{"count":60},"Lider":{"count":65},"Unimarc":{"count":177},"The Co-operative Food":{"count":190},"Santa Isabel":{"count":128},"Седьмой континент":{"count":79},"HIT":{"count":59},"Rimi":{"count":106},"Conad":{"count":304},"Фуршет":{"count":76},"Willys":{"count":56},"Farmfoods":{"count":64},"U Express":{"count":51},"Фора":{"count":52},"Dunnes Stores":{"count":73},"Сільпо":{"count":125},"マルエツ":{"count":59},"Piggly Wiggly":{"count":57},"Crai":{"count":54},"El Árbol":{"count":73},"Centre Commercial E. Leclerc":{"count":549},"Foodland":{"count":100},"Super Brugsen":{"count":67},"Дикси":{"count":683},"Пятёрочка":{"count":1344},"Publix":{"count":339},"Føtex":{"count":66},"coop":{"count":73},"Fressnapf":{"count":69},"Coop Konsum":{"count":79},"Carrefour Contact":{"count":83},"No Frills":{"count":105},"Plodine":{"count":52},"ADEG":{"count":68},"Minipreço":{"count":111},"Biedronka":{"count":1335},"Eurospin":{"count":155},"Семья":{"count":62},"Gadis":{"count":53},"Евроопт":{"count":68},"Centra":{"count":51},"Квартал":{"count":82},"New World":{"count":69},"Countdown":{"count":95},"Reliance Fresh":{"count":61},"Stokrotka":{"count":98},"Coop Jednota":{"count":74},"Fred Meyer":{"count":64},"Irma":{"count":58},"Continente":{"count":75},"Price Chopper":{"count":99},"Game":{"count":52},"Soriana":{"count":93},"Alimerka":{"count":64},"Piotr i Paweł":{"count":53},"Перекресток":{"count":312},"Maxima X":{"count":117},"Карусель":{"count":55},"ALDI Nord":{"count":51},"Condis":{"count":67},"Sam's Club":{"count":138},"Копейка":{"count":87},"Géant Casino":{"count":54},"ASDA":{"count":180},"Intermarche":{"count":115},"Stop & Shop":{"count":66},"Food Lion":{"count":216},"Harris Teeter":{"count":92},"Foodworks":{"count":62},"Polo Market":{"count":86},"Лента":{"count":51},"西友 (SEIYU)":{"count":58},"H-E-B":{"count":293},"Атак":{"count":53},"Полушка":{"count":139},"Extra":{"count":82},"Lewiatan":{"count":94},"Sigma":{"count":51},"АТБ":{"count":322},"Społem":{"count":55},"Bodega Aurrera":{"count":82},"Tesco Lotus":{"count":77},"Мария-Ра":{"count":108},"Магнолия":{"count":72},"Магазин":{"count":120},"Монетка":{"count":174},"Hy-Vee":{"count":75},"Walmart Supercenter":{"count":133},"Hannaford":{"count":57},"Wegmans":{"count":83},"業務スーパー":{"count":61},"Norfa XL":{"count":55},"ヨークマート (YorkMart)":{"count":64},"Leclerc Drive":{"count":76}},"electronics":{"Media Markt":{"count":285},"Maplin":{"count":65},"Best Buy":{"count":345},"Future Shop":{"count":73},"Saturn":{"count":134},"Currys":{"count":80},"Radio Shack":{"count":269},"Euronics":{"count":115},"Expert":{"count":123},"Эльдорадо":{"count":184},"Darty":{"count":74},"М.Видео":{"count":89},"ヤマダ電機":{"count":51}},"convenience":{"Shell":{"count":255},"Spar":{"count":1119},"McColl's":{"count":100},"Tesco Express":{"count":426},"Sainsbury's Local":{"count":104},"Aral":{"count":56},"One Stop":{"count":146},"The Co-operative Food":{"count":115},"Londis":{"count":352},"7-Eleven":{"count":4440},"CBA":{"count":135},"Coop":{"count":678},"Sale":{"count":80},"Statoil":{"count":69},"Sheetz":{"count":54},"Konzum":{"count":173},"Siwa":{"count":216},"Mercator":{"count":57},"Esso":{"count":67},"COOP Jednota":{"count":181},"Mac's":{"count":152},"Alepa":{"count":62},"Hasty Market":{"count":54},"K-Market":{"count":54},"Costcutter":{"count":292},"Valintatalo":{"count":62},"Casino":{"count":90},"Franprix":{"count":61},"Circle K":{"count":289},"セブンイレブン":{"count":3011,"tags":{"name:en":"7-Eleven"}},"ローソン":{"count":1596,"tags":{"name:en":"LAWSON"}},"BP":{"count":163},"Tesco":{"count":55},"Petit Casino":{"count":233},"Volg":{"count":116},"Mace":{"count":115},"Mini Market":{"count":272},"Nisa Local":{"count":77},"Dorfladen":{"count":75},"Продукты":{"count":4285},"Mini Stop":{"count":228},"LAWSON":{"count":419},"デイリーヤマザキ":{"count":141},"Biedronka":{"count":83},"Надежда":{"count":56},"Mobil":{"count":66},"Nisa":{"count":51},"Premier":{"count":129},"ABC":{"count":152},"ミニストップ":{"count":316,"tags":{"name:en":"MINISTOP"}},"サンクス":{"count":560,"tags":{"name:en":"sunkus"}},"スリーエフ":{"count":88},"8 à Huit":{"count":61},"Tchibo":{"count":56},"Żabka":{"count":546},"Almacen":{"count":229},"Vival":{"count":194},"FamilyMart":{"count":529},"ファミリーマート":{"count":1608,"tags":{"name:en":"FamilyMart"}},"Carrefour City":{"count":57},"Sunkus":{"count":62},"Casey's General Store":{"count":95},"セブンイレブン(Seven-Eleven)":{"count":65},"Jednota":{"count":58},"Магазин":{"count":915},"Гастроном":{"count":152},"Centra":{"count":111},"Магнит":{"count":701},"サークルK":{"count":538,"tags":{"name:en":"Circle K"}},"Wawa":{"count":135},"Proxi":{"count":123},"Универсам":{"count":78},"Перекресток":{"count":51},"Groszek":{"count":65},"Select":{"count":62},"Večerka":{"count":51},"Potraviny":{"count":249},"Смак":{"count":78},"Эконом":{"count":55},"Березка":{"count":77},"Społem":{"count":93},"Carrefour Express":{"count":84},"Cumberland Farms":{"count":63},"Chevron":{"count":59},"Coop Jednota":{"count":66},"Tesco Lotus Express":{"count":67},"Kiosk":{"count":55},"Sklep spożywczy":{"count":130},"24 часа":{"count":58},"Минимаркет":{"count":102},"Oxxo":{"count":669},"Пятёрочка":{"count":398},"abc":{"count":74},"7/11":{"count":51},"Stewart's":{"count":255},"Продукти":{"count":171},"ローソンストア100 (LAWSON STORE 100)":{"count":85},"Дикси":{"count":119},"Радуга":{"count":86},"ローソンストア100":{"count":76},"เซเว่นอีเลฟเว่น":{"count":185},"Delikatesy Centrum":{"count":53},"Citgo":{"count":62},"Фортуна":{"count":51},"Kum & Go":{"count":59},"Мария-Ра":{"count":76},"Picard":{"count":57},"Four Square":{"count":52},"Визит":{"count":57},"Авоська":{"count":55},"Dollar General":{"count":127},"Studenac":{"count":76},"Central Convenience Store":{"count":55},"Монетка":{"count":62},"продукты":{"count":114},"Теремок":{"count":56},"Kwik Trip":{"count":69},"Кулинария":{"count":55},"全家":{"count":90},"Мечта":{"count":54},"Epicerie":{"count":102},"Кировский":{"count":67},"Food Mart":{"count":117},"Delikatesy":{"count":81},"ポプラ":{"count":54},"Lewiatan":{"count":135},"Продуктовый магазин":{"count":149},"Продуктовый":{"count":84},"セイコーマート (Seicomart)":{"count":72},"Виктория":{"count":70},"Весна":{"count":57},"Mini Market Non-Stop":{"count":60},"QuikTrip":{"count":75},"Копеечка":{"count":51},"Royal Farms":{"count":51},"Alfamart":{"count":103},"Indomaret":{"count":141},"магазин":{"count":171},"全家便利商店":{"count":156},"Boutique":{"count":59},"მარკეტი (Market)":{"count":144},"Stores":{"count":61}},"chemist":{"dm":{"count":939},"Müller":{"count":212},"Schlecker":{"count":187},"Etos":{"count":467},"Bipa":{"count":289},"Rossmann":{"count":1669},"DM Drogeriemarkt":{"count":55},"Ihr Platz":{"count":73},"Douglas":{"count":62},"Kruidvat":{"count":123}},"car_repair":{"Peugeot":{"count":83},"Kwik Fit":{"count":128},"ATU":{"count":261},"Midas":{"count":202},"Feu Vert":{"count":113},"Norauto":{"count":152},"Speedy":{"count":115},"Автозапчасти":{"count":212},"Renault":{"count":171},"Pit Stop":{"count":58},"Jiffy Lube":{"count":198},"Шиномонтаж":{"count":1157},"СТО":{"count":395},"O'Reilly Auto Parts":{"count":81},"Carglass":{"count":112},"шиномонтаж":{"count":62},"Citroen":{"count":51},"Euromaster":{"count":87},"Firestone":{"count":88},"Автосервис":{"count":361},"Advance Auto Parts":{"count":52},"Roady":{"count":56}},"furniture":{"IKEA":{"count":169},"Jysk":{"count":109},"Roller":{"count":78},"Dänisches Bettenlager":{"count":309},"Conforama":{"count":99},"Matratzen Concord":{"count":52},"Мебель":{"count":210},"But":{"count":63}},"doityourself":{"Hornbach":{"count":123},"B&Q":{"count":225},"Hubo":{"count":77},"Mr Bricolage":{"count":88},"Gamma":{"count":111},"OBI":{"count":422},"Lowes":{"count":1152},"Wickes":{"count":123},"Hagebau":{"count":59},"Max Bahr":{"count":79},"Castorama":{"count":153},"Rona":{"count":61},"Home Depot":{"count":865},"Toom Baumarkt":{"count":71},"Homebase":{"count":225},"Baumax":{"count":95},"Lagerhaus":{"count":79},"Bauhaus":{"count":186},"Canadian Tire":{"count":97},"Leroy Merlin":{"count":209},"Hellweg":{"count":58},"Brico":{"count":98},"Bricomarché":{"count":235},"Toom":{"count":67},"Hagebaumarkt":{"count":107},"Praktiker":{"count":122},"Menards":{"count":70},"Weldom":{"count":73},"Bunnings Warehouse":{"count":91},"Ace Hardware":{"count":147},"Home Hardware":{"count":72},"Хозтовары":{"count":86},"Стройматериалы":{"count":197},"Bricorama":{"count":60},"Point P":{"count":59}},"stationery":{"Staples":{"count":299},"McPaper":{"count":83},"Office Depot":{"count":98},"Канцтовары":{"count":63}},"car":{"Skoda":{"count":97},"BMW":{"count":149},"Citroen":{"count":277},"Renault":{"count":382},"Mercedes-Benz":{"count":235},"Volvo":{"count":96},"Ford":{"count":239},"Volkswagen":{"count":217},"Mazda":{"count":105},"Mitsubishi":{"count":73},"Fiat":{"count":93},"Автозапчасти":{"count":277},"Opel":{"count":165},"Audi":{"count":121},"Toyota":{"count":271},"Nissan":{"count":189},"Suzuki":{"count":75},"Honda":{"count":157},"Peugeot":{"count":308},"Шиномонтаж":{"count":259},"Hyundai":{"count":166},"Subaru":{"count":58},"Chevrolet":{"count":86},"Автомагазин":{"count":72}},"clothes":{"Matalan":{"count":90},"KiK":{"count":1219},"H&M":{"count":658},"Urban Outfitters":{"count":63},"Vögele":{"count":132},"Zeeman":{"count":121},"Takko":{"count":515},"Adler":{"count":55},"C&A":{"count":506},"Zara":{"count":217},"Vero Moda":{"count":95},"NKD":{"count":486},"Ernsting's family":{"count":312},"Winners":{"count":65},"River Island":{"count":59},"Next":{"count":176},"Gap":{"count":81},"Adidas":{"count":92},"Woolworths":{"count":117},"Mr Price":{"count":88},"Jet":{"count":61},"Pep":{"count":134},"Edgars":{"count":110},"Ackermans":{"count":91},"Truworths":{"count":65},"Ross":{"count":93},"Burton":{"count":51},"Dorothy Perkins":{"count":53},"Deichmann":{"count":61},"Lindex":{"count":73},"s.Oliver":{"count":56},"Cecil":{"count":51},"Dress Barn":{"count":52},"Old Navy":{"count":174},"Jack & Jones":{"count":52},"Pimkie":{"count":73},"Esprit":{"count":231},"Primark":{"count":92},"Bonita":{"count":155},"Mexx":{"count":67},"Gerry Weber":{"count":71},"Tally Weijl":{"count":70},"Mango":{"count":133},"TK Maxx":{"count":84},"Benetton":{"count":101},"Ulla Popken":{"count":61},"AWG":{"count":66},"Tommy Hilfiger":{"count":75},"New Yorker":{"count":180},"Orsay":{"count":73},"Jeans Fritz":{"count":51},"Charles Vögele":{"count":69},"New Look":{"count":126},"Lacoste":{"count":78},"Etam":{"count":53},"Kiabi":{"count":148},"Jack Wolfskin":{"count":60},"American Apparel":{"count":57},"Men's Wearhouse":{"count":54},"Intimissimi":{"count":52},"United Colors of Benetton":{"count":96},"Jules":{"count":63},"Second Hand":{"count":53},"AOKI":{"count":57},"Calzedonia":{"count":68},"洋服の青山":{"count":100},"Levi's":{"count":63},"Celio":{"count":74},"TJ Maxx":{"count":57},"Promod":{"count":82},"Street One":{"count":72},"ユニクロ":{"count":59},"Banana Republic":{"count":57},"Одежда":{"count":75},"Marshalls":{"count":56},"La Halle":{"count":62},"Peacocks":{"count":89},"しまむら":{"count":60}},"books":{"Bruna":{"count":58},"Waterstones":{"count":90},"Libro":{"count":57},"Barnes & Noble":{"count":267},"Weltbild":{"count":74},"Thalia":{"count":121},"Книги":{"count":112}},"department_store":{"Debenhams":{"count":67},"Canadian Tire":{"count":75},"Karstadt":{"count":64},"Walmart":{"count":517},"Kmart":{"count":143},"Target":{"count":574},"Galeria Kaufhof":{"count":61},"Marks & Spencer":{"count":66},"Big W":{"count":57},"Woolworth":{"count":78},"Универмаг":{"count":72},"Sears":{"count":235},"Walmart Supercenter":{"count":101},"Kohl's":{"count":153},"Macy's":{"count":147},"Sam's Club":{"count":54},"JCPenney":{"count":66}},"alcohol":{"Alko":{"count":145},"The Beer Store":{"count":150},"Systembolaget":{"count":210},"LCBO":{"count":239},"Ароматный мир":{"count":62},"Bargain Booze":{"count":62},"Nicolas":{"count":119},"BWS":{"count":70},"Botilleria":{"count":77},"SAQ":{"count":72},"Gall & Gall":{"count":512},"Живое пиво":{"count":70}},"bakery":{"Kamps":{"count":252},"Banette":{"count":52},"Bäckerei Schmidt":{"count":57},"Anker":{"count":73},"Hofpfisterei":{"count":111},"Greggs":{"count":276},"Oebel":{"count":57},"Boulangerie":{"count":266},"Stadtbäckerei":{"count":57},"Steinecke":{"count":145},"Ihle":{"count":76},"Goldilocks":{"count":59},"Dat Backhus":{"count":67},"K&U":{"count":61},"Der Beck":{"count":96},"Thürmann":{"count":54},"Backwerk":{"count":95},"Schäfer's":{"count":51},"Panaderia":{"count":168},"Goeken backen":{"count":51},"Stadtbäckerei Junge":{"count":51},"Boulangerie Patisserie":{"count":119},"Paul":{"count":81},"Хлеб":{"count":89},"Пекарня":{"count":52},"Кулиничи":{"count":51}},"sports":{"Sports Direct":{"count":57},"Decathlon":{"count":309},"Intersport":{"count":283},"Sports Authority":{"count":75},"Спортмастер":{"count":87},"Sport 2000":{"count":90},"Dick's Sporting Goods":{"count":77}},"variety_store":{"Tedi":{"count":157},"Dollarama":{"count":103},"Family Dollar":{"count":61},"Dollar Tree":{"count":110},"Dollar General":{"count":80}},"pet":{"Fressnapf":{"count":318},"PetSmart":{"count":177},"Das Futterhaus":{"count":69},"Pets at Home":{"count":62},"Petco":{"count":101},"Зоомагазин":{"count":100}},"shoes":{"Deichmann":{"count":622},"Reno":{"count":183},"Ecco":{"count":55},"Clarks":{"count":109},"La Halle aux Chaussures":{"count":69},"Brantano":{"count":71},"Geox":{"count":51},"Salamander":{"count":51},"Обувь":{"count":100},"Payless Shoe Source":{"count":67},"Famous Footwear":{"count":59},"Quick Schuh":{"count":72},"Shoe Zone":{"count":55},"Foot Locker":{"count":82},"Bata":{"count":101},"ЦентрОбувь":{"count":51}},"toys":{"La Grande Récré":{"count":56},"Toys R Us":{"count":151,"tags":{"shop":"toys"}},"Intertoys":{"count":57},"Детский мир":{"count":86},"Игрушки":{"count":58}},"travel_agency":{"Flight Centre":{"count":92},"Thomas Cook":{"count":119}},"jewelry":{"Bijou Brigitte":{"count":57},"Christ":{"count":57},"Swarovski":{"count":74}},"optician":{"Fielmann":{"count":232},"Apollo Optik":{"count":150},"Vision Express":{"count":58},"Оптика":{"count":182},"Optic 2000":{"count":98},"Alain Afflelou":{"count":73},"Specsavers":{"count":124},"Krys":{"count":77},"Atol":{"count":55}},"video":{"Blockbuster":{"count":184},"World of Video":{"count":64}},"mobile_phone":{"Билайн":{"count":128},"ソフトバンクショップ (SoftBank shop)":{"count":255},"Vodafone":{"count":355},"O2":{"count":208},"Carphone Warehouse":{"count":127},"Orange":{"count":246},"Verizon Wireless":{"count":125},"Sprint":{"count":109},"T-Mobile":{"count":175},"МТС":{"count":352},"Евросеть":{"count":506},"Bell":{"count":190},"The Phone House":{"count":83},"SFR":{"count":71},"Связной":{"count":439},"Мегафон":{"count":251},"AT&T":{"count":124},"ドコモショップ (docomo shop)":{"count":114},"au":{"count":65},"Movistar":{"count":77},"Bitė":{"count":72}},"hifi":{},"computer":{"PC World":{"count":55},"DNS":{"count":128}},"hairdresser":{"Klier":{"count":119},"Supercuts":{"count":106},"Hairkiller":{"count":51},"Great Clips":{"count":182},"Парикмахерская":{"count":510},"Стиль":{"count":51},"Franck Provost":{"count":70},"Салон красоты":{"count":70}},"hardware":{"1000 мелочей":{"count":61},"Хозтовары":{"count":151},"Стройматериалы":{"count":54}},"motorcycle":{"Yamaha":{"count":67},"Honda":{"count":69}}};
18594 var dataSuggestions = {
18595         amenity: amenity,
18596         shop: shop
18597 };
18598
18599 var dataAddressFormats = [{"format":[["housenumber","street"],["city","postcode"]]},{"countryCodes":["gb"],"format":[["housename"],["housenumber","street"],["city","postcode"]]},{"countryCodes":["ie"],"format":[["housename"],["housenumber","street"],["city"],["postcode"]]},{"countryCodes":["ad","at","ba","be","ch","cz","de","dk","es","fi","gr","hr","is","it","li","nl","no","pl","pt","se","si","sk","sm","va"],"format":[["street","housenumber"],["postcode","city"]]},{"countryCodes":["fr","lu","mo"],"format":[["housenumber","street"],["postcode","city"]]},{"countryCodes":["br"],"format":[["street"],["housenumber","suburb"],["city","postcode"]]},{"countryCodes":["vn"],"format":[["housenumber","street"],["subdistrict"],["district"],["city"],["province","postcode"]]},{"countryCodes":["us"],"format":[["housenumber","street"],["city","state","postcode"]]},{"countryCodes":["ca"],"format":[["housenumber","street"],["city","province","postcode"]]},{"countryCodes":["tw"],"format":[["postcode","city","district"],["place","street"],["housenumber","floor"]]},{"countryCodes":["jp"],"format":[["postcode","province","county"],["city","suburb"],["quarter","neighbourhood"],["block_number","housenumber"]],"dropdowns":["postcode","province","county","city","suburb","quarter","neighbourhood","block_number"],"widths":{"postcode":0.3,"province":0.35,"county":0.35,"city":0.65,"suburb":0.35,"quarter":0.5,"neighbourhood":0.5,"block_number":0.5,"housenumber":0.5}},{"countryCodes":["tr"],"format":[["neighbourhood"],["street","housenumber"],["postcode","district","city"]]},{"countryCodes":["ua"],"format":[["housenumber","postcode"],["street"]]},{"countryCodes":["cn"],"format":[["postcode","province"],["city"],["district"],["street","housenumber"]]}];
18600
18601 var dataDeprecated = [{"old":{"amenity":"firepit"},"replace":{"leisure":"firepit"}},{"old":{"barrier":"wire_fence"},"replace":{"barrier":"fence","fence_type":"chain"}},{"old":{"barrier":"wood_fence"},"replace":{"barrier":"fence","fence_type":"wood"}},{"old":{"highway":"ford"},"replace":{"ford":"yes"}},{"old":{"highway":"stile"},"replace":{"barrier":"stile"}},{"old":{"highway":"incline"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"incline_steep"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"unsurfaced"},"replace":{"highway":"road","incline":"unpaved"}},{"old":{"landuse":"wood"},"replace":{"landuse":"forest","natural":"wood"}},{"old":{"natural":"marsh"},"replace":{"natural":"wetland","wetland":"marsh"}},{"old":{"power_source":"*"},"replace":{"generator:source":"$1"}},{"old":{"power_rating":"*"},"replace":{"generator:output":"$1"}},{"old":{"shop":"organic"},"replace":{"shop":"supermarket","organic":"only"}}];
18602
18603 var dataDiscarded = ["created_by","odbl","odbl:note","tiger:upload_uuid","tiger:tlid","tiger:source","tiger:separated","geobase:datasetName","geobase:uuid","sub_sea:type","KSJ2:ADS","KSJ2:ARE","KSJ2:AdminArea","KSJ2:COP_label","KSJ2:DFD","KSJ2:INT","KSJ2:INT_label","KSJ2:LOC","KSJ2:LPN","KSJ2:OPC","KSJ2:PubFacAdmin","KSJ2:RAC","KSJ2:RAC_label","KSJ2:RIC","KSJ2:RIN","KSJ2:WSC","KSJ2:coordinate","KSJ2:curve_id","KSJ2:curve_type","KSJ2:filename","KSJ2:lake_id","KSJ2:lat","KSJ2:long","KSJ2:river_id","yh:LINE_NAME","yh:LINE_NUM","yh:STRUCTURE","yh:TOTYUMONO","yh:TYPE","yh:WIDTH","yh:WIDTH_RANK","SK53_bulk:load"];
18604
18605 var dataLocales = {"af":{"rtl":false},"ar":{"rtl":true},"ar-AA":{"rtl":true},"ast":{"rtl":false},"bg":{"rtl":false},"bg-BG":{"rtl":false},"bn":{"rtl":false},"bs":{"rtl":false},"ca":{"rtl":false},"cs":{"rtl":false},"da":{"rtl":false},"de":{"rtl":false},"dv":{"rtl":false},"el":{"rtl":false},"en-GB":{"rtl":false},"eo":{"rtl":false},"es":{"rtl":false},"et":{"rtl":false},"fa":{"rtl":true},"fi":{"rtl":false},"fr":{"rtl":false},"gan":{"rtl":false},"gl":{"rtl":false},"gu":{"rtl":false},"he":{"rtl":true},"hi":{"rtl":false},"hr":{"rtl":false},"hu":{"rtl":false},"hy":{"rtl":false},"ia":{"rtl":false},"id":{"rtl":false},"is":{"rtl":false},"it":{"rtl":false},"ja":{"rtl":false},"jv":{"rtl":false},"km":{"rtl":false},"kn":{"rtl":false},"ko":{"rtl":false},"ku":{"rtl":true},"lij":{"rtl":false},"lt":{"rtl":false},"lv":{"rtl":false},"mg":{"rtl":false},"mk":{"rtl":false},"ml":{"rtl":false},"mn":{"rtl":false},"ms":{"rtl":false},"ne":{"rtl":false},"nl":{"rtl":false},"nn":{"rtl":false},"no":{"rtl":false},"nv":{"rtl":false},"pl":{"rtl":false},"pt":{"rtl":false},"pt-BR":{"rtl":false},"rm":{"rtl":false},"ro":{"rtl":false},"ru":{"rtl":false},"sc":{"rtl":false},"si":{"rtl":false},"sk":{"rtl":false},"sl":{"rtl":false},"sq":{"rtl":false},"sr":{"rtl":false},"sv":{"rtl":false},"ta":{"rtl":false},"te":{"rtl":false},"th":{"rtl":false},"tl":{"rtl":false},"tr":{"rtl":false},"uk":{"rtl":false},"ur":{"rtl":true},"vi":{"rtl":false},"yue":{"rtl":false},"zh":{"rtl":false},"zh-CN":{"rtl":false},"zh-HK":{"rtl":false},"zh-TW":{"rtl":false}};
18606
18607 var dataPhoneFormats = {"us":"+1-202-555-1234","ca":"+1-226-555-1234","bs":"+1-242-555-1234","bb":"+1-246-555-1234","ai":"+1-264-555-1234","ag":"+1-268-555-1234","vg":"+1-284-555-1234","vi":"+1-340-555-1234","ky":"+1-345-555-1234","bm":"+1-441-555-1234","gd":"+1-473-555-1234","tc":"+1-649-555-1234","ms":"+1-664-555-1234","mp":"+1-670-555-1234","gu":"+1-671-555-1234","as":"+1-684-555-1234","sx":"+1-721-555-1234","lc":"+1-758-555-1234","dm":"+1-767-555-1234","vc":"+1-784-555-1234","pr":"+1-787-555-1234","do":"+1-809-555-1234","tt":"+1-868-555-1234","kn":"+1-869-555-1234","jm":"+1-876-555-1234","za":"+27 11 907 1111","nl":"+31 42 123 4567","fr":"+33 1 23 45 67 89","es":"+34 989 12 34 56","pt":"+351 211 123456","ie":"+353 20 912 3456","fi":"+358 40 123 4567","hu":"+36 1 123 45 67","hr":"+385 01 123 4567","si":"+386 31 123 4567","it":"+39 01 123 456","va":"+39 01 123 456","gb":"+44 1632 961234","gg":"+44 1632 961234","im":"+44 1632 961234","je":"+44 1632 961234","se":"+46 31 123 4567","no":"+47 22 12 34 56","sj":"+47 22 12 34 56","pl":"+48 42 123 4567","de":"+49 89 1234567","br":"+55 11 0982 1098","ru":"+7 495 1234567","kz":"+7 495 1234567","vn":"+84 1 234 5678","hk":"+852 1234 5678","cn":"+86 10 12345678","tw":"+886 1 2345 6789","tr":"+90 312 123 4567","ua":"+380 44 123 4567"};
18608
18609 var dataShortcuts = [{"tab":"browsing","text":"shortcuts.browsing.title","columns":[{"rows":[{"section":"navigation","text":"shortcuts.browsing.navigation.title"},{"shortcuts":["↓","↑","←","→"],"text":"shortcuts.browsing.navigation.pan","separator":","},{"modifiers":["⌘"],"shortcuts":["↓","↑","←","→"],"text":"shortcuts.browsing.navigation.pan_more","separator":","},{"shortcuts":["+","-"],"text":"shortcuts.browsing.navigation.zoom","separator":","},{"modifiers":["⌘"],"shortcuts":["+","-"],"text":"shortcuts.browsing.navigation.zoom_more","separator":","},{"section":"help","text":"shortcuts.browsing.help.title"},{"shortcuts":["help.key"],"text":"shortcuts.browsing.help.help"},{"shortcuts":["shortcuts.toggle.key"],"text":"shortcuts.browsing.help.keyboard"},{"section":"display_options","text":"shortcuts.browsing.display_options.title"},{"shortcuts":["background.key"],"text":"shortcuts.browsing.display_options.background"},{"modifiers":["⌘"],"shortcuts":["background.key"],"text":"shortcuts.browsing.display_options.background_switch"},{"shortcuts":["map_data.key"],"text":"shortcuts.browsing.display_options.map_data"},{"modifiers":["⌃","⌘"],"shortcuts":["F","F11"],"text":"shortcuts.browsing.display_options.fullscreen"},{"shortcuts":["area_fill.wireframe.key"],"text":"shortcuts.browsing.display_options.wireframe"},{"shortcuts":["background.minimap.key"],"text":"shortcuts.browsing.display_options.minimap"}]},{"rows":[{"section":"selecting","text":"shortcuts.browsing.selecting.title"},{"shortcuts":["Left-click"],"text":"shortcuts.browsing.selecting.select_one"},{"modifiers":["⇧"],"shortcuts":["Left-click"],"text":"shortcuts.browsing.selecting.select_multi"},{"modifiers":["⇧"],"shortcuts":["Left-click"],"gesture":"shortcuts.gesture.drag","text":"shortcuts.browsing.selecting.lasso"},{"shortcuts":[],"text":""},{"section":"with_selected","text":"shortcuts.browsing.with_selected.title"},{"shortcuts":["Right-click","shortcuts.key.space"],"text":"shortcuts.browsing.with_selected.edit_menu"},{"shortcuts":[],"text":""},{"section":"vertex_selected","text":"shortcuts.browsing.vertex_selected.title"},{"shortcuts":["[","↖"],"text":"shortcuts.browsing.vertex_selected.previous"},{"shortcuts":["]","↘"],"text":"shortcuts.browsing.vertex_selected.next"},{"shortcuts":["{","⇞"],"text":"shortcuts.browsing.vertex_selected.first"},{"shortcuts":["}","⇟"],"text":"shortcuts.browsing.vertex_selected.last"},{"shortcuts":["\\","shortcuts.key.pause"],"text":"shortcuts.browsing.vertex_selected.change_parent"}]}]},{"tab":"editing","text":"shortcuts.editing.title","columns":[{"rows":[{"section":"drawing","text":"shortcuts.editing.drawing.title"},{"shortcuts":["1"],"text":"shortcuts.editing.drawing.add_point"},{"shortcuts":["2"],"text":"shortcuts.editing.drawing.add_line"},{"shortcuts":["3"],"text":"shortcuts.editing.drawing.add_area"},{"shortcuts":["Left-click","shortcuts.key.space"],"text":"shortcuts.editing.drawing.place_point"},{"shortcuts":["⌥"],"text":"shortcuts.editing.drawing.disable_snap"},{"shortcuts":["↵","⎋"],"text":"shortcuts.editing.drawing.stop_line"},{"section":"commands","text":"shortcuts.editing.commands.title"},{"modifiers":["⌘"],"shortcuts":["C"],"text":"shortcuts.editing.commands.copy"},{"modifiers":["⌘"],"shortcuts":["V"],"text":"shortcuts.editing.commands.paste"},{"modifiers":["⌘"],"shortcuts":["Z"],"text":"shortcuts.editing.commands.undo"},{"modifiers":["⌘","⇧"],"shortcuts":["Z"],"text":"shortcuts.editing.commands.redo"},{"modifiers":["⌘"],"shortcuts":["S"],"text":"shortcuts.editing.commands.save"}]},{"rows":[{"section":"operations","text":"shortcuts.editing.operations.title"},{"shortcuts":["operations.continue.key"],"text":"shortcuts.editing.operations.continue_line"},{"shortcuts":["operations.merge.key"],"text":"shortcuts.editing.operations.merge"},{"shortcuts":["operations.disconnect.key"],"text":"shortcuts.editing.operations.disconnect"},{"shortcuts":["operations.split.key"],"text":"shortcuts.editing.operations.split"},{"shortcuts":["operations.reverse.key"],"text":"shortcuts.editing.operations.reverse"},{"shortcuts":["operations.move.key"],"text":"shortcuts.editing.operations.move"},{"shortcuts":["operations.rotate.key"],"text":"shortcuts.editing.operations.rotate"},{"shortcuts":["operations.orthogonalize.key"],"text":"shortcuts.editing.operations.orthogonalize"},{"shortcuts":["operations.circularize.key"],"text":"shortcuts.editing.operations.circularize"},{"shortcuts":["operations.reflect.key.long"],"text":"shortcuts.editing.operations.reflect_long"},{"shortcuts":["operations.reflect.key.short"],"text":"shortcuts.editing.operations.reflect_short"},{"modifiers":["⌘"],"shortcuts":["⌫"],"text":"shortcuts.editing.operations.delete"}]}]},{"tab":"tools","text":"shortcuts.tools.title","columns":[{"rows":[{"section":"info","text":"shortcuts.tools.info.title"},{"modifiers":["⌘"],"shortcuts":["info_panels.key"],"text":"shortcuts.tools.info.all"},{"modifiers":["⌘","⇧"],"shortcuts":["info_panels.background.key"],"text":"shortcuts.tools.info.background"},{"modifiers":["⌘","⇧"],"shortcuts":["info_panels.history.key"],"text":"shortcuts.tools.info.history"},{"modifiers":["⌘","⇧"],"shortcuts":["info_panels.location.key"],"text":"shortcuts.tools.info.location"},{"modifiers":["⌘","⇧"],"shortcuts":["info_panels.measurement.key"],"text":"shortcuts.tools.info.measurement"}]}]}];
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"},"info_panels":{"key":"I","background":{"key":"B","title":"Background","zoom":"Zoom","vintage":"Vintage","unknown":"Unknown","show_tiles":"Show Tiles","hide_tiles":"Hide Tiles"},"history":{"key":"H","title":"History","selected":"{n} selected","version":"Version","last_edit":"Last Edit","edited_by":"Edited By","changeset":"Changeset","unknown":"Unknown","link_text":"History on openstreetmap.org"},"location":{"key":"L","title":"Location","unknown_location":"Unknown Location"},"measurement":{"key":"M","title":"Measurement","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","key":"B","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:\n   - {zoom}/{z}, {x}, {y} for Z/X/Y tile scheme\n   - {ty} for flipped TMS-style Y coordinates\n   - {u} for quadtile scheme\n   - {switch:a,b,c} for DNS server multiplexing\n\nExample:\n{example}","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.","key":"/"}},"map_data":{"title":"Map Data","description":"Map Data","key":"F","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.","key":"W"},"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 my changes","reset":"Discard my changes"},"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","key":"H","help":"# Help\n\nThis is an editor for [OpenStreetMap](http://www.openstreetmap.org/), the\nfree and editable map of the world. You can use it to add and update\ndata in your area, making an open-source and open-data map of the world\nbetter for everyone.\n\nEdits that you make on this map will be visible to everyone who uses\nOpenStreetMap. In order to make an edit, you'll need to\n[log in](https://www.openstreetmap.org/login).\n\nThe [iD editor](http://ideditor.com/) is a collaborative project with [source\ncode available on GitHub](https://github.com/openstreetmap/iD).\n","editing_saving":"# Editing & Saving\n\nThis editor is designed to work primarily online, and you're accessing\nit through a website right now.\n\n### Selecting Features\n\nTo select a map feature, like a road or point of interest, click\non it on the map. This will highlight the selected feature, open a panel with\ndetails about it, and show a menu of things you can do with the feature.\n\nTo select multiple features, hold down the 'Shift' key. Then either click\non the features you want to select, or drag on the map to draw a rectangle.\nThis will draw a box and select all the points within it.\n\n### Saving Edits\n\nWhen you make changes like editing roads, buildings, and places, these are\nstored locally until you save them to the server. Don't worry if you make\na mistake - you can undo changes by clicking the undo button, and redo\nchanges by clicking the redo button.\n\nClick 'Save' to finish a group of edits - for instance, if you've completed\nan area of town and would like to start on a new area. You'll have a chance\nto review what you've done, and the editor supplies helpful suggestions\nand warnings if something doesn't seem right about the changes.\n\nIf everything looks good, you can enter a short comment explaining the change\nyou made, and click 'Save' again to post the changes\nto [OpenStreetMap.org](http://www.openstreetmap.org/), where they are visible\nto all other users and available for others to build and improve upon.\n\nIf you can't finish your edits in one sitting, you can leave the editor\nwindow and come back (on the same browser and computer), and the\neditor application will offer to restore your work.\n\n### Using the editor\n\nYou can view a list of keyboard shortcuts by pressing the `?` key.\n","roads":"# Roads\n\nYou can create, fix, and delete roads with this editor. Roads can be all\nkinds: paths, highways, trails, cycleways, and more - any often-crossed\nsegment should be mappable.\n\n### Selecting\n\nClick on a road to select it. An outline should become visible, along\nwith a small tools menu on the map and a sidebar showing more information\nabout the road.\n\n### Modifying\n\nOften you'll see roads that aren't aligned to the imagery behind them\nor to a GPS track. You can adjust these roads so they are in the correct\nplace.\n\nFirst click on the road you want to change. This will highlight it and show\ncontrol points along it that you can drag to better locations. If\nyou want to add new control points for more detail, double-click a part\nof the road without a node, and one will be added.\n\nIf the road connects to another road, but doesn't properly connect on\nthe map, you can drag one of its control points onto the other road in\norder to join them. Having roads connect is important for the map\nand essential for providing driving directions.\n\nYou can also click the 'Move' tool or press the `M` shortcut key to move the entire road at\none time, and then click again to save that movement.\n\n### Deleting\n\nIf a road is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.\n\nYou can delete a road by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n\n### Creating\n\nFound somewhere there should be a road but there isn't? Click the 'Line'\nicon in the top-left of the editor or press the shortcut key `2` to start drawing\na line.\n\nClick on the start of the road on the map to start drawing. If the road\nbranches off from an existing road, start by clicking on the place where they connect.\n\nThen click on points along the road so that it follows the right path, according\nto satellite imagery or GPS. If the road you are drawing crosses another road, connect\nit by clicking on the intersection point. When you're done drawing, double-click\nor press 'Return' or 'Enter' on your keyboard.\n","gps":"# GPS\n\nCollected GPS traces are one valuable source of data for OpenStreetMap. This editor\nsupports local traces - `.gpx` files on your local computer. You can collect\nthis kind of GPS trace with a number of smartphone applications as well as\npersonal GPS hardware.\n\nFor information on how to perform a GPS survey, read\n[Mapping with a smartphone, GPS, or paper](http://learnosm.org/en/mobile-mapping/).\n\nTo use a GPX track for mapping, drag and drop the GPX file onto the map\neditor. If it's recognized, it will be added to the map as a bright purple\nline. Click on the 'Map Data' menu on the right side to enable,\ndisable, or zoom to this new GPX-powered layer.\n\nThe GPX track isn't directly uploaded to OpenStreetMap - the best way to\nuse it is to draw on the map, using it as a guide for the new features that\nyou add, and also to [upload it to OpenStreetMap](http://www.openstreetmap.org/trace/create)\nfor other users to use.\n","imagery":"# Imagery\n\nAerial imagery is an important resource for mapping. A combination of\nairplane flyovers, satellite views, and freely-compiled sources are available\nin the editor under the 'Background Settings' menu on the right.\n\nBy default a [Bing Maps](http://www.bing.com/maps/) satellite layer is\npresented in the editor, but as you pan and zoom the map to new geographical\nareas, new sources will become available. Some countries, like the United\nStates, France, and Denmark have very high-quality imagery available for some areas.\n\nImagery is sometimes offset from the map data because of a mistake on the\nimagery provider's side. If you see a lot of roads shifted from the background,\ndon't immediately move them all to match the background. Instead you can adjust\nthe imagery so that it matches the existing data by clicking 'Fix alignment' at\nthe bottom of the Background Settings UI.\n","addresses":"# Addresses\n\nAddresses are some of the most useful information for the map.\n\nAlthough addresses are often represented as parts of streets, in OpenStreetMap\nthey're recorded as attributes of buildings and places along streets.\n\nYou can add address information to places mapped as building outlines\nas well as those mapped as single points. The optimal source of address\ndata is from an on-the-ground survey or personal knowledge - as with any\nother feature, copying from commercial sources like Google Maps is strictly\nforbidden.\n","inspector":"# Using the Inspector\n\nThe inspector is the section on the left side of the page that allows you to\nedit the details of the selected feature.\n\n### Selecting a Feature Type\n\nAfter you add a point, line, or area, you can choose what type of feature it\nis, like whether it's a highway or residential road, supermarket or cafe.\nThe inspector will display buttons for common feature types, and you can\nfind others by typing what you're looking for in the search box.\n\nClick the 'i' in the bottom-right-hand corner of a feature type button to\nlearn more about it. Click a button to choose that type.\n\n### Using Forms and Editing Tags\n\nAfter you choose a feature type, or when you select a feature that already\nhas a type assigned, the inspector will display fields with details about\nthe feature like its name and address.\n\nBelow the fields you see, you can click the 'Add field' dropdown to add\nother details, like a Wikipedia link, wheelchair access, and more.\n\nAt the bottom of the inspector, click 'Additional tags' to add arbitrary\nother tags to the element. [Taginfo](http://taginfo.openstreetmap.org/) is a\ngreat resource for learn more about popular tag combinations.\n\nChanges you make in the inspector are automatically applied to the map.\nYou can undo them at any time by clicking the 'Undo' button.\n","buildings":"# Buildings\n\nOpenStreetMap is the world's largest database of buildings. You can create\nand improve this database.\n\n### Selecting\n\nYou can select a building by clicking on its border. This will highlight the\nbuilding and open a small tools menu and a sidebar showing more information\nabout the building.\n\n### Modifying\n\nSometimes buildings are incorrectly placed or have incorrect tags.\n\nTo move an entire building, select it, then click the 'Move' tool. Move your\nmouse to shift the building, and click when it's correctly placed.\n\nTo fix the specific shape of a building, click and drag the nodes that form\nits border into better places.\n\n### Creating\n\nOne of the main questions around adding buildings to the map is that\nOpenStreetMap records buildings both as shapes and points. The rule of thumb\nis to _map a building as a shape whenever possible_, and map companies, homes,\namenities, and other things that operate out of buildings as points placed\nwithin the building shape.\n\nStart drawing a building as a shape by clicking the 'Area' button in the top\nleft of the interface, and end it either by pressing 'Return' on your keyboard\nor clicking on the first node drawn to close the shape.\n\n### Deleting\n\nIf a building is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the building could simply be newly built.\n\nYou can delete a building by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n","relations":"# Relations\n\nA relation is a special type of feature in OpenStreetMap that groups together\nother features. For example, two common types of relations are *route relations*,\nwhich group together sections of road that belong to a specific freeway or\nhighway, and *multipolygons*, which group together several lines that define\na complex area (one with several pieces or holes in it like a donut).\n\nThe group of features in a relation are called *members*. In the sidebar, you can\nsee which relations a feature is a member of, and click on a relation there\nto select the it. When the relation is selected, you can see all of its\nmembers listed in the sidebar and highlighted on the map.\n\nFor the most part, iD will take care of maintaining relations automatically\nwhile you edit. The main thing you should be aware of is that if you delete a\nsection of road to redraw it more accurately, you should make sure that the\nnew section is a member of the same relations as the original.\n\n## Editing Relations\n\nIf you want to edit relations, here are the basics.\n\nTo add a feature to a relation, select the feature, click the \"+\" button in the\n\"All relations\" section of the sidebar, and select or type the name of the relation.\n\nTo create a new relation, select the first feature that should be a member,\nclick the \"+\" button in the \"All relations\" section, and select \"New relation...\".\n\nTo remove a feature from a relation, select the feature and click the trash\nbutton next to the relation you want to remove it from.\n\nYou can create multipolygons with holes using the \"Merge\" tool. Draw two areas (inner\nand outer), hold the Shift key and click on each of them to select them both, and then\nclick the \"Merge\" (+) button.\n"},"intro":{"done":"done","ok":"OK","graph":{"block_number":"<value for addr:block_number>","city":"Three Rivers","county":"<value for addr:county>","district":"<value for addr:district>","hamlet":"<value for addr:hamlet>","neighbourhood":"<value for addr:neighbourhood>","postcode":"49093","province":"<value for addr:province>","quarter":"<value for addr:quarter>","state":"MI","subdistrict":"<value for addr:subdistrict>","suburb":"<value for addr:suburb>","countrycode":"us","name":{"1st-avenue":"1st Avenue","2nd-avenue":"2nd Avenue","4th-avenue":"4th Avenue","5th-avenue":"5th Avenue","6th-avenue":"6th Avenue","6th-street":"6th Street","7th-avenue":"7th Avenue","8th-avenue":"8th Avenue","9th-avenue":"9th Avenue","10th-avenue":"10th Avenue","11th-avenue":"11th Avenue","12th-avenue":"12th Avenue","access-point-employment":"Access Point Employment","adams-street":"Adams Street","andrews-elementary-school":"Andrews Elementary School","andrews-street":"Andrews Street","armitage-street":"Armitage Street","barrows-school":"Barrows School","battle-street":"Battle Street","bennett-street":"Bennett Street","bowman-park":"Bowman Park","collins-drive":"Collins Drive","conrail-railroad":"Conrail Railroad","conservation-park":"Conservation Park","constantine-street":"Constantine Street","cushman-street":"Cushman Street","dollar-tree":"Dollar Tree","douglas-avenue":"Douglas Avenue","east-street":"East Street","elm-street":"Elm Street","flower-street":"Flower Street","foster-street":"Foster Street","french-street":"French Street","garden-street":"Garden Street","gem-pawnbroker":"Gem Pawnbroker","golden-finch-framing":"Golden Finch Framing","grant-avenue":"Grant Avenue","hoffman-pond":"Hoffman Pond","hoffman-street":"Hoffman Street","hook-avenue":"Hook Avenue","jefferson-street":"Jefferson Street","kelsey-street":"Kelsey Street","lafayette-park":"LaFayette Park","las-coffee-cafe":"L.A.'s Coffee Cafe","lincoln-avenue":"Lincoln Avenue","lowrys-books":"Lowry's Books","lynns-garage":"Lynn's Garage","main-street-barbell":"Main Street Barbell","main-street-cafe":"Main Street Cafe","main-street-fitness":"Main Street Fitness","main-street":"Main Street","maple-street":"Maple Street","marina-park":"Marina Park","market-street":"Market Street","memory-isle-park":"Memory Isle Park","memory-isle":"Memory Isle","michigan-avenue":"Michigan Avenue","middle-street":"Middle Street","millard-street":"Millard Street","moore-street":"Moore Street","morris-avenue":"Morris Avenue","mural-mall":"Mural Mall","paisanos-bar-and-grill":"Paisano's Bar and Grill","paisley-emporium":"Paisley Emporium","paparazzi-tattoo":"Paparazzi Tattoo","pealer-street":"Pealer Street","pine-street":"Pine Street","pizza-hut":"Pizza Hut","portage-avenue":"Portage Avenue","portage-river":"Portage River","preferred-insurance-services":"Preferred Insurance Services","railroad-drive":"Railroad Drive","river-city-appliance":"River City Appliance","river-drive":"River Drive","river-road":"River Road","river-street":"River Street","riverside-cemetery":"Riverside Cemetery","riverwalk-trail":"Riverwalk Trail","riviera-theatre":"Riviera Theatre","rocky-river":"Rocky River","saint-joseph-river":"Saint Joseph River","scidmore-park-petting-zoo":"Scidmore Park Petting Zoo","scidmore-park":"Scidmore Park","scouter-park":"Scouter Park","sherwin-williams":"Sherwin-Williams","south-street":"South Street","southern-michigan-bank":"Southern Michigan Bank","spring-street":"Spring Street","sturgeon-river-road":"Sturgeon River Road","three-rivers-city-hall":"Three Rivers City Hall","three-rivers-elementary-school":"Three Rivers Elementary School","three-rivers-fire-department":"Three Rivers Fire Department","three-rivers-high-school":"Three Rivers High School","three-rivers-middle-school":"Three Rivers Middle School","three-rivers-municipal-airport":"Three Rivers Municipal Airport","three-rivers-post-office":"Three Rivers Post Office","three-rivers-public-library":"Three Rivers Public Library","three-rivers":"Three Rivers","unique-jewelry":"Unique Jewelry","walnut-street":"Walnut Street","washington-street":"Washington Street","water-street":"Water Street","west-street":"West Street","wheeler-street":"Wheeler Street","william-towing":"William Towing","willow-drive":"Willow Drive","wood-street":"Wood Street","world-fare":"World Fare"}},"welcome":{"title":"Welcome","welcome":"Welcome! This walkthrough will teach you the basics of editing on OpenStreetMap.","practice":"All of the data in this walkthrough is just for practicing, and any edits that you make in the walkthrough will not be saved.","words":"This walkthrough will introduce some new words and concepts. When we introduce a new word, we'll use *italics*.","mouse":"You can use any input device to edit the map, but this walkthrough assumes you have a mouse with left and right buttons. **If you want to attach a mouse, do so now, then click OK.**","leftclick":"When this tutorial asks you to click or double-click, we mean with the left button. On a trackpad it might be a single-click or single-finger tap. **Left-click {num} times.**","rightclick":"Sometimes we'll also ask you to right-click. This might be the same as control-click, or two-finger tap on a trackpad. Your keyboard might even have a 'menu' key that works like right-click. **Right-click {num} times.**","chapters":"So far, so good! You can use the buttons below to skip chapters at any time or to restart a chapter if you get stuck. Let's begin! **Click '{next}' to continue.**"},"navigation":{"title":"Navigation","drag":"The main map area shows OpenStreetMap data on top of a background.{br}You can drag the map by pressing and holding the left mouse button while moving the mouse around. You can also use the arrow keys on your keyboard. **Drag the map!**","zoom":"You can zoom in or out by scrolling with the mouse wheel or trackpad, or by clicking the {plus} / {minus} buttons. **Zoom the map!**","features":"We use the word *features* to describe the things that appear on the map. Anything in the real world can be mapped as a feature on OpenStreetMap.","points_lines_areas":"Map features are represented using *points, lines, or areas.*","nodes_ways":"In OpenStreetMap, points are sometimes called *nodes*, and lines and areas are sometimes called *ways*.","click_townhall":"All features on the map can be selected by clicking on them. **Click on the point to select it.**","selected_townhall":"Great! The point is now selected. Selected features are drawn with a pulsing glow.","editor_townhall":"When a feature is selected, the *feature editor* is displayed alongside the map.","preset_townhall":"The top part of the feature editor shows the feature's type. This point is a {preset}.","fields_townhall":"The middle part of the feature editor contains *fields* showing the feature's attributes, such as its name and address.","close_townhall":"**Close the feature editor by hitting escape or pressing the {button} button in the upper corner.**","search_street":"You can also search for features in the current view, or worldwide. **Search for '{name}'.**","choose_street":"**Choose {name} from the list to select it.**","selected_street":"Great! {name} is now selected.","editor_street":"The fields shown for a street are different than the fields that were shown for the town hall.{br}For this selected street, the feature editor shows fields like '{field1}' and '{field2}'. **Close the feature editor by hitting escape or pressing the {button} button.**","play":"Try moving the map and clicking on some other features to see what kinds of things can be added to OpenStreetMap. **When you are ready to continue to the next chapter, click '{next}'.**"},"points":{"title":"Points","add_point":"*Points* can be used to represent features such as shops, restaurants, and monuments.{br}They mark a specific location, and describe what's there. **Click the {button} Point button to add a new point.**","place_point":"To place the new point on the map, position your mouse cursor where the point should go, then left-click or press the spacebar. **Move the mouse pointer over this building, then left-click or press the spacebar.**","search_cafe":"There are many different features that can be represented by points. The point you just added is a cafe. **Search for '{preset}'.**","choose_cafe":"**Choose {preset} from the list.**","feature_editor":"The point is now marked as a cafe. Using the feature editor, we can add more information about the cafe.","add_name":"In OpenStreetMap, all of the fields are optional, and it's OK to leave a field blank if you are unsure.{br}Let's pretend that you have local knowledge of this cafe, and you know its name. **Add a name for the cafe.**","add_close":"The feature editor will remember all of your changes automatically. **When you are finished adding the name, hit escape, enter, or click the {button} button to close the feature editor.**","reselect":"Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the cafe you just created.**","update":"Let's fill in some more details for this cafe. You can change its name, add a cuisine, or add an address. **Change the cafe details.**","update_close":"**When you are finished updating the cafe, hit escape, enter, or click the {button} button to close the feature editor.**","rightclick":"You can right-click on any feature to see the *edit menu*, which shows a list of editing operations that can be performed. **Right-click to select the point you created and show the edit menu.**","delete":"It's OK to delete features that don't exist in the real world.{br}Deleting a feature from OpenStreetMap removes it from the map that everyone uses, so you should make sure a feature is really gone before you delete it. **Click on the {button} button to delete the point.**","undo":"You can always undo any changes up until you save your edits to OpenStreetMap. **Click on the {button} button to undo the delete and get the point back.**","play":"Now that you know how to create and edit points, try creating a few more points for practice! **When you are ready to continue to the next chapter, click '{next}'.**"},"areas":{"title":"Areas","add_playground":"*Areas* are used to show the boundaries of features like lakes, buildings, and residential areas.{br}They can be also be used for more detailed mapping of many features you might normally map as points. **Click the {button} Area button to add a new area.**","start_playground":"Let's add this playground to the map by drawing an area. Areas are drawn by placing *nodes* along the outer edge of the feature. **Click or press spacebar to place a starting node on one of the corners of the playground.**","continue_playground":"Continue drawing the area by placing more nodes along the playground's edge. It is OK to connect the area to the existing walking paths.{br}Tip: You can hold down the '{alt}' key to prevent nodes from connecting to other features. **Continue drawing an area for the playground.**","finish_playground":"Finish the area by pressing enter, or clicking again on either the first or last node. **Finish drawing an area for the playground.**","search_playground":"**Search for '{preset}'.**","choose_playground":"**Choose {preset} from the list.**","add_field":"This playground doesn't have an official name, so we won't add anything in the Name field.{br}Instead let's add some additional details about the playground to the Description field. **Open the Add Field list.**","choose_field":"**Choose {field} from the list.**","retry_add_field":"You didn't select the {field} field. Let's try again.","describe_playground":"**Add a description, then click the {button} button to close the feature editor.**","play":"Good job! Try drawing a few more areas, and see what other kinds of area features you can add to OpenStreetMap. **When you are ready to continue to the next chapter, click '{next}'.**"},"lines":{"title":"Lines","add_line":"*Lines* are used to represent features such as roads, railroads, and rivers. **Click the {button} Line button to add a new line.**","start_line":"Here is a road that is missing. Let's add it!{br}In OpenStreetMap, lines should be drawn down the center of the road. You can drag and zoom the map while drawing if necessary. **Start a new line by clicking at the top end of this missing road.**","intersect":"Click or press spacebar to add more nodes to the line.{br}Roads, and many other types of lines, are part of a larger network. It is important for these lines to be connected properly in order for routing applications to work. **Click on {name} to create an intersection connecting the two lines.**","retry_intersect":"The road needs to intersect {name}. Let's try again!","continue_line":"Continue drawing the line for the new road. Remember that you can drag and zoom the map if needed.{br}When you are finished drawing, click on the last node again. **Finish drawing the road.**","choose_category_road":"**Select {category} from the list.**","choose_preset_residential":"There are many different types of roads, but this one is a residential road. **Choose the {preset} type.**","retry_preset_residential":"You didn't select the {preset} type. **Click here to choose again.**","name_road":"**Give this road a name, then hit escape, enter, or click the {button} button to close the feature editor.**","did_name_road":"Looks good! Next we will learn how to update the shape of a line.","update_line":"Sometimes you will need to change the shape of an existing line. Here is a road that doesn't look quite right.","add_node":"We can add some nodes to this line to improve its shape. One way to add a node is to double-click the line where you want to add a node. **Double-click on the line to create a new node.**","start_drag_endpoint":"When a line is selected, you can drag any of its nodes by clicking and holding down the left mouse button while you drag. **Drag the endpoint to the place where these roads should intersect.**","finish_drag_endpoint":"This spot looks good. **Release the left mouse button to finish dragging.**","start_drag_midpoint":"Small triangles are drawn at the *midpoints* between nodes. Another way to create a new node is to drag a midpoint to a new location. **Drag the midpoint triangle to create a new node along the curve of the road.**","continue_drag_midpoint":"This line is looking much better! Continue to adjust this line by double-clicking or dragging midpoints until the curve matches the road shape. **When you're happy with how the line looks, click OK.**","delete_lines":"It's OK to delete lines for roads that don't exist in the real world.{br}Here's an example where the city planned a {street} but never built it. We can improve this part of the map by deleting the extra lines.","rightclick_intersection":"The last real street is {street1}, so we will *split* {street2} at this intersection and remove everything above it. **Right click on the intersection node.**","split_intersection":"**Click on the {button} button to split {street}.**","retry_split":"You didn't click the Split button. Try again.","did_split_multi":"Good job! {street1} is now split into two pieces. The top part can be removed. **Click the top part of {street2} to select it.**","did_split_single":"**Click the top part of {street2} to select it.**","multi_select":"{selected} is now selected. Let's also select {other1}. You can shift-click to select multiple things. **Shift-click on {other2}.**","multi_rightclick":"Good! Both lines to delete are now selected. **Right-click on one of the lines to show the edit menu.**","multi_delete":"**Click on the {button} button to delete the extra lines.**","retry_delete":"You didn't click the Delete button. Try again.","play":"Great! Use the skills that you've learned in this chapter to practice editing some more lines. **When you are ready to continue to the next chapter, click '{next}'.**"},"buildings":{"title":"Buildings","add_building":"OpenStreetMap is the world's largest database of buildings.{br}You can help improve this database by tracing buildings that aren't already mapped. **Click the {button} Area button to add a new area.**","start_building":"Let's add this house to the map by tracing its outline.{br}Buildings should be traced around their footprint as accurately as possible. **Click or press spacebar to place a starting node on one of the corners of the building.**","continue_building":"Continue adding more nodes to trace the outline of the building. Remember that you can zoom in if you want to add more details.{br}Finish the building by pressing enter, or clicking again on either the first or last node. **Finish tracing the building.**","retry_building":"It looks like you had some trouble placing the nodes at the building corners. Try again!","choose_category_building":"**Choose {category} from the list.**","choose_preset_house":"There are many different types of buildings, but this one is clearly a house.{br}If you're not sure of the type, it's OK to just choose the generic Building type. **Choose the {preset} type.**","close":"**Hit escape or click the {button} button to close the feature editor.**","rightclick_building":"**Right-click to select the building you created and show the edit menu.**","square_building":"The house that you just added will look even better with perfectly square corners. **Click on the {button} button to square the building shape.**","retry_square":"You didn't click the Square button. Try again.","done_square":"See how the corners of the building moved into place? Let's learn another useful trick.","add_tank":"Next we'll trace this circular storage tank. **Click the {button} Area button to add a new area.**","start_tank":"Don't worry, you won't need to draw a perfect circle. Just draw an area inside the tank that touches its edge. **Click or press spacebar to place a starting node on the edge of the tank.**","continue_tank":"Add a few more nodes around the edge. The circle will be created outside the nodes that you draw.{br}Finish the area by pressing enter, or clicking again on either the first or last node. **Finish tracing the tank.**","search_tank":"**Search for '{preset}'.**","choose_tank":"**Choose {preset} from the list.**","rightclick_tank":"**Right-click to select the storage tank you created and show the edit menu.**","circle_tank":"**Click on the {button} button to make the tank a circle.**","retry_circle":"You didn't click the Circularize button. Try again.","play":"Great Job! Practice tracing a few more buildings, and try some of the other commands on the edit menu. **When you are ready to continue to the next chapter, click '{next}'.**"},"startediting":{"title":"Start Editing","help":"You're now ready to edit OpenStreetMap!{br}You can replay this walkthrough anytime or view more documentation by clicking the {button} Help button or pressing the '{key}' key.","shortcuts":"You can view a list of commands along with their keyboard shortcuts by pressing the '{key}' key.","save":"Don't forget to regularly save your changes!","start":"Start mapping!"}},"shortcuts":{"title":"Keyboard shortcuts","tooltip":"Show the keyboard shortcuts screen.","toggle":{"key":"?"},"key":{"alt":"Alt","backspace":"Backspace","cmd":"Cmd","ctrl":"Ctrl","delete":"Delete","del":"Del","end":"End","enter":"Enter","esc":"Esc","home":"Home","option":"Option","pause":"Pause","pgdn":"PgDn","pgup":"PgUp","return":"Return","shift":"Shift","space":"Space"},"gesture":{"drag":"drag"},"or":"-or-","browsing":{"title":"Browsing","navigation":{"title":"Navigation","pan":"Pan map","pan_more":"Pan map by one screenful","zoom":"Zoom in / Zoom out","zoom_more":"Zoom in / Zoom out by a lot"},"help":{"title":"Help","help":"Show help/documentation","keyboard":"Show keyboard shortcuts"},"display_options":{"title":"Display options","background":"Show background options","background_switch":"Switch back to last background","map_data":"Show map data options","fullscreen":"Enter full screen mode","wireframe":"Toggle wireframe mode","minimap":"Toggle minimap"},"selecting":{"title":"Selecting features","select_one":"Select a single feature","select_multi":"Select multiple features","lasso":"Draw a selection lasso around features"},"with_selected":{"title":"With feature selected","edit_menu":"Toggle edit menu"},"vertex_selected":{"title":"With node selected","previous":"Jump to previous node","next":"Jump to next node","first":"Jump to first node","last":"Jump to last node","change_parent":"Switch parent way"}},"editing":{"title":"Editing","drawing":{"title":"Drawing","add_point":"'Add point' mode","add_line":"'Add line' mode","add_area":"'Add area' mode","place_point":"Place a point","disable_snap":"Hold to disable point snapping","stop_line":"Finish drawing a line or area"},"operations":{"title":"Operations","continue_line":"Continue a line at the selected node","merge":"Combine (merge) selected features","disconnect":"Disconnect features at the selected node","split":"Split a line into two at the selected node","reverse":"Reverse a line","move":"Move selected features","rotate":"Rotate selected features","orthogonalize":"Straighten line / Square area corners","circularize":"Circularize a closed line or area","reflect_long":"Reflect features across the longer axis","reflect_short":"Reflect features across the shorter axis","delete":"Delete selected features"},"commands":{"title":"Commands","copy":"Copy selected features","paste":"Paste copied features","undo":"Undo last action","redo":"Redo last action","save":"Save changes"}},"tools":{"title":"Tools","info":{"title":"Information","all":"Toggle all information panels","background":"Toggle background panel","history":"Toggle history panel","location":"Toggle location panel","measurement":"Toggle measurement panel"}}},"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"}},"clothes":{"label":"Clothes"},"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":"Content"},"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/output/electricity":{"label":"Power Output","placeholder":"50 MW, 100 MW, 200 MW..."},"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"},"label":{"label":"Label"},"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"},"manhole":{"label":"Type"},"map_size":{"label":"Coverage"},"map_type":{"label":"Type"},"maxheight":{"label":"Max Height","placeholder":"4, 4.5, 5, 14'0\", 14'6\", 15'0\""},"maxspeed":{"label":"Speed Limit","placeholder":"40, 50, 60..."},"maxstay":{"label":"Max Stay"},"maxweight":{"label":"Max Weight"},"mtb/scale":{"label":"Mountain Biking Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Solid gravel/packed earth, no obstacles, wide curves","1":"1: Some loose surface, small obstacles, wide curves","2":"2: Much loose surface, large obstacles, easy hairpins","3":"3: Slippery surface, large obstacles, tight hairpins","4":"4: Loose surface or boulders, dangerous hairpins","5":"5: Maximum difficulty, boulder fields, landslides","6":"6: Not rideable except by the very best mountain bikers"}},"mtb/scale/imba":{"label":"IMBA Trail Difficulty","placeholder":"Easy, Medium, Difficult...","options":{"0":"Easiest (white circle)","1":"Easy (green circle)","2":"Medium (blue square)","3":"Difficult (black diamond)","4":"Extremely Difficult (double black diamond)"}},"mtb/scale/uphill":{"label":"Mountain Biking Uphill Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Avg. incline <10%, gravel/packed earth, no obstacles","1":"1: Avg. incline <15%, gravel/packed earth, few small objects","2":"2: Avg. incline <20%, stable surface, fistsize rocks/roots","3":"3: Avg. incline <25%, variable surface, fistsize rocks/branches","4":"4: Avg. incline <30%, poor condition, big rocks/branches","5":"5: Very steep, bike generally needs to be pushed or carried"}},"name":{"label":"Name","placeholder":"Common name (if any)"},"natural":{"label":"Natural"},"network_bicycle":{"label":"Network Type","placeholder":"Local, Regional, National, International","options":{"lcn":"Local","rcn":"Regional","ncn":"National","icn":"International"}},"network_foot":{"label":"Network Type","placeholder":"Local, Regional, National, International","options":{"lwn":"Local","rwn":"Regional","nwn":"National","iwn":"International"}},"network_horse":{"label":"Network Type","placeholder":"Local, Regional, National, International","options":{"lhn":"Local","rhn":"Regional","nhn":"National","ihn":"International"}},"network_road":{"label":"Network"},"network":{"label":"Network"},"note":{"label":"Note"},"office":{"label":"Type"},"oneway_yes":{"label":"One Way","options":{"undefined":"Assumed to be Yes","yes":"Yes","no":"No"}},"oneway":{"label":"One Way","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"opening_hours":{"label":"Hours"},"operator":{"label":"Operator"},"outdoor_seating":{"label":"Outdoor Seating"},"par":{"label":"Par","placeholder":"3, 4, 5..."},"parallel_direction":{"label":"Direction","options":{"forward":"Forward","backward":"Backward"}},"park_ride":{"label":"Park and Ride"},"parking":{"label":"Type","options":{"surface":"Surface","multi-storey":"Multilevel","underground":"Underground","sheds":"Sheds","carports":"Carports","garage_boxes":"Garage Boxes","lane":"Roadside Lane"}},"payment_multi":{"label":"Payment Types"},"phone":{"label":"Phone","placeholder":"+31 42 123 4567"},"piste/difficulty":{"label":"Difficulty","placeholder":"Easy, Intermediate, Advanced...","options":{"novice":"Novice (instructional)","easy":"Easy (green circle)","intermediate":"Intermediate (blue square)","advanced":"Advanced (black diamond)","expert":"Expert (double black diamond)","freeride":"Freeride (off-piste)","extreme":"Extreme (climbing equipment required)"}},"piste/grooming":{"label":"Grooming","options":{"classic":"Classic","mogul":"Mogul","backcountry":"Backcountry","classic+skating":"Classic and Skating","scooter":"Scooter/Snowmobile","skating":"Skating"}},"piste/type":{"label":"Type","options":{"downhill":"Downhill","nordic":"Nordic","skitour":"Skitour","sled":"Sled","hike":"Hike","sleigh":"Sleigh","ice_skate":"Ice Skate","snow_park":"Snow Park","playground":"Playground"}},"place":{"label":"Type"},"plant":{"label":"Plant"},"plant/output/electricity":{"label":"Power Output","placeholder":"500 MW, 1000 MW, 2000 MW..."},"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/hindu":{"name":"Hindu Temple","terms":"garbhargriha,mandu,puja,shrine,temple"},"amenity/place_of_worship/jewish":{"name":"Synagogue","terms":"jewish"},"amenity/place_of_worship/muslim":{"name":"Mosque","terms":"muslim"},"amenity/place_of_worship/shinto":{"name":"Shinto Shrine","terms":"kami,torii"},"amenity/place_of_worship/sikh":{"name":"Sikh Temple","terms":"gurudwara,temple"},"amenity/place_of_worship/taoist":{"name":"Taoist Temple","terms":"daoist,monastery,temple"},"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/scrapyard":{"name":"Scrap Yard","terms":"car,junk,metal,salvage,scrap,u-pull-it,vehicle,wreck,yard"},"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/waste/dog_excrement":{"name":"Dog Excrement Bin","terms":"bin,garbage,rubbish,litter,trash,poo,dog"},"amenity/water_point":{"name":"RV Drinking Water","terms":""},"amenity/watering_place":{"name":"Animal Watering Place","terms":""},"area":{"name":"Area","terms":""},"area/highway":{"name":"Road Surface","terms":""},"barrier":{"name":"Barrier","terms":""},"barrier/entrance":{"name":"Entrance","terms":""},"barrier/block":{"name":"Block","terms":""},"barrier/bollard":{"name":"Bollard","terms":""},"barrier/border_control":{"name":"Border Control","terms":""},"barrier/cattle_grid":{"name":"Cattle Grid","terms":""},"barrier/city_wall":{"name":"City Wall","terms":""},"barrier/cycle_barrier":{"name":"Cycle Barrier","terms":""},"barrier/ditch":{"name":"Trench","terms":""},"barrier/fence":{"name":"Fence","terms":""},"barrier/gate":{"name":"Gate","terms":""},"barrier/hedge":{"name":"Hedge","terms":""},"barrier/kissing_gate":{"name":"Kissing Gate","terms":""},"barrier/lift_gate":{"name":"Lift Gate","terms":""},"barrier/retaining_wall":{"name":"Retaining Wall","terms":""},"barrier/stile":{"name":"Stile","terms":""},"barrier/toll_booth":{"name":"Toll Booth","terms":""},"barrier/wall":{"name":"Wall","terms":""},"boundary/administrative":{"name":"Administrative Boundary","terms":""},"building":{"name":"Building","terms":""},"building/bunker":{"name":"Bunker","terms":""},"building/entrance":{"name":"Entrance/Exit","terms":""},"building/train_station":{"name":"Train Station","terms":""},"building/apartments":{"name":"Apartments","terms":""},"building/barn":{"name":"Barn","terms":""},"building/cabin":{"name":"Cabin","terms":""},"building/cathedral":{"name":"Cathedral Building","terms":""},"building/chapel":{"name":"Chapel Building","terms":""},"building/church":{"name":"Church Building","terms":""},"building/college":{"name":"College Building","terms":"university"},"building/commercial":{"name":"Commercial Building","terms":""},"building/construction":{"name":"Building Under Construction","terms":""},"building/detached":{"name":"Detached House","terms":"home,single,family,residence,dwelling"},"building/dormitory":{"name":"Dormitory","terms":""},"building/garage":{"name":"Garage","terms":""},"building/garages":{"name":"Garages","terms":""},"building/greenhouse":{"name":"Greenhouse","terms":""},"building/hospital":{"name":"Hospital Building","terms":""},"building/hotel":{"name":"Hotel Building","terms":""},"building/house":{"name":"House","terms":"home,family,residence,dwelling"},"building/hut":{"name":"Hut","terms":""},"building/industrial":{"name":"Industrial Building","terms":""},"building/kindergarten":{"name":"Preschool/Kindergarten Building","terms":"kindergarden,pre-school"},"building/public":{"name":"Public Building","terms":""},"building/residential":{"name":"Residential Building","terms":""},"building/retail":{"name":"Retail Building","terms":""},"building/roof":{"name":"Roof","terms":""},"building/school":{"name":"School Building","terms":"academy,elementary school,middle school,high school"},"building/semidetached_house":{"name":"Semi-Detached House","terms":"home,double,duplex,twin,family,residence,dwelling"},"building/shed":{"name":"Shed","terms":""},"building/stable":{"name":"Stable","terms":""},"building/static_caravan":{"name":"Static Mobile Home","terms":""},"building/terrace":{"name":"Row Houses","terms":"home,terrace,brownstone,family,residence,dwelling"},"building/university":{"name":"University Building","terms":"college"},"building/warehouse":{"name":"Warehouse","terms":""},"camp_site/camp_pitch":{"name":"Camp Pitch","terms":"tent,rv"},"club":{"name":"Club","terms":"social"},"craft":{"name":"Craft","terms":""},"craft/jeweler":{"name":"Jeweler","terms":""},"craft/locksmith":{"name":"Locksmith","terms":""},"craft/optician":{"name":"Optician","terms":""},"craft/tailor":{"name":"Tailor","terms":"clothes,suit"},"craft/basket_maker":{"name":"Basket Maker","terms":""},"craft/beekeeper":{"name":"Beekeeper","terms":""},"craft/blacksmith":{"name":"Blacksmith","terms":""},"craft/boatbuilder":{"name":"Boat Builder","terms":""},"craft/bookbinder":{"name":"Bookbinder","terms":"book repair"},"craft/brewery":{"name":"Brewery","terms":"alcohol,beer,beverage,bier,booze,cider"},"craft/carpenter":{"name":"Carpenter","terms":"woodworker"},"craft/carpet_layer":{"name":"Carpet Layer","terms":""},"craft/caterer":{"name":"Caterer","terms":""},"craft/clockmaker":{"name":"Clockmaker","terms":""},"craft/confectionery":{"name":"Confectionery","terms":"sweets,candy"},"craft/distillery":{"name":"Distillery","terms":"alcohol,beverage,bourbon,booze,brandy,gin,hooch,liquor,mezcal,moonshine,rum,scotch,spirits,still,tequila,vodka,whiskey,whisky"},"craft/dressmaker":{"name":"Dressmaker","terms":"seamstress"},"craft/electrician":{"name":"Electrician","terms":"power,wire"},"craft/electronics_repair":{"name":"Electronics Repair Shop","terms":""},"craft/gardener":{"name":"Gardener","terms":"landscaper,grounds keeper"},"craft/glaziery":{"name":"Glaziery","terms":"glass,stained-glass,window"},"craft/handicraft":{"name":"Handicraft","terms":""},"craft/hvac":{"name":"HVAC","terms":"heat*,vent*,air conditioning"},"craft/insulator":{"name":"Insulator","terms":""},"craft/key_cutter":{"name":"Key Cutter","terms":""},"craft/metal_construction":{"name":"Metal Construction","terms":""},"craft/painter":{"name":"Painter","terms":""},"craft/photographer":{"name":"Photographer","terms":""},"craft/photographic_laboratory":{"name":"Photographic Laboratory","terms":"film"},"craft/plasterer":{"name":"Plasterer","terms":""},"craft/plumber":{"name":"Plumber","terms":"pipe"},"craft/pottery":{"name":"Pottery","terms":"ceramic"},"craft/rigger":{"name":"Rigger","terms":""},"craft/roofer":{"name":"Roofer","terms":""},"craft/saddler":{"name":"Saddler","terms":""},"craft/sailmaker":{"name":"Sailmaker","terms":""},"craft/sawmill":{"name":"Sawmill","terms":"lumber"},"craft/scaffolder":{"name":"Scaffolder","terms":""},"craft/sculpter":{"name":"Sculpter","terms":""},"craft/shoemaker":{"name":"Shoemaker","terms":"cobbler"},"craft/stonemason":{"name":"Stonemason","terms":"masonry"},"craft/sweep":{"name":"Chimney Sweep","terms":""},"craft/tiler":{"name":"Tiler","terms":""},"craft/tinsmith":{"name":"Tinsmith","terms":""},"craft/upholsterer":{"name":"Upholsterer","terms":""},"craft/watchmaker":{"name":"Watchmaker","terms":""},"craft/window_construction":{"name":"Window Construction","terms":"glass"},"craft/winery":{"name":"Winery","terms":""},"embankment":{"name":"Embankment","terms":""},"emergency/designated":{"name":"Emergency Access Designated","terms":""},"emergency/destination":{"name":"Emergency Access Destination","terms":""},"emergency/no":{"name":"Emergency Access No","terms":""},"emergency/official":{"name":"Emergency Access Official","terms":""},"emergency/private":{"name":"Emergency Access Private","terms":""},"emergency/yes":{"name":"Emergency Access Yes","terms":""},"emergency/ambulance_station":{"name":"Ambulance Station","terms":"EMS,EMT,rescue"},"emergency/defibrillator":{"name":"Defibrillator","terms":"AED"},"emergency/fire_hydrant":{"name":"Fire Hydrant","terms":"fire plug"},"emergency/phone":{"name":"Emergency Phone","terms":""},"entrance":{"name":"Entrance/Exit","terms":""},"footway/crossing":{"name":"Street Crossing","terms":""},"footway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"footway/sidewalk":{"name":"Sidewalk","terms":""},"ford":{"name":"Ford","terms":""},"golf/bunker":{"name":"Sand Trap","terms":"hazard,bunker"},"golf/fairway":{"name":"Fairway","terms":""},"golf/green":{"name":"Putting Green","terms":""},"golf/hole":{"name":"Golf Hole","terms":""},"golf/lateral_water_hazard_area":{"name":"Lateral Water Hazard","terms":""},"golf/lateral_water_hazard_line":{"name":"Lateral Water Hazard","terms":""},"golf/rough":{"name":"Rough","terms":""},"golf/tee":{"name":"Tee Box","terms":"teeing ground"},"golf/water_hazard_area":{"name":"Water Hazard","terms":""},"golf/water_hazard_line":{"name":"Water Hazard","terms":""},"healthcare/blood_donation":{"name":"Blood Donor Center","terms":"blood bank,blood donation,blood transfusion,apheresis,plasmapheresis,plateletpheresis,stem cell donation"},"highway/bridleway":{"name":"Bridle Path","terms":"bridleway,equestrian,horse"},"highway/bus_stop":{"name":"Bus Stop","terms":""},"highway/corridor":{"name":"Indoor Corridor","terms":"gallery,hall,hallway,indoor,passage,passageway"},"highway/crossing":{"name":"Street Crossing","terms":""},"highway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"highway/cycleway":{"name":"Cycle Path","terms":"bike"},"highway/elevator":{"name":"Elevator","terms":"lift"},"highway/footway":{"name":"Foot Path","terms":"hike,hiking,trackway,trail,walk"},"highway/give_way":{"name":"Yield Sign","terms":"give way,yield,sign"},"highway/living_street":{"name":"Living Street","terms":""},"highway/mini_roundabout":{"name":"Mini-Roundabout","terms":""},"highway/motorway_junction":{"name":"Motorway Junction / Exit","terms":""},"highway/motorway_link":{"name":"Motorway Link","terms":"ramp,on ramp,off ramp"},"highway/motorway":{"name":"Motorway","terms":"autobahn,expressway,freeway,highway,interstate,parkway,thruway,turnpike"},"highway/path":{"name":"Path","terms":"hike,hiking,trackway,trail,walk"},"highway/pedestrian":{"name":"Pedestrian Street","terms":""},"highway/primary_link":{"name":"Primary Link","terms":"ramp,on ramp,off ramp"},"highway/primary":{"name":"Primary Road","terms":""},"highway/raceway":{"name":"Racetrack (Motorsport)","terms":"auto*,formula one,kart,motocross,nascar,race*,track"},"highway/residential":{"name":"Residential Road","terms":""},"highway/rest_area":{"name":"Rest Area","terms":"rest stop"},"highway/road":{"name":"Unknown Road","terms":""},"highway/secondary_link":{"name":"Secondary Link","terms":"ramp,on ramp,off ramp"},"highway/secondary":{"name":"Secondary Road","terms":""},"highway/service":{"name":"Service Road","terms":""},"highway/service/alley":{"name":"Alley","terms":""},"highway/service/drive-through":{"name":"Drive-Through","terms":""},"highway/service/driveway":{"name":"Driveway","terms":""},"highway/service/emergency_access":{"name":"Emergency Access","terms":""},"highway/service/parking_aisle":{"name":"Parking Aisle","terms":""},"highway/services":{"name":"Service Area","terms":"services,travel plaza,service station"},"highway/speed_camera":{"name":"Speed Camera","terms":""},"highway/steps":{"name":"Steps","terms":"stairs,staircase"},"highway/stop":{"name":"Stop Sign","terms":"stop,halt,sign"},"highway/street_lamp":{"name":"Street Lamp","terms":"streetlight,street light,lamp,light,gaslight"},"highway/tertiary_link":{"name":"Tertiary Link","terms":"ramp,on ramp,off ramp"},"highway/tertiary":{"name":"Tertiary Road","terms":""},"highway/track":{"name":"Unmaintained Track Road","terms":"woods road,forest road,logging road,fire road,farm road,agricultural road,ranch road,carriage road,primitive,unmaintained,rut,offroad,4wd,4x4,four wheel drive,atv,quad,jeep,double track,two track"},"highway/traffic_mirror":{"name":"Traffic Mirror","terms":"blind spot,convex,corner,curved,roadside,round,safety,sphere,visibility"},"highway/traffic_signals":{"name":"Traffic Signals","terms":"light,stoplight,traffic light"},"highway/trunk_link":{"name":"Trunk Link","terms":"ramp,on ramp,off ramp"},"highway/trunk":{"name":"Trunk Road","terms":""},"highway/turning_circle":{"name":"Turning Circle","terms":"cul-de-sac"},"highway/turning_loop":{"name":"Turning Loop (Island)","terms":"cul-de-sac"},"highway/unclassified":{"name":"Minor/Unclassified Road","terms":""},"historic":{"name":"Historic Site","terms":""},"historic/archaeological_site":{"name":"Archaeological Site","terms":""},"historic/boundary_stone":{"name":"Boundary Stone","terms":""},"historic/castle":{"name":"Castle","terms":""},"historic/memorial":{"name":"Memorial","terms":""},"historic/monument":{"name":"Monument","terms":""},"historic/ruins":{"name":"Ruins","terms":""},"historic/tomb":{"name":"Tomb","terms":""},"historic/wayside_cross":{"name":"Wayside Cross","terms":""},"historic/wayside_shrine":{"name":"Wayside Shrine","terms":""},"junction":{"name":"Junction","terms":""},"landuse":{"name":"Land Use","terms":""},"landuse/farm":{"name":"Farmland","terms":""},"landuse/allotments":{"name":"Community Garden","terms":"allotment,garden"},"landuse/aquaculture":{"name":"Aquaculture","terms":"fish farm,crustacean,algae,aquafarming,shrimp farm,oyster farm,mariculture,algaculture"},"landuse/basin":{"name":"Basin","terms":""},"landuse/cemetery":{"name":"Cemetery","terms":""},"landuse/churchyard":{"name":"Churchyard","terms":""},"landuse/commercial":{"name":"Commercial Area","terms":""},"landuse/construction":{"name":"Construction","terms":""},"landuse/farmland":{"name":"Farmland","terms":"crop,grow,plant"},"landuse/farmyard":{"name":"Farmyard","terms":"crop,grow,plant"},"landuse/forest":{"name":"Forest","terms":"tree"},"landuse/garages":{"name":"Garages","terms":""},"landuse/grass":{"name":"Grass","terms":""},"landuse/harbour":{"name":"Harbor","terms":"boat"},"landuse/industrial":{"name":"Industrial Area","terms":""},"landuse/landfill":{"name":"Landfill","terms":"dump"},"landuse/meadow":{"name":"Meadow","terms":""},"landuse/military":{"name":"Military Area","terms":""},"landuse/military/airfield":{"name":"Military Airfield","terms":"air force,army,base,bomb,fight,force,guard,heli*,jet,marine,navy,plane,troop,war"},"landuse/military/barracks":{"name":"Barracks","terms":"air force,army,base,fight,force,guard,marine,navy,troop,war"},"landuse/military/bunker":{"name":"Military Bunker","terms":"air force,army,base,fight,force,guard,marine,navy,troop,war"},"landuse/military/checkpoint":{"name":"Checkpoint","terms":"air force,army,base,force,guard,marine,navy,troop,war"},"landuse/military/danger_area":{"name":"Danger Area","terms":"air force,army,base,blast,bomb,explo*,force,guard,mine,marine,navy,troop,war"},"landuse/military/naval_base":{"name":"Naval Base","terms":"base,fight,force,guard,marine,navy,ship,sub,troop,war"},"landuse/military/nuclear_explosion_site":{"name":"Nuclear Explosion Site","terms":"atom,blast,bomb,detonat*,nuke,site,test"},"landuse/military/obstacle_course":{"name":"Obstacle Course","terms":"army,base,force,guard,marine,navy,troop,war"},"landuse/military/office":{"name":"Military Office","terms":"air force,army,base,enlist,fight,force,guard,marine,navy,recruit,troop,war"},"landuse/military/range":{"name":"Military Range","terms":"air force,army,base,fight,fire,force,guard,gun,marine,navy,rifle,shoot*,snip*,train,troop,war"},"landuse/military/training_area":{"name":"Training Area","terms":"air force,army,base,fight,fire,force,guard,gun,marine,navy,rifle,shoot*,snip*,train,troop,war"},"landuse/orchard":{"name":"Orchard","terms":"fruit"},"landuse/plant_nursery":{"name":"Plant Nursery","terms":"flower,garden,grow,vivero"},"landuse/quarry":{"name":"Quarry","terms":""},"landuse/railway":{"name":"Railway Corridor","terms":"rail,train,track"},"landuse/recreation_ground":{"name":"Recreation Ground","terms":"playing fields"},"landuse/residential":{"name":"Residential Area","terms":""},"landuse/retail":{"name":"Retail Area","terms":""},"landuse/vineyard":{"name":"Vineyard","terms":"grape,wine"},"leisure":{"name":"Leisure","terms":""},"leisure/adult_gaming_centre":{"name":"Adult Gaming Center","terms":"gambling,slot machine"},"leisure/bird_hide":{"name":"Bird Hide","terms":"machan,ornithology"},"leisure/bowling_alley":{"name":"Bowling Alley","terms":""},"leisure/common":{"name":"Common","terms":"open space"},"leisure/dance":{"name":"Dance Hall","terms":"ballroom,jive,swing,tango,waltz"},"leisure/dog_park":{"name":"Dog Park","terms":""},"leisure/firepit":{"name":"Firepit","terms":"fireplace,campfire"},"leisure/fitness_centre":{"name":"Gym / Fitness Center","terms":"health,gym,leisure,studio"},"leisure/fitness_centre/yoga":{"name":"Yoga Studio","terms":"studio"},"leisure/fitness_station":{"name":"Outdoor Fitness Station","terms":"fitness,gym"},"leisure/garden":{"name":"Garden","terms":""},"leisure/golf_course":{"name":"Golf Course","terms":"links"},"leisure/horse_riding":{"name":"Horseback Riding Facility","terms":"equestrian,stable"},"leisure/ice_rink":{"name":"Ice Rink","terms":"hockey,skating,curling"},"leisure/marina":{"name":"Marina","terms":"boat"},"leisure/miniature_golf":{"name":"Miniature Golf","terms":"crazy golf,mini golf,putt-putt"},"leisure/nature_reserve":{"name":"Nature Reserve","terms":"protected,wildlife"},"leisure/park":{"name":"Park","terms":"esplanade,estate,forest,garden,grass,green,grounds,lawn,lot,meadow,parkland,place,playground,plaza,pleasure garden,recreation area,square,tract,village green,woodland"},"leisure/picnic_table":{"name":"Picnic Table","terms":"bench"},"leisure/pitch":{"name":"Sport Pitch","terms":"field"},"leisure/pitch/american_football":{"name":"American Football Field","terms":""},"leisure/pitch/baseball":{"name":"Baseball Diamond","terms":""},"leisure/pitch/basketball":{"name":"Basketball Court","terms":""},"leisure/pitch/beachvolleyball":{"name":"Beach Volleyball Court","terms":"volleyball"},"leisure/pitch/bowls":{"name":"Bowling Green","terms":""},"leisure/pitch/cricket":{"name":"Cricket Field","terms":""},"leisure/pitch/equestrian":{"name":"Riding Arena","terms":"dressage,equestrian,horse,horseback,riding"},"leisure/pitch/rugby_league":{"name":"Rugby League Field","terms":""},"leisure/pitch/rugby_union":{"name":"Rugby Union Field","terms":""},"leisure/pitch/skateboard":{"name":"Skate Park","terms":""},"leisure/pitch/soccer":{"name":"Soccer Field","terms":"football"},"leisure/pitch/table_tennis":{"name":"Ping Pong Table","terms":"table tennis,ping pong"},"leisure/pitch/tennis":{"name":"Tennis Court","terms":""},"leisure/pitch/volleyball":{"name":"Volleyball Court","terms":""},"leisure/playground":{"name":"Playground","terms":"jungle gym,play area"},"leisure/resort":{"name":"Resort","terms":""},"leisure/running_track":{"name":"Racetrack (Running)","terms":"race*,running,sprint,track"},"leisure/slipway":{"name":"Slipway","terms":"boat launch,boat ramp"},"leisure/sports_centre":{"name":"Sports Center / Complex","terms":""},"leisure/sports_centre/swimming":{"name":"Swimming Pool Facility","terms":"dive,water"},"leisure/stadium":{"name":"Stadium","terms":""},"leisure/swimming_pool":{"name":"Swimming Pool","terms":"dive,water"},"leisure/track":{"name":"Racetrack (Non-Motorsport)","terms":"cycle,dog,greyhound,horse,race*,track"},"leisure/water_park":{"name":"Water Park","terms":"swim,pool,dive"},"line":{"name":"Line","terms":""},"man_made":{"name":"Man Made","terms":""},"man_made/embankment":{"name":"Embankment","terms":""},"man_made/adit":{"name":"Adit","terms":"entrance,underground,mine,cave"},"man_made/breakwater":{"name":"Breakwater","terms":""},"man_made/bridge":{"name":"Bridge","terms":""},"man_made/chimney":{"name":"Chimney","terms":""},"man_made/cutline":{"name":"Cut line","terms":""},"man_made/flagpole":{"name":"Flagpole","terms":""},"man_made/gasometer":{"name":"Gasometer","terms":"gas holder"},"man_made/groyne":{"name":"Groyne","terms":""},"man_made/lighthouse":{"name":"Lighthouse","terms":""},"man_made/mast":{"name":"Mast","terms":"antenna,broadcast tower,cell phone tower,cell tower,communication mast,communication tower,guyed tower,mobile phone tower,radio mast,radio tower,television tower,transmission mast,transmission tower,tv tower"},"man_made/observation":{"name":"Observation Tower","terms":"lookout tower,fire tower"},"man_made/petroleum_well":{"name":"Oil Well","terms":"drilling rig,oil derrick,oil drill,oil horse,oil rig,oil pump,petroleum well,pumpjack"},"man_made/pier":{"name":"Pier","terms":"dock"},"man_made/pipeline":{"name":"Pipeline","terms":""},"man_made/pumping_station":{"name":"Pumping Station","terms":""},"man_made/silo":{"name":"Silo","terms":"grain,corn,wheat"},"man_made/storage_tank":{"name":"Storage Tank","terms":"water,oil,gas,petrol"},"man_made/surveillance_camera":{"name":"Surveillance Camera","terms":"anpr,alpr,camera,car plate recognition,cctv,guard,license plate recognition,monitoring,number plate recognition,security,video,webcam"},"man_made/surveillance":{"name":"Surveillance","terms":"anpr,alpr,camera,car plate recognition,cctv,guard,license plate recognition,monitoring,number plate recognition,security,video,webcam"},"man_made/survey_point":{"name":"Survey Point","terms":""},"man_made/tower":{"name":"Tower","terms":""},"man_made/wastewater_plant":{"name":"Wastewater Plant","terms":"sewage*,water treatment plant,reclamation plant"},"man_made/water_tower":{"name":"Water Tower","terms":""},"man_made/water_well":{"name":"Water Well","terms":""},"man_made/water_works":{"name":"Water Works","terms":""},"man_made/watermill":{"name":"Watermill","terms":"water,wheel,mill"},"man_made/windmill":{"name":"Windmill","terms":"wind,wheel,mill"},"man_made/works":{"name":"Factory","terms":"assembly,build,brewery,car,plant,plastic,processing,manufacture,refinery"},"manhole":{"name":"Manhole","terms":"cover,hole,sewer,sewage,telecom"},"manhole/drain":{"name":"Storm Drain","terms":"cover,drain,hole,rain,sewer,sewage,storm"},"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":"hydro,solar,turbine,wind"},"power/generator/source_nuclear":{"name":"Nuclear Reactor","terms":"fission,generator,nuclear,nuke,reactor"},"power/generator/source_wind":{"name":"Wind Turbine","terms":"generator,turbine,windmill,wind"},"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":"metro,transit"},"railway/subway":{"name":"Subway","terms":"metro,transit"},"railway/tram_stop":{"name":"Tram Stop","terms":"light rail,streetcar,tram,trolley"},"railway/tram":{"name":"Tram","terms":"light rail,streetcar,tram,trolley"},"relation":{"name":"Relation","terms":""},"route/ferry":{"name":"Ferry Route","terms":""},"shop":{"name":"Shop","terms":""},"shop/fishmonger":{"name":"Fishmonger","terms":""},"shop/vacant":{"name":"Vacant Shop","terms":""},"shop/alcohol":{"name":"Liquor Store","terms":"alcohol,beer,booze,wine"},"shop/anime":{"name":"Anime Shop","terms":"manga,japan,cosplay,figurine,dakimakura"},"shop/antiques":{"name":"Antiques Shop","terms":""},"shop/appliance":{"name":"Appliance Store","terms":"air conditioner,appliance,dishwasher,dryer,freezer,fridge,grill,kitchen,oven,refrigerator,stove,washer,washing machine"},"shop/art":{"name":"Art Store","terms":"art*,exhibit*,gallery"},"shop/baby_goods":{"name":"Baby Goods Store","terms":""},"shop/bag":{"name":"Bag/Luggage Store","terms":"handbag,purse"},"shop/bakery":{"name":"Bakery","terms":""},"shop/bathroom_furnishing":{"name":"Bathroom Furnishing Store","terms":""},"shop/beauty":{"name":"Beauty Shop","terms":"spa,salon,tanning"},"shop/beauty/nails":{"name":"Nail Salon","terms":"manicure,pedicure"},"shop/beauty/tanning":{"name":"Tanning Salon","terms":""},"shop/bed":{"name":"Bedding/Mattress Store","terms":""},"shop/beverages":{"name":"Beverage Store","terms":""},"shop/bicycle":{"name":"Bicycle Shop","terms":"bike,repair"},"shop/bookmaker":{"name":"Bookmaker","terms":"betting"},"shop/books":{"name":"Book Store","terms":""},"shop/boutique":{"name":"Boutique","terms":""},"shop/butcher":{"name":"Butcher","terms":"meat"},"shop/candles":{"name":"Candle Shop","terms":""},"shop/car_parts":{"name":"Car Parts Store","terms":"auto"},"shop/car_repair":{"name":"Car Repair Shop","terms":"auto,garage,service"},"shop/car":{"name":"Car Dealership","terms":"auto"},"shop/carpet":{"name":"Carpet Store","terms":"rug"},"shop/charity":{"name":"Charity Store","terms":"thrift,op shop,nonprofit"},"shop/cheese":{"name":"Cheese Store","terms":""},"shop/chemist":{"name":"Drugstore","terms":"med*,drug*,gift"},"shop/chocolate":{"name":"Chocolate Store","terms":""},"shop/clothes":{"name":"Clothing Store","terms":""},"shop/coffee":{"name":"Coffee Store","terms":""},"shop/computer":{"name":"Computer Store","terms":""},"shop/confectionery":{"name":"Candy Store","terms":""},"shop/convenience":{"name":"Convenience Store","terms":""},"shop/copyshop":{"name":"Copy Store","terms":""},"shop/cosmetics":{"name":"Cosmetics Store","terms":""},"shop/craft":{"name":"Arts and Crafts Store","terms":"art*,paint*,frame"},"shop/curtain":{"name":"Curtain Store","terms":"drape*,window"},"shop/dairy":{"name":"Dairy Store","terms":"milk,egg,cheese"},"shop/deli":{"name":"Deli","terms":"lunch,meat,sandwich"},"shop/department_store":{"name":"Department Store","terms":""},"shop/doityourself":{"name":"DIY Store","terms":""},"shop/dry_cleaning":{"name":"Dry Cleaner","terms":""},"shop/e-cigarette":{"name":"E-Cigarette Shop","terms":"electronic,vapor"},"shop/electronics":{"name":"Electronics Store","terms":"appliance,audio,blueray,camera,computer,dvd,home theater,radio,speaker,tv,video"},"shop/erotic":{"name":"Erotic Store","terms":"sex,porn"},"shop/fabric":{"name":"Fabric Store","terms":"sew"},"shop/farm":{"name":"Produce Stand","terms":"farm shop,farm stand"},"shop/fashion":{"name":"Fashion Store","terms":""},"shop/florist":{"name":"Florist","terms":"flower"},"shop/frame":{"name":"Framing Shop","terms":"art*,paint*,photo*,frame"},"shop/funeral_directors":{"name":"Funeral Home","terms":"undertaker,memorial home"},"shop/furnace":{"name":"Furnace Store","terms":"oven,stove"},"shop/furniture":{"name":"Furniture Store","terms":"chair,sofa,table"},"shop/garden_centre":{"name":"Garden Center","terms":"landscape,mulch,shrub,tree"},"shop/gas":{"name":"Bottled Gas Shop","terms":"cng,lpg,natural gas,propane,refill,tank"},"shop/gift":{"name":"Gift Shop","terms":"souvenir"},"shop/greengrocer":{"name":"Greengrocer","terms":"fruit,vegetable"},"shop/hairdresser":{"name":"Hairdresser","terms":"barber"},"shop/hardware":{"name":"Hardware Store","terms":""},"shop/hearing_aids":{"name":"Hearing Aids Store","terms":""},"shop/herbalist":{"name":"Herbalist","terms":""},"shop/hifi":{"name":"Hifi Store","terms":"stereo,video"},"shop/houseware":{"name":"Houseware Store","terms":"home,household"},"shop/interior_decoration":{"name":"Interior Decoration Store","terms":""},"shop/jewelry":{"name":"Jeweler","terms":"diamond,gem,ring"},"shop/kiosk":{"name":"News Kiosk","terms":""},"shop/kitchen":{"name":"Kitchen Design Store","terms":""},"shop/laundry":{"name":"Laundry","terms":""},"shop/leather":{"name":"Leather Store","terms":""},"shop/locksmith":{"name":"Locksmith","terms":"key,lockpick"},"shop/lottery":{"name":"Lottery Shop","terms":""},"shop/mall":{"name":"Mall","terms":"shopping"},"shop/massage":{"name":"Massage Shop","terms":""},"shop/medical_supply":{"name":"Medical Supply Store","terms":""},"shop/mobile_phone":{"name":"Mobile Phone Store","terms":""},"shop/money_lender":{"name":"Money Lender","terms":""},"shop/motorcycle":{"name":"Motorcycle Dealership","terms":"bike"},"shop/music":{"name":"Music Store","terms":"CD,vinyl"},"shop/musical_instrument":{"name":"Musical Instrument Store","terms":"guitar"},"shop/newsagent":{"name":"Newspaper/Magazine Shop","terms":""},"shop/nutrition_supplements":{"name":"Nutrition Supplements Store","terms":""},"shop/optician":{"name":"Optician","terms":"eye,glasses"},"shop/organic":{"name":"Organic Goods Store","terms":""},"shop/outdoor":{"name":"Outdoors Store","terms":"camping,climbing,hiking"},"shop/paint":{"name":"Paint Store","terms":""},"shop/pastry":{"name":"Pastry Shop","terms":"patisserie,cake shop,cakery"},"shop/pawnbroker":{"name":"Pawn Shop","terms":""},"shop/perfumery":{"name":"Perfume Store","terms":""},"shop/pet":{"name":"Pet Store","terms":"animal,cat,dog,fish,kitten,puppy,reptile"},"shop/photo":{"name":"Photography Store","terms":"camera,film"},"shop/pyrotechnics":{"name":"Fireworks Store","terms":""},"shop/radiotechnics":{"name":"Radio/Electronic Component Store","terms":""},"shop/religion":{"name":"Religious Store","terms":""},"shop/scuba_diving":{"name":"Scuba Diving Shop","terms":""},"shop/seafood":{"name":"Seafood Shop","terms":"fishmonger"},"shop/second_hand":{"name":"Consignment/Thrift Store","terms":"secondhand,second hand,resale,thrift,used"},"shop/shoes":{"name":"Shoe Store","terms":""},"shop/sports":{"name":"Sporting Goods Store","terms":""},"shop/stationery":{"name":"Stationery Store","terms":"card,paper"},"shop/storage_rental":{"name":"Storage Rental","terms":""},"shop/supermarket":{"name":"Supermarket","terms":"grocery,store,shop"},"shop/tailor":{"name":"Tailor","terms":"clothes,suit"},"shop/tattoo":{"name":"Tattoo Parlor","terms":""},"shop/tea":{"name":"Tea Store","terms":""},"shop/ticket":{"name":"Ticket Seller","terms":""},"shop/tobacco":{"name":"Tobacco Shop","terms":""},"shop/toys":{"name":"Toy Store","terms":""},"shop/travel_agency":{"name":"Travel Agency","terms":""},"shop/tyres":{"name":"Tire Store","terms":""},"shop/vacuum_cleaner":{"name":"Vacuum Cleaner Store","terms":""},"shop/variety_store":{"name":"Variety Store","terms":""},"shop/video_games":{"name":"Video Game Store","terms":""},"shop/video":{"name":"Video Store","terms":"DVD"},"shop/watches":{"name":"Watches Shop","terms":""},"shop/water_sports":{"name":"Watersport/Swim Shop","terms":""},"shop/weapons":{"name":"Weapon Shop","terms":"ammo,gun,knife,knives"},"shop/window_blind":{"name":"Window Blind Store","terms":""},"shop/wine":{"name":"Wine Shop","terms":""},"tourism":{"name":"Tourism","terms":""},"tourism/alpine_hut":{"name":"Alpine Hut","terms":""},"tourism/apartment":{"name":"Guest Apartment / Condo","terms":""},"tourism/aquarium":{"name":"Aquarium","terms":"fish,sea,water"},"tourism/artwork":{"name":"Artwork","terms":"mural,sculpture,statue"},"tourism/attraction":{"name":"Tourist Attraction","terms":""},"tourism/camp_site":{"name":"Campground","terms":"tent,rv"},"tourism/caravan_site":{"name":"RV Park","terms":"Motor Home,Camper"},"tourism/chalet":{"name":"Chalet","terms":""},"tourism/gallery":{"name":"Art Gallery","terms":"art*,exhibit*,paint*,photo*,sculpt*"},"tourism/guest_house":{"name":"Guest House","terms":"B&B,Bed and Breakfast"},"tourism/hostel":{"name":"Hostel","terms":""},"tourism/hotel":{"name":"Hotel","terms":""},"tourism/information":{"name":"Information","terms":""},"tourism/information/board":{"name":"Information Board","terms":""},"tourism/information/guidepost":{"name":"Guidepost","terms":""},"tourism/information/map":{"name":"Map","terms":""},"tourism/information/office":{"name":"Tourist Information Office","terms":""},"tourism/motel":{"name":"Motel","terms":""},"tourism/museum":{"name":"Museum","terms":"art*,exhibit*,gallery,foundation,hall,institution,paint*,photo*,sculpt*"},"tourism/picnic_site":{"name":"Picnic Site","terms":"camp"},"tourism/theme_park":{"name":"Theme Park","terms":""},"tourism/viewpoint":{"name":"Viewpoint","terms":""},"tourism/zoo":{"name":"Zoo","terms":"animal"},"traffic_calming":{"name":"Traffic Calming","terms":"bump,hump,slow,speed"},"traffic_calming/bump":{"name":"Speed Bump","terms":"hump,speed,slow"},"traffic_calming/chicane":{"name":"Traffic Chicane","terms":"driveway link,speed,slow"},"traffic_calming/choker":{"name":"Traffic Choker","terms":"speed,slow"},"traffic_calming/cushion":{"name":"Speed Cushion","terms":"bump,hump,speed,slow"},"traffic_calming/dip":{"name":"Dip","terms":"speed,slow"},"traffic_calming/hump":{"name":"Speed Hump","terms":"bump,speed,slow"},"traffic_calming/island":{"name":"Traffic Island","terms":"circle,roundabout,slow"},"traffic_calming/rumble_strip":{"name":"Rumble Strip","terms":"audible lines,sleeper lines,growlers"},"traffic_calming/table":{"name":"Raised Pedestrian Crossing","terms":"flat top,hump,speed,slow"},"type/multipolygon":{"name":"Multipolygon","terms":""},"type/boundary":{"name":"Boundary","terms":""},"type/boundary/administrative":{"name":"Administrative Boundary","terms":""},"type/restriction":{"name":"Restriction","terms":""},"type/restriction/no_left_turn":{"name":"No Left Turn","terms":""},"type/restriction/no_right_turn":{"name":"No Right Turn","terms":""},"type/restriction/no_straight_on":{"name":"No Straight On","terms":""},"type/restriction/no_u_turn":{"name":"No U-turn","terms":""},"type/restriction/only_left_turn":{"name":"Left Turn Only","terms":""},"type/restriction/only_right_turn":{"name":"Right Turn Only","terms":""},"type/restriction/only_straight_on":{"name":"No Turns","terms":""},"type/route_master":{"name":"Route Master","terms":""},"type/route":{"name":"Route","terms":""},"type/route/bicycle":{"name":"Cycle Route","terms":""},"type/route/bus":{"name":"Bus Route","terms":""},"type/route/detour":{"name":"Detour Route","terms":""},"type/route/ferry":{"name":"Ferry Route","terms":""},"type/route/foot":{"name":"Foot Route","terms":""},"type/route/hiking":{"name":"Hiking Route","terms":""},"type/route/horse":{"name":"Riding Route","terms":""},"type/route/pipeline":{"name":"Pipeline Route","terms":""},"type/route/power":{"name":"Power Route","terms":""},"type/route/road":{"name":"Road Route","terms":""},"type/route/train":{"name":"Train Route","terms":""},"type/route/tram":{"name":"Tram Route","terms":""},"type/site":{"name":"Site","terms":""},"vertex":{"name":"Other","terms":""},"waterway/boatyard":{"name":"Boatyard","terms":""},"waterway/canal":{"name":"Canal","terms":""},"waterway/dam":{"name":"Dam","terms":""},"waterway/ditch":{"name":"Ditch","terms":""},"waterway/dock":{"name":"Wet Dock / Dry Dock","terms":"boat,ship,vessel,marine"},"waterway/drain":{"name":"Drain","terms":""},"waterway/fuel":{"name":"Marine Fuel Station","terms":"petrol,gas,diesel,boat"},"waterway/river":{"name":"River","terms":"beck,branch,brook,course,creek,estuary,rill,rivulet,run,runnel,stream,tributary,watercourse"},"waterway/riverbank":{"name":"Riverbank","terms":""},"waterway/sanitary_dump_station":{"name":"Marine Toilet Disposal","terms":"Boat,Watercraft,Sanitary,Dump Station,Pumpout,Pump out,Elsan,CDP,CTDP,Chemical Toilet"},"waterway/stream":{"name":"Stream","terms":"beck,branch,brook,burn,course,creek,current,drift,flood,flow,freshet,race,rill,rindle,rivulet,run,runnel,rush,spate,spritz,surge,tide,torrent,tributary,watercourse"},"waterway/water_point":{"name":"Marine Drinking Water","terms":""},"waterway/waterfall":{"name":"Waterfall","terms":"fall"},"waterway/weir":{"name":"Weir","terms":""}}},"imagery":{"Bing":{"description":"Satellite and aerial imagery.","name":"Bing aerial imagery"},"DigitalGlobe-Premium":{"attribution":{"text":"Terms & Feedback"},"description":"Premium DigitalGlobe satellite imagery.","name":"DigitalGlobe Premium Imagery"},"DigitalGlobe-Standard":{"attribution":{"text":"Terms & Feedback"},"description":"Standard DigitalGlobe satellite imagery.","name":"DigitalGlobe Standard Imagery"},"MAPNIK":{"attribution":{"text":"© OpenStreetMap contributors, CC-BY-SA"},"description":"The default OpenStreetMap layer.","name":"OpenStreetMap (Standard)"},"Mapbox":{"attribution":{"text":"Terms & Feedback"},"description":"Satellite and aerial imagery.","name":"Mapbox Satellite"},"New_and_Misaligned_TIGER_Roads-2013":{"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","name":"New & Misaligned TIGER Roads"},"OSM_Inspector-Addresses":{"attribution":{"text":"© Geofabrik GmbH, OpenStreetMap contributors, CC-BY-SA"},"name":"OSM Inspector: Addresses"},"OSM_Inspector-Geometry":{"attribution":{"text":"© Geofabrik GmbH, OpenStreetMap contributors, CC-BY-SA"},"name":"OSM Inspector: Geometry"},"OSM_Inspector-Highways":{"attribution":{"text":"© Geofabrik GmbH, OpenStreetMap contributors, CC-BY-SA"},"name":"OSM Inspector: Highways"},"OSM_Inspector-Multipolygon":{"attribution":{"text":"© Geofabrik GmbH, OpenStreetMap contributors, CC-BY-SA"},"name":"OSM Inspector: Area"},"OSM_Inspector-Places":{"attribution":{"text":"© Geofabrik GmbH, OpenStreetMap contributors, CC-BY-SA"},"name":"OSM Inspector: Places"},"OSM_Inspector-Routing":{"attribution":{"text":"© Geofabrik GmbH, OpenStreetMap contributors, CC-BY-SA"},"name":"OSM Inspector: Routing"},"OSM_Inspector-Tagging":{"attribution":{"text":"© Geofabrik GmbH, OpenStreetMap contributors, CC-BY-SA"},"name":"OSM Inspector: Tagging"},"Waymarked_Trails-Cycling":{"attribution":{"text":"© Sarah Hoffmann, CC by-SA 3.0, map data OpenStreetMap contributors, ODbL 1.0"},"name":"Waymarked Trails: Cycling"},"Waymarked_Trails-Hiking":{"attribution":{"text":"© Sarah Hoffmann, CC by-SA 3.0, map data OpenStreetMap contributors, ODbL 1.0"},"name":"Waymarked Trails: Hiking"},"Waymarked_Trails-MTB":{"attribution":{"text":"© Sarah Hoffmann, CC by-SA 3.0, map data OpenStreetMap contributors, ODbL 1.0"},"name":"Waymarked Trails: MTB"},"Waymarked_Trails-Skating":{"attribution":{"text":"© Sarah Hoffmann, CC by-SA 3.0, map data OpenStreetMap contributors, ODbL 1.0"},"name":"Waymarked Trails: Skating"},"Waymarked_Trails-Winter_Sports":{"attribution":{"text":"© Michael Spreng, CC by-SA 3.0, map data OpenStreetMap contributors, ODbL 1.0"},"name":"Waymarked Trails: Winter Sports"},"basemap.at":{"attribution":{"text":"basemap.at"},"description":"Basemap of Austria, based on goverment data.","name":"basemap.at"},"basemap.at-orthofoto":{"attribution":{"text":"basemap.at"},"description":"Orthofoto layer provided by basemap.at. \"Successor\" of geoimage.at imagery.","name":"basemap.at Orthofoto"},"hike_n_bike":{"attribution":{"text":"© OpenStreetMap contributors"},"name":"Hike & Bike"},"mapbox_locator_overlay":{"attribution":{"text":"Terms & Feedback"},"description":"Shows major features to help orient you.","name":"Locator Overlay"},"openpt_map":{"attribution":{"text":"© OpenStreetMap contributors, CC-BY-SA"},"name":"OpenPT Map (overlay)"},"osm-gps":{"attribution":{"text":"© OpenStreetMap contributors"},"description":"Public GPS traces uploaded to OpenStreetMap.","name":"OpenStreetMap GPS traces"},"osm-mapnik-black_and_white":{"attribution":{"text":"© OpenStreetMap contributors, CC-BY-SA"},"name":"OpenStreetMap (Standard Black & White)"},"osm-mapnik-german_style":{"attribution":{"text":"© OpenStreetMap contributors, CC-BY-SA"},"name":"OpenStreetMap (German Style)"},"qa_no_address":{"attribution":{"text":"Simon Poole, Data ©OpenStreetMap contributors"},"name":"QA No Address"},"skobbler":{"attribution":{"text":"© Tiles: skobbler Map data: OpenStreetMap contributors"},"name":"skobbler"},"stamen-terrain-background":{"attribution":{"text":"Map tiles by Stamen Design, under CC BY 3.0"},"name":"Stamen Terrain"},"tf-cycle":{"attribution":{"text":"Maps © Thunderforest, Data © OpenStreetMap contributors"},"name":"Thunderforest OpenCycleMap"},"tf-landscape":{"attribution":{"text":"Maps © Thunderforest, Data © OpenStreetMap contributors"},"name":"Thunderforest Landscape"}}};
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}","endDate":"2013-06-01T00:00:00.000Z","startDate":"2013-05-01T00:00:00.000Z","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]]],"description":"Public domain aerial imagery taken in May/June 2013 from San Juan County, WA. Resolution is 9 inch."},{"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}","endDate":"2016-07-01T00:00:00.000Z","startDate":"2016-05-01T00:00:00.000Z","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,"description":"Public domain aerial imagery taken in May, June, and July from San Juan County, WA. Resolution is 6 inch countywide."},{"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","endDate":"2010-07-20T00:00:00.000Z","startDate":"2013-07-19T00:00:00.000Z","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","icon":"https://www.geoportail.lu/static/img/lion.png"},{"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","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","description":"Basemap of Austria, based on goverment data.","icon":"https://www.basemap.at/images/logo_basemap.jpg"},{"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","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,"description":"Orthofoto layer provided by basemap.at. \"Successor\" of geoimage.at imagery.","icon":"https://www.basemap.at/images/logo_basemap.jpg"},{"id":"bavaria-DOP80","name":"Bavaria DOP 80cm","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/BAYERNDOP80/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[0,18],"polygon":[[[10.1235886,50.568462],[10.1428576,50.5507804],[10.2028056,50.5574195],[10.2520485,50.5179575],[10.3269835,50.4934473],[10.4104825,50.4184762],[10.6031724,50.3310874],[10.6224414,50.2271041],[10.7252093,50.2106649],[10.7294913,50.2476451],[10.8515282,50.2435376],[10.7187863,50.3201525],[10.7123633,50.3652428],[10.8558102,50.3966441],[10.9371682,50.3966441],[10.9906932,50.3666085],[11.1277171,50.3666085],[11.1791011,50.3133169],[11.1619731,50.294172],[11.24119,50.2928042],[11.249754,50.3734364],[11.24119,50.479825],[11.358945,50.5234025],[11.4381619,50.5097889],[11.4424439,50.4893611],[11.425316,50.4771001],[11.425316,50.4416618],[11.4895459,50.4225686],[11.4916869,50.3980089],[11.5195199,50.3980089],[11.5259429,50.3761673],[11.5987369,50.4034677],[11.6372748,50.3884544],[11.7935678,50.4212045],[11.8363877,50.3925494],[11.9220277,50.4280246],[11.9862577,50.3870894],[11.9841167,50.3570478],[12.0483466,50.3310874],[12.0933076,50.3297207],[12.1297046,50.2982751],[12.1404096,50.2722826],[12.1061536,50.255859],[12.1125766,50.2353216],[12.1489736,50.236691],[12.1982166,50.2010728],[12.2239086,50.1640565],[12.2046396,50.1434795],[12.2067806,50.1077916],[12.2431775,50.0995522],[12.2774335,50.0720772],[12.4936744,49.985428],[12.4979564,49.9413559],[12.5557634,49.9220616],[12.5493404,49.8682726],[12.4808284,49.7881677],[12.4101755,49.7577484],[12.4615594,49.7065456],[12.5471994,49.6802313],[12.5878784,49.552613],[12.6542493,49.534553],[12.6628133,49.4330153],[12.7527353,49.4107323],[12.7976963,49.3466124],[12.9047462,49.3563752],[12.9968092,49.3368477],[13.0546161,49.2754251],[13.1316921,49.2195199],[13.1916401,49.1439475],[13.236601,49.1215335],[13.296549,49.1229347],[13.371484,49.0808823],[13.414304,49.0289687],[13.414304,48.9798112],[13.5791609,48.9699739],[13.6348268,48.9432629],[13.6776468,48.8869823],[13.7375948,48.8926132],[13.7846968,48.8334571],[13.8403627,48.774231],[13.8168118,48.7064584],[13.8446447,48.7008065],[13.8425037,48.6003807],[13.7654278,48.5422972],[13.7525818,48.5040106],[13.6712238,48.5054291],[13.6433908,48.5437146],[13.4571239,48.5508013],[13.4571239,48.4159838],[13.40574,48.3605338],[13.283703,48.2751083],[13.0931541,48.2694081],[12.9582712,48.1909669],[12.8769132,48.1852574],[12.7720043,48.0938188],[12.8640672,48.0136764],[12.8983232,47.9549216],[12.9454252,47.9563555],[12.9968092,47.8846147],[13.0139372,47.834337],[12.9347202,47.7321953],[13.0588981,47.7249947],[13.1188461,47.6385093],[13.0653211,47.5692178],[13.0567571,47.473792],[13.0032322,47.4520801],[12.7677223,47.5504355],[12.7698633,47.6327385],[12.7398893,47.6731207],[12.6670953,47.6702373],[12.5750324,47.621195],[12.4808284,47.6197519],[12.4144575,47.6702373],[12.2431775,47.6774455],[12.2132036,47.6918589],[12.1917936,47.6817699],[12.2132036,47.6659119],[12.2110626,47.603875],[12.1746656,47.5952129],[12.1382686,47.603875],[11.8920537,47.603875],[11.8513747,47.5793285],[11.6394158,47.5822169],[11.5944549,47.5489905],[11.5901729,47.5128508],[11.5173789,47.498388],[11.4403029,47.5041736],[11.395342,47.4752392],[11.427457,47.4448409],[11.346099,47.4433929],[11.279728,47.3955873],[11.2133571,47.3883402],[11.247613,47.4318076],[11.1020251,47.3926886],[10.9650012,47.3897897],[10.9778472,47.4361524],[10.9178992,47.4752392],[10.8707972,47.4752392],[10.8558102,47.4940484],[10.9007712,47.5142969],[10.8729382,47.5359831],[10.8108493,47.5128508],[10.6438513,47.5489905],[10.5946084,47.5547705],[10.5796214,47.5287553],[10.4618664,47.5403192],[10.4661484,47.4839212],[10.4875584,47.4781333],[10.4875584,47.4129762],[10.4597254,47.4028333],[10.4597254,47.375293],[10.4104825,47.3738431],[10.4083415,47.3433862],[10.3205605,47.2867768],[10.2820225,47.2780622],[10.2841635,47.2620819],[10.1471396,47.2620819],[10.1921006,47.3027497],[10.1942416,47.3738431],[10.1664086,47.3738431],[10.1664086,47.3462876],[10.1000376,47.3433862],[10.0614996,47.3636928],[10.0679226,47.4187712],[10.0936146,47.426014],[10.0957556,47.4419449],[9.9780007,47.485368],[9.9565907,47.5273097],[9.8945017,47.5287553],[9.8559637,47.5085124],[9.8174258,47.544655],[9.8217078,47.5764399],[9.7746058,47.5822169],[9.7382088,47.525864],[9.6739788,47.5345376],[9.5840569,47.564884],[9.6397228,47.6053186],[9.7167988,47.603875],[9.8559637,47.6760039],[9.9780007,47.6558179],[10.0293846,47.6817699],[10.1000376,47.6673537],[10.1321526,47.6760039],[10.1428576,47.7019459],[10.0614996,47.7725005],[10.1128836,47.8098988],[10.0829096,47.8530173],[10.1086016,47.9090177],[10.0764866,47.9649577],[10.1300116,48.020837],[10.1342936,48.1066872],[10.1000376,48.1281274],[10.0550766,48.2622821],[9.9694367,48.3676462],[10.0315256,48.4259299],[10.0293846,48.461436],[10.1235886,48.4770509],[10.1535626,48.4514968],[10.2349205,48.5125212],[10.3162785,48.516776],[10.2991505,48.6187835],[10.2456255,48.6682961],[10.2734585,48.7064584],[10.3698035,48.6838472],[10.4318924,48.6993935],[10.4511614,48.7276471],[10.4019185,48.7460035],[10.4404564,48.8489571],[10.4340334,48.9587289],[10.3376885,49.0205451],[10.2499075,49.0359872],[10.2499075,49.0738701],[10.2006646,49.1033147],[10.2520485,49.1327418],[10.1235886,49.1971401],[10.1193066,49.2628519],[10.1514216,49.2893915],[10.1043196,49.3452175],[10.1407166,49.3940134],[10.1086016,49.445545],[10.1107426,49.5053651],[10.0722046,49.5331635],[10.0165387,49.4761598],[9.9266167,49.478942],[9.9244757,49.5567797],[9.8987837,49.5817727],[9.8559637,49.5387213],[9.8067208,49.5567797],[9.8666687,49.6067529],[9.8538227,49.6441991],[9.8174258,49.6608327],[9.8345537,49.6899277],[9.7960158,49.7203895],[9.7574778,49.7079302],[9.7403498,49.6857723],[9.7060938,49.7162368],[9.6782608,49.7162368],[9.6825428,49.6885426],[9.6204539,49.6913127],[9.6461458,49.78955],[9.5583649,49.7743431],[9.5712109,49.7356133],[9.5069809,49.7522156],[9.4919939,49.7798735],[9.4684429,49.7605146],[9.425623,49.7784909],[9.404213,49.7646636],[9.33356,49.770195],[9.329278,49.7342295],[9.408495,49.725926],[9.427764,49.6982374],[9.414918,49.6441991],[9.380662,49.6386533],[9.359252,49.6497443],[9.339983,49.6372668],[9.31215,49.648358],[9.277894,49.626173],[9.284317,49.6081403],[9.241497,49.5748315],[9.0980501,49.5720547],[9.0659351,49.6081403],[9.1001911,49.6511305],[9.0916271,49.6926978],[9.1301651,49.7120837],[9.1387291,49.7425316],[9.1087551,49.7563653],[9.1365881,49.7909322],[9.1001911,49.78955],[9.0723581,49.8282367],[9.0359611,49.8351418],[9.0166922,50.0267091],[8.9631672,50.0308352],[8.9567442,50.0597083],[9.0017052,50.0707031],[9.0209742,50.1105378],[9.1216011,50.1228936],[9.1558571,50.1132838],[9.1965361,50.1187753],[9.1858311,50.1352462],[9.235074,50.1475956],[9.37638,50.1270115],[9.408495,50.0816953],[9.5219679,50.095432],[9.5048399,50.1421073],[9.5326729,50.1640565],[9.4898529,50.1695422],[9.4941349,50.2435376],[9.6140309,50.221625],[9.6654148,50.2353216],[9.6354408,50.2490142],[9.6675558,50.2722826],[9.7424908,50.3092151],[9.7296448,50.3584137],[9.7703238,50.4293885],[9.8688097,50.4007384],[9.9180527,50.4089259],[10.0358076,50.479825],[10.0379486,50.5111504],[10.1235886,50.568462]]]},{"id":"GRB","name":"Belgium AGIV GRB Flanders","type":"tms","template":"http://tile.informatievlaanderen.be/ws/raadpleegdiensten/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=grb_bsk&STYLE=&FORMAT=image/png&tileMatrixSet=GoogleMapsVL&tileMatrix={zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,21],"polygon":[[[2.522393220658428,51.101723961331],[3.1260610915867457,51.34117672029327],[3.174929443042849,51.382459567439525],[3.3761520666856217,51.38784154353026],[3.410647373595811,51.33040116175589],[3.4020235468682634,51.28547573497245],[3.4911364230529203,51.256700377228974],[3.4825125963253734,51.30345118353617],[3.5773746903283947,51.323216048914524],[3.813092620881357,51.27288873325703],[3.8217164476089045,51.236906864834886],[3.9309515861578386,51.236906864834886],[4.054559769252684,51.27468708752057],[4.20116482362099,51.35194974615148],[4.169544125619984,51.38066543475199],[4.342020660170932,51.395016527087456],[4.3650175314443915,51.46491366130351],[4.5374940659953396,51.50071687469512],[4.571989372905529,51.479238319799464],[4.560490937268798,51.44879304380801],[4.638105377816725,51.45058450468522],[4.750215125274841,51.5239738914927],[4.8364533925503155,51.507874144493115],[5.080795149830825,51.49892738159079],[5.135412719105292,51.447001512638565],[5.106666630013469,51.391429175957505],[5.264770120018504,51.31782647548482],[5.264770120018504,51.28727359653538],[5.4085005654776275,51.292666758936925],[5.486115006025553,51.325012432665545],[5.5809771000285755,51.28367780302667],[5.583851708937758,51.23510703218069],[5.767826679125435,51.20449910348059],[5.8770618176743685,51.161253258857485],[5.704585283123422,50.80292546633848],[5.905807906766195,50.7865720955422],[5.9374286047672005,50.732019528192964],[5.902933297857012,50.70107817444857],[5.8138204216723555,50.69379488717487],[5.615472406938765,50.761122144578216],[5.500488050571466,50.71200098472672],[5.204403332925673,50.70289881954383],[5.164158808197117,50.67558172042608],[5.037676016193088,50.70107817444857],[4.988807664736986,50.750210783384084],[4.916942442007425,50.72656077355532],[4.790459650003396,50.766576871275696],[4.681224511454462,50.77021300246129],[4.6697260758177315,50.73565834458533],[4.287403090896464,50.67922491935501],[3.91082932379356,50.677403355240585],[3.718230526878334,50.752029520237265],[3.6549891308763196,50.71200098472672],[3.5342555566906557,50.710180693059606],[3.514133294326379,50.741116039142966],[3.45664111614273,50.74384464791457],[3.373277457776438,50.69561581502901],[3.310036061774423,50.70745012302645],[3.2899137994101473,50.7365680045137],[3.1648683118607086,50.742935129324266],[3.1318103094051106,50.77203096207303],[3.080067349039826,50.76021296163662],[2.8745328120332805,50.73929687829333],[2.8960923788521487,50.71109084772858],[2.8745328120332805,50.69561581502901],[2.796918371485353,50.70289881954383],[2.699181668573149,50.80020030189157],[2.6201299235706315,50.79747497850781],[2.5698242676599374,50.85830267681076],[2.5669496587507554,50.923581424665855],[2.6028822701155367,50.94984841176044],[2.549702005295661,50.996006093918574],[2.522393220658428,51.101723961331]]],"terms_text":"GRB Flanders © AGIV","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAABm0lEQVQ4y6WTPUgCYRjHf5oFJVfRUZKVHYFBoBAUFLZE0FBD0NQHRENESzS019LSFNHWx1DQEhGRg0JFREM11FJuLWem4GB5HULdwdkgHprn5LO97/O8v+fj/7y2bDabpQKzFx5S6ntlgE81xvHtclHAbuSNloNT5q/uywP021cAvO4hAPYu5/hI5e6GWpsBCEfjxNSMNUALPvJ7eA3AQPcML3KIzbNhlvdEWmu+6RCcAISiCWtA3fosPztBfrYvAGgX/QCIggdR8DDe6Qbg5E0uAdjyKhhykq+uBeySi9qVCfSAB61HRBQ8RFJpRs6vALiZHMUnNpYO0Ujn+jPkJJnVfbTBNeqfFQB8YqP56H8VJqBKcuHcWsQuuXIOyUX1sN8MnPJKlnOwWS2SIScx0hkcvV3mXUzN0HcSAuBoNMBYZxsADittVXcT/XcPKE/PltqHowkTYLcMkOMoml52+wr9jnIZAJZ8XjYGe0vaUDSdsBxnulsqrUDRdMLReNHg8tYhOAs2M2HdQiSVBqChprpI7/9q5JPYKv3OfxL1n52ATYYBAAAAAElFTkSuQmCC"},{"id":"AGIV","name":"Belgium AGIV Orthophoto Flanders","type":"tms","template":"http://tile.informatievlaanderen.be/ws/raadpleegdiensten/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=omwrgbmrvl&STYLE=&FORMAT=image/png&tileMatrixSet=GoogleMapsVL&tileMatrix={zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,21],"polygon":[[[2.522393220658428,51.101723961331],[3.1260610915867457,51.34117672029327],[3.174929443042849,51.382459567439525],[3.3761520666856217,51.38784154353026],[3.410647373595811,51.33040116175589],[3.4020235468682634,51.28547573497245],[3.4911364230529203,51.256700377228974],[3.4825125963253734,51.30345118353617],[3.5773746903283947,51.323216048914524],[3.813092620881357,51.27288873325703],[3.8217164476089045,51.236906864834886],[3.9309515861578386,51.236906864834886],[4.054559769252684,51.27468708752057],[4.20116482362099,51.35194974615148],[4.169544125619984,51.38066543475199],[4.342020660170932,51.395016527087456],[4.3650175314443915,51.46491366130351],[4.5374940659953396,51.50071687469512],[4.571989372905529,51.479238319799464],[4.560490937268798,51.44879304380801],[4.638105377816725,51.45058450468522],[4.750215125274841,51.5239738914927],[4.8364533925503155,51.507874144493115],[5.080795149830825,51.49892738159079],[5.135412719105292,51.447001512638565],[5.106666630013469,51.391429175957505],[5.264770120018504,51.31782647548482],[5.264770120018504,51.28727359653538],[5.4085005654776275,51.292666758936925],[5.486115006025553,51.325012432665545],[5.5809771000285755,51.28367780302667],[5.583851708937758,51.23510703218069],[5.767826679125435,51.20449910348059],[5.8770618176743685,51.161253258857485],[5.704585283123422,50.80292546633848],[5.905807906766195,50.7865720955422],[5.9374286047672005,50.732019528192964],[5.902933297857012,50.70107817444857],[5.8138204216723555,50.69379488717487],[5.615472406938765,50.761122144578216],[5.500488050571466,50.71200098472672],[5.204403332925673,50.70289881954383],[5.164158808197117,50.67558172042608],[5.037676016193088,50.70107817444857],[4.988807664736986,50.750210783384084],[4.916942442007425,50.72656077355532],[4.790459650003396,50.766576871275696],[4.681224511454462,50.77021300246129],[4.6697260758177315,50.73565834458533],[4.287403090896464,50.67922491935501],[3.91082932379356,50.677403355240585],[3.718230526878334,50.752029520237265],[3.6549891308763196,50.71200098472672],[3.5342555566906557,50.710180693059606],[3.514133294326379,50.741116039142966],[3.45664111614273,50.74384464791457],[3.373277457776438,50.69561581502901],[3.310036061774423,50.70745012302645],[3.2899137994101473,50.7365680045137],[3.1648683118607086,50.742935129324266],[3.1318103094051106,50.77203096207303],[3.080067349039826,50.76021296163662],[2.8745328120332805,50.73929687829333],[2.8960923788521487,50.71109084772858],[2.8745328120332805,50.69561581502901],[2.796918371485353,50.70289881954383],[2.699181668573149,50.80020030189157],[2.6201299235706315,50.79747497850781],[2.5698242676599374,50.85830267681076],[2.5669496587507554,50.923581424665855],[2.6028822701155367,50.94984841176044],[2.549702005295661,50.996006093918574],[2.522393220658428,51.101723961331]]],"terms_text":"Orthophoto Flanders most recent © AGIV","best":true,"icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsSAAALEgHS3X78AAABm0lEQVQ4y6WTPUgCYRjHf5oFJVfRUZKVHYFBoBAUFLZE0FBD0NQHRENESzS019LSFNHWx1DQEhGRg0JFREM11FJuLWem4GB5HULdwdkgHprn5LO97/O8v+fj/7y2bDabpQKzFx5S6ntlgE81xvHtclHAbuSNloNT5q/uywP021cAvO4hAPYu5/hI5e6GWpsBCEfjxNSMNUALPvJ7eA3AQPcML3KIzbNhlvdEWmu+6RCcAISiCWtA3fosPztBfrYvAGgX/QCIggdR8DDe6Qbg5E0uAdjyKhhykq+uBeySi9qVCfSAB61HRBQ8RFJpRs6vALiZHMUnNpYO0Ujn+jPkJJnVfbTBNeqfFQB8YqP56H8VJqBKcuHcWsQuuXIOyUX1sN8MnPJKlnOwWS2SIScx0hkcvV3mXUzN0HcSAuBoNMBYZxsADittVXcT/XcPKE/PltqHowkTYLcMkOMoml52+wr9jnIZAJZ8XjYGe0vaUDSdsBxnulsqrUDRdMLReNHg8tYhOAs2M2HdQiSVBqChprpI7/9q5JPYKv3OfxL1n52ATYYBAAAAAElFTkSuQmCC"},{"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/","scaleExtent":[0,22],"default":true,"description":"Satellite and aerial imagery.","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEkAAABJCAYAAABxcwvcAAAGsklEQVR4Xu2aa2wUZRSG393Z3VKhW0AjQgvhjhRMxVoFSkTSVhJEGqUkECkXQSyoiBCJicYYo+GPiAS1MQREMI2GhGI0UQilJJSCFcWqoDYol0ChEG6lLdu9et5vu01ZWpg0nZ3dMM9msrAz03SenHO+c76tDe+tDMHittijP7C4FUuSDixJOrAk6cCSpANLkg4sSTqwJOnAkqQDS5IOLEk6MEySzWaDLfrDBMUwSaFAgKag2e0JL8sQSYyi+1PcSlSguQmhUFB9bpfPeSSaNEMkiRWsHP8kKua/jFdycjHA3RsI+BH0eeXwKYmUlSjYDNlPEkmbC+ZgYWa2+u81zw3sO/kvvvrzF1SfOYXTVy6pa+Byhd/jHGMiSfAx1YJB+OVI7ZGMggfHYnvhfFQteg2fF8zGQ2kDYfP7kQjJZ5gkplSkaDNWghIxAalNaSmpWPLIBOQNGYWQ3we7/S6W1B5qYA3SbHYlyxcMwCOCEoWYSGoPZTntWkIV7phLSkQsSTqwJOnAkqQD0yWxfMd7CTddkp8dt6x0Dlnx4rWxNF2S25Wkmkp/03U1CLOXirdtFtMkUQSH3mF97sXXsxagKDsHfZJ7IuBpRkiG4JCMM21du8k9lWmSFPLwJ69eRlb/dGx9di6qZa77UoTljhiNlKQeSlbgRrMSZmYDapqkEGuRw4krDdew/qf96rPhfe/DvMxs7JlbjCNLVuH9/GcwZdRY9JSU9DU1hLdZEO7aY7kvZZokhRKlYfeJWpxvbFBzHXcNyDAR9takPOwtWordz7+ENU/PwmODhqqoCu9LeZVoh6SjZnCEmS7JJVFSW3caFSePh6Oj9XkpgML4PnHgYLyZk4vyomIcfnEVVoq8Ef0GwOlwwN/ciIAIMxJzJaE17ewObPqtGiF5cXUjLNaMElrjvhS3WXqJ0KwB6VibPwPHildjR+ECLMvJQ8YD6YamnumSmGJwOlFx4jhqzteJjFBYXCt8eK5wlEeJPMd7KHD6yAx8Om0m9kiEPTl4ONDiUdd2N93/E7sAo4Y1ZrNEE+sL95vai2q7jq/Wok0YYR6/H/17udGvZ4oYDxgSUfEhSaWcHduP1eD3+jq4NEdbb8Q0u1VXGEYNIyqykWfUgBMXktR6JkX4vCzzeVs/w+Lvv8Ef9efUOdWB33T1rYTbgTtd1XXiQpJCokESCRebGrGpuhKPblqHeTtLsfu/f3CZDSUvib4nRsSPJFCCrG7SYDqTkuGVxnFb1V68XfEDmlubyI7qVCyIK0msMSzGPk8T+qWkYt3MItV9p7tT1fm7bixpT2TM4JyWpGkonjAFh15YjhWPT4abM1z0DVGoNsJATJWkpnx+zSTpxGN6xsMon7cUJdMKMbh3X/XwfHUWPzzPIyzZuEcx7iffAdUcBgLwttxARv80lMr0XzZ7EXIGDlHLfuThO1u1mJY875LI+1nGmqMX6lRTakRQmSbpmteDVGkA1zxVgIMLX8WcseNUz0NBFNhR/Yl8E0xYv7jNsvzHMkzasgFH68/C5nSp+7sbUyRx9JgzZhwqFq9Qg6tbVrO2h+8kbfjw1EZ5LdJlf1hVgclbPsGGyj3w+qXTdjCKDAgjmCSJo8fUYaMwTib5yKTfUeQQPnYkush3tUcxYfN6vCERdPrqJTiS71G1zShBxBRJhAU5Mqh2tD3Lh2bEqQFXBLHuPLf9C8wo3YgjZ0/B5nLBLtGjJEff3M0YJimyMnUGC3Jn0cOiHF75bLggHfjru3Yif2sJymoOS1o5VO2J7AbEAsMkce+HIu4kqz3qWjlYlNlllxyuQtbGtfj4QLkq9EwtLl9GplZHdLsklTryEDv+qkF903U4tfD3abdLi/b9Du9n3cnbVoJl35bizNUrsLt6wGbXbvszjMSQPwdUc5b0QGnSEK6eOAXzM7ORqjpnRsHN4wVTK7JRduxiPd7dtwtlf9fA7/NCEznUEuvIicYQSYTRE+Iej9+H7EFDsXpSLgpHZ6pz0bLONTZgQ/V+OSrR2NwIOFzQtPAcFw8YJomovoYNYksL/4GpIzLwzhP5mChdNQnK0r7x10P46OA+1J47CyQlqesZOYb9Ul3AUEkRmE5B1hOvV4IkCYuzxmPGyDH4oLIcB07Ugr+Gw8Vu2fzU6oiYSCKRblmlEP9eku+aQ+1I8vNYLeddodtXt86gAkYKvyKySzRp7JRlICXxLIjETFJ7KIURFY+p1RGmSEo0LEk6sCTpwJKkA0uSDixJOrAk6cCSpANLkg4sSTqwJOnAkqQDS5IOLEk6sCTp4H8Lf75Du1VW7QAAAABJRU5ErkJggiAgICAgICAgICAgICAgICAgICAgICAg"},{"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","endDate":"2013-06-01T00:00:00.000Z","startDate":"2009-01-01T00:00:00.000Z","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","icon":"https://www.geoportail.lu/static/img/lion.png"},{"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","endDate":"2015-01-01T00:00:00.000Z","startDate":"2013-01-01T00:00:00.000Z","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","description":"OpenStreetMap use only. City of Cape Town Aerial ortho-photography of the municipal area. 12cm ground sample distance"},{"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","endDate":"2016-01-01T00:00:00.000Z","startDate":"2015-01-01T00:00:00.000Z","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,"description":"OpenStreetMap use only. City of Cape Town Aerial ortho-photography of the municipal area. 8cm ground sample distance"},{"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","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","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."},{"id":"DigitalGlobe-Premium","name":"DigitalGlobe Premium Imagery","type":"tms","template":"https://{switch:a,b,c}.tiles.mapbox.com/v4/digitalglobe.316c9a2e/{zoom}/{x}/{y}.png?access_token=pk.eyJ1IjoiZGlnaXRhbGdsb2JlIiwiYSI6ImNqM293YnJ5MTAwajIzMnF0bmV4dnV1MW4ifQ.psvzzOez33BOH8xmRiJZWg","scaleExtent":[0,19],"terms_url":"https://wiki.openstreetmap.org/wiki/DigitalGlobe","terms_text":"Terms & Feedback","default":true,"description":"Premium DigitalGlobe satellite imagery.","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMQAAADECAYAAADApo5rAAAgAElEQVR4nMy9a7Bl2VEm9uU5595bt6puvd9dVa1+6k3rgRCSQLKMEDCBAHsEGptAGE948Bgz88Nhw0w4bBzjmBl7HDE2EzM4PGZgAIMNNkYEDKDBIARIAoQeLSG1uumu7uqq7nq/bt1b9738Y6/M/DL32vdWYzw6u6PrnLP2Wrkyc2V+meux95WFd31fAQR6FdRfRYuF7ujvAhSpdQsgUusLSikQ6e6hfkcpKOJ9AIBo/VBaINRfqd8jd17Lf8HqgspCy8pm6K0Km4pNCYUqimQukHrs/mn1kcuoi979QNsGo02rRNVXjTGf3e9ePRoj2bZe/Oz1a+0j41omLR53+vwqyzBqDoR9casohe6WTmrroPiHVKcA3BkgYgMsXN9csXT3itBNN+lKDp37CUSZLahKIPrGp1FGIQYLeaBIdWhSQnGmjIoqXukYYIQr4IoXCfVPl8oQnaEow/qBUoZl0KZhHKoM3QAL3S9WjwGro+P1CtHLn8a7lhMfYgXFxqtU+mx83m0JKpsWGUadSZCFEdNqHGrodk+otoj9dmSQrhK5paKx+5WQkmpLikjqG2agQrwpkmQEQHHe2AZL11c22FJxxepKsahVTCvFBpadjEe4pHtqyPpbqtu5casuitdXPs2r6XNABuOwqB7EeFMDLUX5T9G4Wg3zqarOZd0n91VcBi1HB2gWu4WjqttXMGiZPhlGqKFGUFCKCyAiHpoCDyV0CL1vdat5mGEWQ0o1GTKrDvOLO5wyZ3XFfN946OxCjK7dFa/p5WpYETn0rnQj6b/pm1LreCjkky6Dyizqt8Y3NJDaIIoAUgqhktQ2xXkWgXDvso0M4nX0vusZNeIqx8S/RnCAxpiN1cdd6Qn15WMSy9lQAv8SywKETJkMk5hjVRhns0ioChLUWfLymJu5ZCWTMWQWiFDmKNRAnaT+o4KZaTBzAsCpIJp48Win6Z71UarlKiB4lLDhU4dlRDNnrTWlmMyayypN0xWlj2Te1BOXlV55loGCB1AEnnGqx1XaharTgMd8Xex3Yd2bIgsNIkd3Zlvp+fxS4dZl6I/rNMkwcu+IA9NLkY2MG4Xxqy0FYaA6BZFwxjQRkxgzDHlpzAOuEGOOIqlOjxUx5HUfLarnwEPEMUIym8go0zQIhdsb/Ft/wTlrbsCmnl2CuShlWIYuChVjS5iizduU7443Q0YNYdXZu2o+mKZ7YVmE+CpG3/otfSlQXIZSaXCEmDYZRoZVRf9hB+w80OYTNFg296Q2yrCFd2png671henVT8rVJd9TmpQWmYqkjbU6Go5Z8b4k/LKQa23E5dGvqkDTDzwkB9rcR5WNUjPWSXFzCXqSUjq5t5FB5xYEZZZmaWTLE0udbzEGampDawrk28XLRdOSKoP4yo5Uw7ZITuUC1R8h+BTKYKtMKkkpahQgb4rLjm4QnYGqpxvcWhsaPpvEqNc7dGqELKpFSih4IspCRkT2ZVZH1IhIpVBkMqJdiFXa6mxhibhEgCqmJ5gzMYqXGgVsUqd9WB4pKFJCVGFJTIaqVNVZUwYwcKH+Fr8tcOmMp84xi8lF4FV1qfM+BzafT6LWs/FnHmiQOHXuutE2KoMvVkyTDKMSDN4N33cB1IPcpW0gCQn4N4qia/XsoqHKL7M581oPaW4c7mgWlUqxfsycKFTHeYaVOu8WSqSmZVrbhikglcGOMSz24askhfrs2nB+avMY0g3zWSyOaAPPi/uxkgyFFV89t6gMjmqdsYlYWqxjY3pQjy/eq42H9ekg5cjqJQrVtjonJcmPYEM2J5syGUYRo/qmFASAV+N1cSgSFL4PsrPCTcElTFZv6GpXCDpmbtFhlIYqMfCMzoEUDTxgEYxBEUNqyiaOOEazGMq7IzJzTK/v0DbxE6mG4sut+VI0DMg6IIONiVYW3aPxSMLqdYMszrJryhkm3hQ9LdoTYLJh6Vexwff83xYTGFegwDBdMozisPiASs9SYzWhQVPyERWJxwaDlnblcsDnC7nfZI0c/qIRuw8VQ66WECHOOF3h+s4k79h0BbTsB5UzqjnL7OimDFbdpVUM5mBIhhYIUG91jNjJ8yyk2DiE4RbltY+ongsGwRAm10a+OOFk5NMqwygyuY0TmIwlerkEetYDCxrNqLImbQQw9Gv3Hipq2NXvITwCKGqw3LqDXRRDsk4IM2jaLbfAbJM6Rxb3Tv9lfIU7ceIehyajq0vOSdiQDApMEXQKdFM0c6a0HECkjkMySbMXDvV8n1d6SC8+cTK9NuNgBbEyhTKMAAR0yrt5bOh+fqREaIeGP0Vm6Q94ECcJV0os5VyzytIJ5hl//xSU/6tteMXfB6nUsOwrRVJ14ImMt2N9eE+KVjqgJEN1Nkc1501qOqD27BtuQm2K67UgGlWSgcvVSHgu6I7E+XgloTNKINSzjnuLJUzH2WmOMKcKTRkqSEyhDJPKghOtlX0y7MR0ct1tu9OGCC8poMTJqtIA7ECf1hfycFUSlBNykpBiwI1KlIdKz42sJnSlqkngxk8TNRRXjq4C2dyuis9Xgdkv2NhNbwWkbFqxA+lSvF8bDLYLEK/meEMyIPZJ48TpikCoHf2GL5Z0KYeYg3fD6vf4CnagSGv5ry5FU59hMk1gS4qdFhkmmiJ4B13rEoh42NKczp0BPriiNWB1IWREDSYy/dI1NCq+XOdKcxRxLWuZGxn3VZXFDieaNhVXoonEjuIDqW3jwIRRNd2oUUBTA9aMpD6MHsU06q+r05ehN80Lk7ioK0/FGJ2ZHnenoMjjg6BzIZ2bBnjcuD7zZW3b0eWrLcOo1I51EIq4Y5TCDWH/x3CoaFaoAoECexYZta1G8ESp1ChSnBaZMBSS2U+L1SeH5rbkqFFvDWcoZJwqOzm+NstoZgfPDNW5K4kIWmnyGR2PBLX/kvodkqHE76IRmnL5YCwl9uX0qQ316X0orOvvalwl0Tb5uu/OB3oOzuM0TTJMzJDrgHW8q3cxQXY8CUKyxxeUcFjPxjVHhhbipggTCEgXxzR6ZMTkf912I6VSFcHHVTzb0xUjR6EYJt1xWmkjy6e5a754taSjI2ZF8QiN1yWw68sgPAg+dlL54fSMQ2Bh/iTYh6vcEIpQXulqDKzMBTWpjJnxMA5VR0L1p0SGUVjXr0ZJm8gKvh1fZNwaGbRO1IdE5uBe3ZtwgYRtas/BQFR1hOjR6xEmyZkOO5A5jRq4Cql1FdmpXx8TdT93Q04PRPlKl9HT9Eg6hMoRx/pv6KKX+lX5ewsTia9sK1wQ+lJ65rwNGRRxVX5C8yBDQwdBNp0fTZEMI5+EOsfOrA5AqeWOZiV80vhz7s36qRZVQA4n1huCYyK3C/rkc3UdTa5j6V9r74F0o6mWsiyqwNin7266VzqPHDqJrvhCxaCfD5T3mjRAtvCXCmIZg3oT72wYLcsDbPyCEWZeqzUWBSIzAGfE7K3Rl+tNpk6GkU4EAfXQevCKiOlqfqE1ehWMHSmuDFX9FAqKhdA2y6TGWb3bEKCzL6vTob/fK+m3nXy1eVB0MQdyGgE9MUmIzwos6bvzTu21TOrxNfOHfqQyPgY81lPVTqghGdhYfKmbeVZhQYPQl6krCK1DX7pnEOYEKqNUYpryhlUdIXouT9z0nS4ZRqUaQuibBSNezMq1I3o8zQzMmGX0zIwkQzUjU8VGYYLnp/xMuB/Wv02WJbZlhWnqh9SWUsJOLHcudlTSq7djnjhFrPcTplg9k0sSbcg2MqheiKSlLamepEmnokkYJ74dx9ZWdUrdrymBUlsfPQajjUyjDCPPodnAkbxYx6pGEsVSRgcgGD0vKVrHAlrGdJwtBou8LR8PSjgjOnFFdR4x46WmVR/eXidofOSsOMlqs+ogQn11ii1Eu1iY8s/urJOOJaVt6lyVX2G+jF4ylDTRHpTBQ4mnGyZ/to40nhV4er6pdAmEijpy/S2apjqxRneJttlmNvLpkmGkDGjeTOAXPiv29dmixE/YWC3C6OS0sxZFWkZNLevSbw6vsO9k2jBjJmczUOI0g0jYRDilN0pSKq8qktLU1a9uIsby1whEOpGKgJL5B3yiXWhlSu/RDwcEFd3ptGTwianSIR6pbdz3MYoISQrpP0d0j4wlTn5LvMdAp+mvH8UGRcw4vtMiw0jqAEk1om7JVIeluoE2AJ1R4vFmcOPwXu8xoheNHooCInasVxT1a8QIKzcmoLj1JxTwaEVr/6QY0jvpz4TrnBLFxoAn1CYD1K4L0Sr0DEXplmNpYqf9AtJ41qLmtpoOEK8UfJsyFK5Ao2uRjuVXsGJoSemnRd00fnEJXaJRMqrniybL4b6O+xTKMPKQxSZvFkffNa0q4GdfC+gTBNrFBzEwD0UNr1MfCqtlvoPMwUIdSesrWxpZzEGoXzVcR5Dq6IRaira2Np4XDkpdkoWQPLobXWz5Lk7soyOaMwt9NyeJ0ckjriZeMihDb9OQZeD5DhTcQDpNR28YKUrUUbhYPYy8yjvivaa3aLsplGESYAjKIFm1OUUnQVe9cwodYAhoj6gyKR2tOJjuqRL6Ux6Ll9gEUoKee5uAhMwdAhNNZY77LtqONeSbakX7oPDMRyvCBqOpwXWoBh/2F1QXLR0oLeXBb7j2ZUgGBzGmxX1wvZ4e69h0m1yk/WoCvGcUj6TY4JEKq7FqyiiIdYmG/RYnMS0y+MZcHYnOMWtoV19wCHAES14WpzbulTx54V1dUyDrM+XGcYUGFiqE7nsIlfCKF4cRNC5R9dc6XT8BqTMf1Fblstq0mlHUEYKiCVqKn6lFGPhKl6KK7CBD1FMCNdJ/0AdTEJcb7MBE3iISAZeWR4rKfyppoHnxwqmTYWTVhb1PjZWbDoyLtVXGggc5AylF4HsepFibEtpUqKTyaJgx4YYjTXXcODllXXnMZBeNS50g1GLmqW0htri/KkOvWYrMgTnlIoFPlqEHwaaugjQE/bHbLo3I/Aw5JBuojk+jGrfvrUROmQwjHizDLhGfqWcmaweWsqWOdKy7ex4JIrPRadz2KCIAPYVsf5G3MT27GySgPF7MsIMzs1wKFiyPokgH9dVXnYe0xeQfNtGMqBd0NSB6lsFCTykRmgldUSftnlmW2FblilbbY9159Dp5JznS074rR5YmUkpVpk+GiaU7EpevSs3hLa9VJvUbAajnA95JXiLzTS06chuciaAQ/bmHy196xmQQbLLAJruJbeO3lQbZ1xKL2JDtd2Y5kbJ8Wagwy2aWQQ7UAoPET4gOpXWT6SQttpJnpaOG1Uo7LK2h/lTHNvbUyLEzGCA4onPfUyLDSOoSoR67tYsMWgBbetXVFHVIB8pmTEqCed+mo0rY7ZcMT6lm+dWhk8N1VZIismFltAi3KZplvnPkUpmDszjS9M7daEN1RpIxfOf+e/f7MvSuHs8llvMKFw8EA1RJ9cN9GgyVOfdpPJMiVU9KPwHwtMhgz1T31t8pl+UVraIELM1wx+z6VCeKhtmtODkjfsbJETLn3bWUFBIjFkcBTifiUpySLCa8v7GyrixVBTt6kFDZESyVjKtQOsiuq+Kf8HEYBI5kG8YXO31DBq4fELLUPRXTiwth53rI2YbAoYTvRN/KxAGtqMwtRyAa+j28WnI6ZBgVtXjx5c2wTAp3LIsQqN5tRwzMghEkpN8MEF0jPz3rfYl3wiRp8qU2oqtL5hPVUPRepm6IzeG3OqIeAbC+WAoybr5v+xXhUVoHHMeN6Jw5jQS19Rk5bE4SJtJZBgJEPUtmTiQqG92nurrzHiJrMOaOZ4HLEPZKbFGjFqlta66vv3WsGCjD9+mSYeSTwaLwH84A+WDwD/UuX/ktwYI8ghiCZ0RzK3aDtifwJTJODNguehXIJ1pQTzFZbU+lKkaRwXfOWTAyTFYc8lyoIQPTUTLkpMYvXyWVKaspP95WBtMDkxG3RENCEsxoIfKl/h1AMSM98x/R3dpQ2uLgEA20ycOUyDCyAGHeFVFL2TdWFJqqE+QdVN9ijx3ZikKt23qAhyJiaktHd/VhCiNVopUab4kYrQKECSzT4r7ZUVRxvNLBY9jHD6sfIDAPQBqgFhkLBYMylL7uMkiYHCCDdecKvFi+rf9XfbJT9mQtbjucPzMdTgHDK2amS4aRepTzUpHJA4a3ScR6E3k2mEqH1+/dJwzCqePqSNy8oomFR+Yk8ZatU+h7trQwea7/G29NqwQpNtZTcZx4od3yGD1CXUFPBmG+8tWSgVILNzquS0wGI/BBD/oGnB4ciLrhChoN9bxIGJ6TgcSde9fldMkw4pTDowXgB4zgKJyXswKyqjLEfpqSgsJUcBeiM8bYzq2HvVUFSBAk6TfxY2RKUkQSQYyFDOE9pgJbmd14yM+bFNLFkM+1+OqQdECGnIZZCpn4FlJnKu+fHnUG7IAkMRwWHlywaLBZhbn+gMzTIEO3U615NwoxI2TjbojBZhIqUwjoyV9SoUWb0k1/g/Fk+k3kMDZjGy3XlaPqxxDEoxBm2wWmg6rxcLKUaPX7oAiokUnbSN3crLoXk82PnvQUY8qiY/IiO8rg7VWxcTLeHARKU/LqjOrV5Jfcno7fSywP85xalFIQ02VzafqrLMOoupEnGgXwZa4Y612ubLnsvbWtGkr67OrSQS4A/uggSc1OXK1BI5f7nRtHXNkofhYLdTxsblOYTZMZVNY/8yJNJOrGWnXEh9Iqz1VhFjirEcRz+j6oLoA6DkfXhgzspUX1qTzQ2CnvOvDqXToWDYSNfWjfrvLQQuh/Lub5nQFX8aCu6DpFMozsL3gqkfAjrKJbWaQCtV9CUjZ+ekbb0NStNxpn7Mr2IFLqIxX6zcNjb66wMN8RN8geLHX3I/gUioyRryy+fudTluavqY4PrETHVSStHpSf5WjLoJbFXaR2dDssNBhYcIUkl2IFg4Hpg1GoUFuXwdLWLEPob7pkGPHNXjiPEFsdmB7sIBE6XhxJGWW1zyBZNYieIL3Y6Chb2DmgfTCK+KOb3gcp0pSUFMh6ykiXVNFL5/hSxIOjWS+UpwbSE5d1RKjYkMEm1tq35mbqnKD+C53b0fEgtAzyljrONUo1ZWD0Ntm1P7pX8rJ1ROtpk2FkD1FUVFKj5/r8Q9GeD0VZiOtxxZ+NSyOH0tD+w71i/bqDM2wXBEMEbE7Eodj3NRCNsGXYpIPsIHl+DfCAaQdep3kgL3Tkn81B20YGizShWUJbvc8gwaz0nM2dTp2xy/Wpk2CEhPAlK9SQjOZaDpp23m2KZBjxfQD2HKz2JkW3n+p3YVruOBYAijqIxNQhyZmPJbgTqkEJ2YLuQDf0NbBKUYICB/TdNG7c1xXjI4cYBHmZ5QAbDVQLObMWbyNDqQgc0FJlqIah38NCAUqilx7cIb0rOxne/BxXR7szm7hRanUVbIsnq/6g1XTJMOpNSETozX3xpKuegAVNTIM8OmFS6YQNPFpA79yQLgeUAl6CtajYq6sMdL8La5J9zWQurhUjlTyWvvPgNaMBj7jxTcNT+zGwoDHvGOI+QTfrPeW7lEEZnLYWCoIe2Q1DaPN6hesVgzJLny3a1ojrWCLGp4534I/SYZtcSycDR/Bpk2ESxgHKt1uUljmw5eMS8Lpq5DQhFPUcuuydqBw2mSSFQJtIpuhiP4lPb0+/RFenYpiNEzZHYT5saAQp4tncKIFIEAB9HdpgWIiVrBbYkfH0eK7TSP0Ui9EU9fisFh+zr7qgMTKg0TEjz9WJe++wJhmc/7kEehpOXAZjV5QCjQd59DTJMCoiYW7byeKRQZ9VJV7JoPTgFC2FshakDq4RrrymP5Log0zr7wUWZv12MVRBQT0tqf/3nanniLUPjVy9B5LYUVgfZJUWZun/EL1IUYVpW//0q1R61pWfPA4MDMhg/XC0Cs5OTw1SdM+TyVL1FZ5TKToZJZ6FAIfmd5pHM99NGeKLkCKfUyLDKCjXWQUnS0UZJvn8ZCKi1yeF8F/q7ISqTIV8EMGa3UkIUVkIQ1AVipDY0i3d4whsU3iufHUeHerASXY8sNEqP/5uHpqAE5xTWhnb0shI6MaaSh6QIRkYnWmlIJgd6aEYSOnNrm04GmM4QjoVI03znFrRuuXnalyG5pyMZJ02GUaWtgSOg0UYAkuwXlAuaJybBoSplK6kt3zGvlgrWmsp5CwJPah/NYze3kIpMfIZi65cD6FkyJUvo+0e7H3mNrmfojKgEXXyEqAPSMt2WlfYM+EUTPlVVLVxc3bcWFwGm0sR+DB7irYuX1/XjuTZSULFXptpk6H7+xCS+kj0bE6gPznH3elqGT8LxUbvXbnBJuNS+fgzf7c2vRtEt9WY7D/MIXSwwNEg1u9dxGQ8/kw0Ut/SEmw7GXIdGsTm+Z4Buj1aua6kgh7thm5aHYb7A31+lWWoZ5mk37ZGBAH8fI5ZZAPLCqInZaVIHxE03bJq4nR0ky8YHD9uamhANDV6iNcNPLEMneDhXj7dG1CiFQkSOaMnhFitq6T/h8qH6lhISZ8ptS0DiBhPEmxfp3meSOsWqltiu4DIOUoy31MmQ3d0QyJvHWPwyCC6/+DWoRtpsT4o1A3FLWdMArMS6nCkUOZKoWcwFMBT6BOG2awIlcmQiKIAWilWLmgolsUiffhDV8k5JP0PKqfv/LjooAy9VSd+ei894iqx3HhSEEn+a1rkFIhTVdMjrRJSNhD5o5Q8dCJTJ4O9l8n5rwY5AG9qxGE7nI23MmDg5jI0nKSfTlhksN/FFMe2bO3DBKt3sxmZO290BPA+ksxJrmi09IBLi746nCAsDOx4tdKFIRnIEWn1PVTRFI1XbYykvmAipzyFnnwmskENJStFDdZaBgRucB+/TIkMtlOt8xld+rNXwMONVjuQXF58a96cApRugVdq/IENV0oxzo21sPpVggaNVtGmSfHKz+CAMDz7+ZhCfXTtVG5SnGq4PubqJyi5L4mpHcKXZjpV8g+mNSBDDxjS6HCEiZtaSpfRN3ZvGiL75NU0f7dv1bMZLK8IMRG4AYogczMtMoxCWKY3aWRUir4Ub9qafqClN3XrnY6YO0/xbyWke4qytthjYU7ApDIChzdsZ3Qt9BkmVvREV8vYggLExiIiV+6LB0mNoh0xJNlBAIMBGRgYepfRct7D3kztg3dzDY1zfqD8FC6i6GdddZXSUKrQQQe2ejRlMozoOB2UPR7fHBUKw14spBDEX4WMprpEjym6b/MF91xbbWoZnHKoLAi1oWXgoJjC7ROsULXQTwPS1P87A6AHi7TcJvrUlg09d5SNQiF2SIa8UsLOyZNCs5+E1NQuGG++1Cgk3y6RDwsJjHguQ3x0tzEPnQIZRuAOdFVJq5rHuRdLdf94jJeF8+MYPMvvHXVgpFbjUSOGb7LEpbzUjuobf/W/YDQWYViBDT4k3S+JRsspSR47IsD9CfqTdTMS/p14DDg1IAMqaATVkjHmCWsDcfubioSabIyBFjPMekD/oj5DZOQJ8xTJ4KddOXSIGzpPZEXLKxO8TR5PfLqB8GZNb23fGE1oaQNfFUZKbMzLo0FZe61LqBA2+9AwPpoLwdt2MsRB8zCgfXLo0DQxh4cUYbVAfboketZ8QAbA/o6CAxfP50rsg4U3HZdYbmzpuCVQBAKKN7A4ysZ1mBYZ6zTJMFIi9clmvymehXFOrl4eUD84np8s9MN5yZh6Rk1LaFxHyZvx5a35fl0WOKRE1VF1IzLkO+KEFLOcRm2lDhQMPDHBkdRoFOvbAxohfiBBgKH1sY0MUHQV7wOUOiQdFPhvT1EZhb1/G30RhAmO+H1jg4ytUB1fDSrOByN1iBDTIUN9c5+Ews7+tFMfM7aFkAKZcw6sN3NRAMdin/FZgELAoF+ov14kQZhQRfQv8Tsty4W5S7jvz2Ko0YpGsjTYQRZDsDq49of7GMG0n6QTcqawJKw0WzJA7aXKIFSoxGwxI93TdCQMo9IpJoIpgfzdHFnIAcz4VReK9PDHCUj1maVpkWEU6NUOunuMSuQU6mgl/SZGfQlMgvMIE9I+SupLUVC92FCE+kS6tB4J2clPCmODU4O2uQ7xr8CeQ28IWR09jmqdLDxA0fHYiIvRhB2DMefUtmE+MiCDsk23HBAqoGlBKfZL7SU4GhSX6aEd5V95DYNOjxwnnoQGQcE5bt6hd02LDHVjjislgyPgDVmCxApWR9iYK+2A2J0xhIN5GTIKIy7YPkh5JTbolcHbV74MJeBlIa0D8SuUxjEd0wNN3uH8NnlACgCipwNKiAZhNS5EiG1kqMoJ8z9VPjoDcbDQZ0OKO2HvT/4ouDAKq2YqOIkbe5in8XcGlIDMDW+YIhlGoCsgedfMaOmR8K6tDpojMz8zUYqYUKIMJ4O2VSXusSgWpCMADYdpT+JB6BJJ9xE1V0BFIDdye8DEcSnwwIYb6XBHSaeUAjKSGm/aRp2V+MkyqO96uaJgalDQjU4SwfXI9dCoJ4Gqv9jY9ocZEa2NITm1zdFt2mSYpGbqP7UCISBAE2RRkHSWS56wVkqKnFo/5cCo5YrUliIU9efqjmoc1N7QXdubAYPaWMfejhyOZfDl2u5XRGcfAG/o/bEM7sk6Qq7H2ZkJ9szvwu5ds9g1N4tdszOYnUwwOzPBaCwYjwJGYWNjE+ubm1hb38Dq6jrura1j6d4KFpdWsLG5GfVp6VfUc6k89PRpoOPgIqEdbEGjO/NWaMC0H9ZHGl8CNNNv/Wa0s018lWWYlIryMUWR+uyDBCQNTqGVzUkqNzRBNgWExyWpPdlO76ivsD87j2ZmMejYXMAcgJSl69zCfamm9Cg7O0vlzZ0J/pRfRXDlpXfmiAZHRLBv724cP7wfxw/tx9GD+3Dy6EGcPn4Yxw/tx7FD+3Fo317sX9iN/Xt3Y25mBrMzY0qdgOWVNSzdW8Htu8u4fmsRV27ewYXLN/D8S1dw8coNvHT1Ji5cuY5rNxexubkJc9IG6LCTmj7JgS2iV7KCoAIAACAASURBVB2oYal90bE7T4fpOx/lsYd1qo34imUPMxOvkZd/4zLsfdeHLbiQL8IP70kz7cvOHRA6NTC8TOhRyEj1d6c/RliiQ5PgZirauhKjtixsYQsRaTTKhZDAaK/ao3K6PRoJzp48gtc/cgaPnT2Bhx44jjPHD+P08UM4eeQg9u2ZDwPJ+zosp17haAj9LgW4fnsRL7x8Fc9duIKnnr+IJ595AX/8xWdx685dOOAwaKVPICrS9JH0m9tU2iGlS2qygc3loH45umhGwOVfBRlk4V0fpiBAiGn0C6UN6TGMYLcaUeC5PN8zhKUb7rbGYzA0oK/MjO5wdGo5I3kjNBqG28EZaFAyz+at3Lj7MR6P8ODJI/j6r3kcb3/Do3j07AmcPnYYxw7tw+5dc1V1ET25fxN1B0cZai8iWLq3ipev3sTT51/G7/3pl/Cbn/gczl28Qipgvesw96zYPxuo47UJGJDGK9VseESjfm7t9A3h/w3JIAvv+nBx4s5yvrhZZIGDUGJLo4b06wywuKOqeqhjsvEmYGOgMrqwg7RCzsA48qrU/PwcvvUdb8Jf+cY344nHH8Th/QvYv3c3ZibjQUPOBs9XdoTtIsVQm61ScHtxGecvXcNv/OFn8bO/9nG8ePl6xZN6CM5S4ipUAoy88hbycdYPkCJB/g4Dku4OWViKEHG+Z0qzMSvW5v9fGWqEiA9ihGO2wYu6zpv2QxHO+gopUk1VdAWK65NDo3q9T40d4XT1Slj5QcjOsz31YqUysYwAKVKxtshhxqMR5nfN4uEHjuM73/u1+ND734ljB/djZjLGaCRxIAau7VKkncq0vNVP6/fG5iZeunoTP/l//w5+9tc/jpt3lrC1teUyqYY5MrPOSA0Y1GWqn0Gr9YlS3+aSaIbyRr9AGq+/fBlsDmHi0LyhKLWC6DCcf3VuHUBB7+mAhs2PAaMxupw7Bp5SYBwwulC34bWGVA0gag9swczMBKePH8YTjz2ID37z1+Pf+trXYd+e3YP9b5WC5XurWF5Zw73VNayur2N9fQPrG5vY3Nqq41gwGo0wHo0wOzPB3OwM5udmsXd+Drvn52y1qSVnC8CGHEivT3z+K/iHP/UR/OmXn8Pi0r0eLQMVS1EKJCILoW9SbQI+vhmzhTgm8WgPT3xbGYWCWD+P+MuUQRbe+WENSKFG6LKUupFRzYkDB/OqdTHUKRHP34fK0PiO9r0mOmcmGBG0Ye67tpuZmeDRMyfwjq95HP/Ov/02fN0bHsP83GzPIDc2t3D99iIuXbuFKzdu4/L123j+pat46eoNvHz9Fq7fWsStxSXcuXsPK2vr2CrdxuRcdYQDC3tw7NB+nDh8AK86dRSvOnUUZ44fxgPHD+HBk0dDnzmNGrpa6dWl67fwz3/5d/BL//qTOH/pGspWhTx7e51RjspS8Kv3THNCOuf0Q42jVOMWpjk0NH1Dh1umy2vOwznEX54MXcrkHLgXVqE8ykUUyBGj8SI6kiudVcrGTLQH07eck21ztRyxE0uRIwKNTqK0zWQ8wmNnT+J9b38j3vf2N+IdX/M45mZnOlXWwdjcKjh38TK+8Mx5PPPiJTz74iWcu3gFL16+jsvXb2Nza6sOqLj6ydHDipnyaf2PceroATx65iSeePxBvPV1D+Mtr3kYp44dhCA6wk6rVXnecmfpHn7zDz+Hf/ZLv4Unnz6Pjc1NbDfPy7qJem4vYoTFjWTn3c+G8de+JBuSB+qQ6TCImpb/EmToJtWJ78yurdX2cva2UnwuFFFqO0QLMvLEqVWhWZAhvk28Nf9hMiePHsR3v+/r8a3vfBPe+NhZWyYFgK2tgpev3cQffu4pfPILz+Arz7+E51+6iis3bmNtfQNu3cLCpDSsfrMBasjg4Rbj0Rinjx/C6x4+jfe+7Q34wLvfgpNHD/UcY7srg8zq+gb++IvP4L/957+MP/7in3fzCqAPSjx+5lhWUMXNluogGRxf0yC1tpbNAGbk0QBLpVU31uj1kwTzfyky0KS6VjBeQtyAu0M1dAFjH9WtocvCGjOfoEIVELSZlBK9D70osZ0ftICoNyBdpZEI/uo3vR1/44Pvw+MPnsL+vbut6dZWwWeeOodf/b1P49kXL2EyGWN+bhazMzNY2D2HmZkJNje3sLh8D9duLuLFy9fwzPlLWFpejaGoxWwzYvbLRiLYv7Abj589iR/4zvfiQ+9/Z5jIA20HGUqxNja38PQLL+GH/sFP4k+/9Fy7X/2itqF2YmKk1ZzGJDbMDXPUCJNgpHFNWYMSbNlEa5L8F5RBFt75fV13Tafrp0mWbljwYzQgL4crI55NYg9XZiUpp4E6Gk5b9bEDraDI2n+tOzszwRsfPYv//Pu/A+9+y2uxe34uoO+txSV8+dxFjEcjPPTAMczNTDAajcwYdUe2VHm3tgq2trawsrqOL527gI99+s/wrz/1JJ67eAX3VtY8lRLeRaUJp90D6dRlEAC75mbxTW9/I/7e3/wQHjx5BJPJuBephybeXAYAz128gu/9u/8TvnzuooFprBdMQG0IoGHs3SNVN8A70WzxqcPPu9+ASNxLslSJMpJWuv1KZLCUycg3vI/2ru2bSh3cIgFFW2BULVUCNFnvXQyozTmE9g7oHzgcCAm98pnJGA+fPo7v+eZ34Ps/8B4cO7Q/IO2wctvLniyv0tBrdW0dn3ryafzMr/8+PvH5r+DStVudYzSvFC0BhOU7uh49cwI/8gPfiW9955vCDjj3v90ycKmT1s98+Rz+03/4k/jScxeo36jP3jywkSol7uOEWwZ4sQaZULJikXbV1oQx2Ncrk2E8d/aJH+tuCd3XyQ1beOeNlgeKE9FORGJ7neToPN2VUw07CBKVUZSuFuv3hlY6e5EgvIfLyijB1aEDC/j2b3wLfvQHvgsffN/XY+/uXY72acBaZVreQlytz/fGoxEePHUU3/7ut+LR0yewvLKKa7cWcW91NcqeE2nOvZMMgODGnbv49Jeeg4jg0TMnsXvXbBiPIV6VX/199OACjh7ch888dQ637y4bDx7FdOxKHA8ethAFKmwGJFe+ksNXsOOIyRmCITjfB0fRWD/y9cplMIfo2rulK/2eoREdpSK1vjuP/nYmwiD1jIlWAKpQjCw8iDDFMj30eHShI9Ovf+QM/ta/9234oQ99C1770OlgwEo7G8/a+gaWllewvLKGra2Cydg34vjiti0nGo1GeOTMCXz9Gx/Dnvk5vHjpOm4tLpsxdYsIrJPSBwX9rIh7d3kFf/bsi9jc2sIbHj2D+bnZZqTIcvHneDzGyaMHsbq+ji88cx6ra+s07Ix89Z9WxNFqbJSA20ArfaAUyCe2DgpFCJihZbU+20Y2bOLplcoge9/1YTrl7KFZiu49sAN5wpSdWZsbhTpgzhDcwNsZgNfJ93JG1cqwBrIuvTe/axZ/5RvejO//wHvwDW96DcZj3/jiiefa+gaeu3gFT527iOcuXsFLV2/g5p0lrK6vo2wVTCZj7J3fhRNHDuB1D5/G217/KM6eONx0qtal9xaX7uGjn3oS//1PfwRfeeElbG01ji6wXKQXB0q/eWj/An7wg+/Df/Z9H8DMZNzjY2gjj/l67sJl/J1/8vP46Cef9JQu9NtaJOEUBcjGYbOAEElq9CuAsIBiHXkDjSCmGonGF/gB4goU2d19yjDpjLjUkAR/BqAnaxTcwSoyn49V8CDElIeYM8H7/TgRroOe0uywRzim3dU5fmQ//sa/+z78tW95J04dPYTRKKJmKQVfPncRv/WJz+H3P/sULl65gTtL97C4vIJ7K6vY2NwKChYRzM/NYP/e3Thx5CDe/ZbX4nu/7Rvw6ledMnbz+j+XAcC+vbvx7e9+K/btmcff/kc/hYuXb9DgkLwWqt0INHr62Auu317ET/zSR/HQA8fwofe/c7DfIScBgAdPHcWHv/09+LNnL+D8pWuuR+WKkY9Qmz/8e7UpHj7L+CSIpjJA55jqLNq3RhDEVE/nrTDeiqeYIRLdvww+qQ4cgwinAaKzSCkyordEHATevj77Qet3ITQISqbvaixaPh6N8IZHTuO//I/+Kt7zta/H3Iw/D7WxuYVbi0v4vT/9Ev63f/X7+PzTL+Du8gpW1zfMQLbLu0Eyzc5McOb4Yfwn3/Mt+J73v2PwiHc3HtEIN7e28Nt/9AV879/9J1hbX6/jMiCk8mAIFysUAU4fO4Rf+Ad/G088/uC2c4fWZ6eXTfwX/+PP4Wd+7eNY29iMOg1RQNmrWYOBXFcqPQHiOSU7hZGE7D0SUO/nyTk48hi9hORQgL9/GWwOYcXqupa7SuycvFeXZbsJc2RSEjM0JAE5OGJp1CxUbnTEnpOq9+MhsI5lH+Ddu2bxgfe8Ff/07/x1vOW1D2My7k6grq6t49kXL+MXfvMP8KM//vP4F7/yuzh38QqWV9a6J9BQHMFMc9oHo7Ub9+bWFm7eXsLvfvqLWFlbxxOPP4g9837sO0/YGaFHoxEeOX0cm1ub3SaZOQ8hSAA1RULiSXVeCpbureL5l6/im77uDdi9a645z8m/ed4zrvz8qz/4LG4tLpsOGEwLj7fEHWAR7oO92eeV5jBSgTfJECIlCCDMJ6TSgNkkPyUH4cUIvCIZfJVJFH39OIHlqVVZ3bJsDLeBYUY2gYW53sTQ0D9utaty8nqzIYSoYApHLKAP6qmjB/G93/aN+Ps//O/jyMF9ALq5wVdeeAkf+b1P47/+iV/EL/32p3D91iKFKphCu76IuD1qV+tayIavdADYKgV/+qXnMDs7wdvf+BjGo1ETpbP+AOCxsyfx2aeexwsvX4sRwRyfQ25d7zPU8M8tFNy6s4y9e3bhra99uDf5z6thmZdSCg4fWMDl67fxqSefqRYe01MIz3dSCFPNkJGXSoMNO+g6yWDpr9ldxAZzCrbwBB5qL8bnfcoQIoS/EsVRnNE9e5p1KpJWikrfeBGI1FSJFaS8SRVXqJwhKAumX7v+X/vQA/hbf+3b8B9/9/sNpV++dgu/8rt/gh//hd/Az/76x3Hp+q3EDynUcj6JitTbKme9L2mkCgq+8Mx5vPHRB/HomROmpyGnUAPdNTeD3bvm8PHPfBkrK2vQKG1zMhFyClqWzqNTBCtr67i3soY3v+YhHD+8f9t+W1GrlIIHjh/G//HRT2B1dc3pk65rQk56IzbC6xXdjmpHrnMbyr4MsT+OGrwiFfkyPrRqKLw/GcazZ574MdeXe6kwKbZBNpYwyJyTspB6mweRBiN0EB0kC8cPAZlDVdqj8Qhve/2j+JH/4Dvxgfe8FXt378LG5ib+4HNfwT/+uV/Hz/767+NLz13A5qZuiFlCGs9MBcCIkSPPw+y5c/1eeVtb38DVW3fw/nd8DfbM72ou6ea5xWg0wt7du/Dsi5fwlRdeMn1pNOhFiGTk2bZuLS7jxJH9ePNrHsIM7WSHyD4QtUQEC7vn8fmnX8BTz79kwBdiAUf9CgQRkf2TT0KDnTibCMtA/YVnJMQNuAjZn84j2LeYzn3KMJ4788SPcZixNWFowqMUnFQ3Ln4swxzIBhru0RVRCw8Gh8LAGFmc5SN+3x0oDuZ4PMa73vQa/L2/+SG884lXY37XHNbWN/Dj//tv4B/99K/ij77w51hc7p4BiMck9DPvk+jg+X3jMa83G4YQPQB3l1fwyOkTeP0jZzB0ZYPcM78LtxaX8AefewrrG5vdWFg/bkThbA/xyyt2axsbEABve90jOHpwXz9SN/jgaDESwWQyxq987NM2HgE0tNBSOG0v4CgQeXV9mS63kUEIBHryAnGCrPXIwGHzWhqnHWQYuYeQIWpHpf4oXSN7UxocnS2lqgauxiHKCssQwlgEiELG5AqSVEvZdF5FBO/92tfjn/7of4i3vu5hzEzGOHfxCv76f/MT+B/+5a/i2QuX62QZxm9mIEwCTcleVmwUOTfWsoRKVV83F5fw23/8JDY2Nl1PZHit/H1mMsYTjz+I17zqFIoNRN+QQ5rGMoiOV1f2J196Fl+sm3YAkFe7hvjQ8jc+9iBe//Dp2Fd1SN8DIH0ofYoC5iQ8lCzSdjIYb9Q3G5ECRTU8yXRzJLoPGbrdKeqjgDbkROz1KzaprQwURnBzktpex5Jva1gtyowOkHlfbeOfKrwvgypqdD92zc3gO979Vvzc3/9hPHjyKO6trOEjH/s0PvQj/xi/+rFPY/neGsmWFElXVE5kqUKVjkYiRUZAI1FEsLm5hecuXMFzFy83c3aWiw3zsbMn8dqHTlekSvw0ZXAdaYqlBrC0vILf/8xTuHnnblhezZty/Ju/H9q3B9/wltdAB9PtncBCUdB4SuNZ1eSpcd/gt5PB9evgU8wAsy6inkr45/5kmACIa7jEiwrjWxGFwlREb8tRMwFKR3wZTMOgp02dQxMi2hvVuF3XbynAvj3z+K73fh3+qx/8IObnZnHlxm38/G/8If6X/+u3cfHqDeN9POqOJkzG3eOak/EY4/GoLsN2uXu33NgtgWo/o9Goe/HtwFXQPSnH8uvjoVtbW9jcKhiPRrh8/TYeO3sy1At0Urp2YGEPHjlzArvn57B0T8866QA0+BHSjemumFF96ovP4Pqtuzi8f6Fp+EPzChHB3vldePOrH8LMZIL1jQ0aLR8HUSQ2oIJH99bR9/BiJq2/vQyhndlFcWMPqRrJYt1XMJOyowyTYny62ZX6r62oaDoEn0DGJyFooAw0+4jo3qoi6e6yKyWTnZ1MsGtuBrvmZrF71yzm52axZ34O73zi1fjBD34zjh3ch43NLZx76Squ3LyNb3r7GzA7M8FkPMbszAQzkzFmZ2YwOzPB7GSM2dlJfVPeDEYjsTdkTMYjTCZjzTgxmYx7b9Hja6tOnu33VsH65ga2tgo2N7ewvrGJPfNzOHPiSGiXI0SeXAPAQ6eO4uC+vVhaXonoVyNj0+BCPVfgsy9ewsUrN/DY2ZO2Q5+voZO94/HIHmd97uIVQ0YDsVb/wSR4nlj/oWHubHlnGQBa+HCD4Y5C8HR6zKz2v70Mky73klCpJGq9yAdaK2YlBFmkn03UupPxCAt75nFg7x7s2zuP/Xt3Y2FP97lvzzz27ZnH3t27sGd+zl73ODc7g12z7hgPnjyKIwcW0G1uCV7zqlN4/MPfgcl4hJnJGOPxuHmmJ//mlZ+h3duh7zu1B/pG3/qdaZ062r3QLM5X4AgYUBgIA6RXrbu+voEnnzmPb3jzazAj48DXTvoQERw5sICHTx/HcxevOGhrBlnISFPKqRhnLKUjDMb2fciAQk5F9VwGW96h/rq2eYVrJxnCu125P95BbPHrIlGgK4CMBAu7d+HowX04dmgfjh06gOOH9uHoof04dnAfjhxYwMKe+e6dprMzmJvp3ms6OzOpr3Lsvs/MjDEzHlsas90xivFohAMLezB0DR20Yzr3m1e3aA0ZfMv4duJHRHDk4D7bQ2nyjLih6WkDaEgU5ASfe/p5bGxuYnam9yrfkCJlOUUEBxb24Mzxw1o5ZiqBExobA0vSQwDNjsmYZWwvg4T9IOWZ+xX2t65cv+f5xjYymIaMUK0UcjGdfUvX7cxkjGOH9uPsySM4c/wwzhw/3IXWE0dw/PB+7J3fFXL1yXhk38fjLjffbhmwtYmVr53u57o7bYy9EuTfbud5J4dp8Z7bHNi7G7tmZ2LIFgdTJwRHYwBsX/4cQcFTz18M850hPlrLrwcW9uDsySOYjEfY2ip2HCd1FxjrltSLPwNjgsL3j1KavJMMMWPRJf8IC6kTZoj4gftVrirARFOODqkdoXfNzuDgwh686oGjeNWp43jo1FGcPXkED548ipNHDmB2ZrJjemDKafweyltNrFSWDa6F6kOhP/++n4gx9LvVT67XcpydUjFuNzc7g8lkHEMz3JACbUF6ETN8wGvRs+cvY70eWmxFhBa46L3JeITv//b34G2vfwTnLl7F8y9dxbMXLuH8pWu4dWepeyv5+gbW1jewsraONe2ndq5THmXGncF5vR8ZisntfuTpkf8IizrUj0WpMC+gtL/Wn7z3a1+PwwcWcPrYITxw7BBOHz+M08cP48yJwzi0b29zgIcMaicDZlpDAzB0DQ3ekLFu53D3K8PQvfuJYENXlqNlmDOTMcZSJ/T1nJUvcCQ+C1kD2Dbc2lbW1nDt1iIOH1gIfOwEQnodObgP7z74Onzjm11nW6Xg9t1lXLxyAy9euo4XL1/H8xev4MKV67h5ZwmLy/ewuLSCxaV7uL20jJXV9ZiGsCnehwy9NKtQWp9DS/3p8QT0ehvNl2DpE+VWmPzLv/dD3RsmtjFgWPv2IO5kfFw+ZEhDqy9D9bcb0KE5wU5OkXloyTfE63ZX5qulKy7b2NzqTr3aDDClSiHWx5vOSuT38o3bvec1WjLsFN31Govg0L69OLRvL97wyBmru7VVcGtxCZeu38Kla7fw8rWb3buqbtzGtZuLuHbrDq7dWsSVG3dwa3HJeb0PGcJNjTYmg6dDfTpULgQuWk4OMhlyhmzA2Ui3SxWyoltovNPKzv2kTPy7xfeQwfHvITocaTLPuT7T2e7aLr1kvtbWN7rddYsC6AGqcOznJVjli8cBwG0zvj4/2+k51891sq7HY8HhAws4tH+vHVsppWB1bR3Xb9/F9VuLuH57EVdvLnbOcuk6Xrx8DRcud1Hm9t17KOk9UaYCRf0QZDr5exHT6qR5Rj6EahGo+02T6riTOZT7Dxla/p7bDA3CTpEgXztFnJ2Q/H6ixJCxb5d3D0XS3H/upyX30soq1jf0xWce6v1JM4I10wenVH2ad5b8LFfms+Xo243vTo6Uo7RINy964NghnDp60O5tbG7hztIy7ty91z2huHQPL1+7iaeefwlPnbuIr7zwEs6/fA0ra+uqxdq2ZjthbtAV6n7FUHbmtl9Ijx59zCGyIQylLa9kPrFT6tNCmFZakem26AwNTL7WNzaxurqOLRSs1ZcQbxVgeWWVHs6J1+bmFpZXVu0FZXyNRLB71xzinpdgftcsxqPuZQRzsxOMR6NtUVd5L6VLOe6trvOow/JnLrMg4cuc/gwwrK6ge0IwZwCtyf0QKA6loUPtW/1wO5FuM/Tw/oWwi765tYWVtXWsrq5jZW0dtxeX8PT5S3jymRfwmS8/h89+5XncvH3X9VGq3CSrRQX2HNJHbVGZqf/UexNmcMgpwlDvEAVy9FCF6Juvu2MNW9jcLPZ9a6vQvYLNzU0srazi7vIKFpdXcHf5Hu4ur2Dp3hqWV1Zwt74BY3llFYtLK1heXcPK6hpW19a7z/UN3Ftdw8raOlZWut8ra+sum2UXldeMIr3ftLTBk7lUv0mP2s7vmsVkNMbs7BhzM91G4/zcbPcsxPwc5ma6TcfFpXv2x05aaI8ez5w4138KgkHkB4XuN7L+Rept157LWvUm4zH2zncvcgCAB44dwuseOYPveu/bAHSAdv7SVXzmy+fwmafO4bNPncOFyzewvLJqY94d8c/gwU6Zogrtm0xaqZFeGUXyvdW1dayub/jn6jpW17ult7X1DaxtbGJtfR13l1dwa3EZt+8u487dZQuPd5bv4e6SGz1/bm2RAMq45s4BHXv6jsbYMW88c4g1JwbiI4hu4XD06crtfUC1mr331vLY6E0FWr/g3spaJ8Ny7MYndeg7F8d/Bh8ba9YNqQwsn+DQ/r1h7IZSvu0i8P2mta1rp1Rzp371+8xkjEdOn8DDDxzHd3/zOwAAl67dwpPPvIAvPHMeXzp3ERcuX8eNO3dx4/Zd3LyzhI3NzToOPMaw77bJzCkTMwDA0Hfp3gru3lvB0vIqFu+tVKRexfK9FdxZ6nK/29XIby8u1+W2zqiXlleweG8Fm5tbPmBsc8aYl9mkyX5zxAG6P3hIdbINBroRxYUJ50STjVnrJf+wolq31MHqoXX4Y45RyDDuLd4tndWIFKMTy6CH7F1ZtW9dfyE8OFLTEga2oblgjvhL91bx9PmXsbK6hoXd81jYM4+F3buwZ/cuzG2zHzVEL/c31G4oTcsynDhyACeOHMD73/EENje3cPXWHTz74mU88+LLePr5l3H+Ujdpv3DlBq7fWrTXiZpy1OhKweSzT53D9epJN+/cxc3FJdxedBS/W52gS1/umUOsrK13qwFZmIH0w+zNxq4OaEn12AgEvmFDuZ6kNi1lRi0C8SQtaqiMWB6QGoD9DTuzs2TN4s3cv1iQyhchUFz37vjKewymAlCfLRlQ+uCgOk3R7uihfT3D3W7Sz2WXrt/C//x/fhRfevYCFupZM3WKfXt248C+PTi4sAeH9u/FwYU9OLCwBwf3dZ+75+fCqeGhifzQ2LXmotvJMB6PcOLwARw/tB/vetOrsbm5hSs3buPFuor1wstX8ecvXsKXn7uIZy9c7pZ+TX+CyQ//d//C/tLNvfqp+TYPtCNkh0T6+J7eMsbyoLKP5IHrlZkaYsoAOOrGao6CLW2qEYUUq58aSeYF0ab8KIsbrw0OSq0X4d6QjOmaw0lMA82xHFQiiwMymLMR6706wMzMGPvTXzxqrSYNIfTS8gqev3gVTz79gvdUnXMyHmHXXHcKeb6eRub/9y/sxqmjB3HqyEGcOHIAJ+3zQO8PUjJvOaLcT5rXkmE8HlkE+bo3PIq19Q3cvHMXV27cweUbt/HM+ZdtLvLshcuYPPn0+QoqES+FJhqsbQ/UA2icr6YhDhhwrd+etLJzUH1Btt50T9Rja5nE+4AjLzt+M5WRHhk6t+nshkFRRJfEm2rX+ZZ+h7FtUwaNSBkwvO6pIwftDeHefXsPpHUtr3ZAaWouzuL6xiY2Nldwd2nF+SHHH4lgRg9wTsbd90l3LP/owX148NRRnD1+GKdPHMHZekLiwZNH7WhQyzH+IjJo+cxkjOOHD+DYof14A87gG978GnzP+9+BpXuruHTtFiaWtRRf1iuaUpQSUmyzaRo3ixfxjQAAIABJREFU71+Nygv9XU3dZy9MQvrGT8yHteLmKwp3+E5lsW8dWDVSlbm7achPRmVSGkk3ZJ/z9j02/LkAVh3pUtMj1UXvD8WYWFkGvYEAGGYcteDxV53CZNx/tqO1qtjSv6bJlhGwzhKPqGOKKsNWKd0S6upaL+159sJl/NEXnrG6CgqTyRhnTxzBI6eP49EzJ/Dw6eN49MxxPHjyKHbNzWCmOpR+smxDMgztr8zNTDA3sxeH9y/gzPHDvA/hw6UpgaOYvu5ePCcWGuyA0LTioYxIiio0mPkYeXA2TT9UYSW+/a0fDkwYqstpkW9u6byaJ54aJ01hltZ4WtRLZdBfXRKbF7B+SvdG9KpPm2/xokFI/2pqWus3ZTD+NToUVyPx/+jZE/aOqE6N2+8xuRq7OjcXl2xjzzfElUYfkX2cq/6IH6kIIDRG2NLHhQXAFja3NvH0Cy/hmfMvB3DTP3559sSR7v962vqBY4ewsHsX9u7unqNZ2L3L5i7ZCXu8JmeZqFYLGaYasw1HUlJPeRzdG5Mlcy6ztr4K2dFyHX43kRmxstukh16EsJSHw1pehrNopmmImGN2/HF/Ka3hUFHUiI35Ss9cpt9ceTbStX6cwPVkCBFWn39nLy8Fr37wFMbj+Cqa7XLzXH7j9l3cvrvkPChYBVBh4ycZlB8FsBBd718GQLC+sYnnLlzBuQuXHagAzM7O4NSRg3jgeHc49czxwzh19CCOHNiHowcXcGj/Ag7v34uD+/ZgZuILq61oUh8hFe8X1WvTpI/MJCC8DyAqAlBZVjIQF0oyUhWvFCavEIQcnD8ZsVqeoQZV+cvOwOgfUyyE9NBQO0dEUq5oH50lxzQP6PUddAJSNB3ayc+79+ZiQn1TlFaNz++aw+MPntw2rWhdOi4ra+u4dvMOVtc2+ilzYMdcnXQKFNPBMA7tJEPIOtCvs7a+gedfvornX75qdMajMQ7u24Pjhw/4w2oH9+P4kf04deQQTh/vjpEcP3QAc7MTk3li3kwdSOjUPwoLY4ZIvGsYNAOXlB5FZfqKSuxLHdTuFQRn6oFrdlCl0vqbTyxrcEgtQ7U976WHotUwLZ6K85nCSCMKKaBWtA7zGO3H+Q7LvT0ZAjsIY1kN6aEHjuHYwf1RL9I/umGt0qT17vIKrty8XfvhQdcP5c15YmDK0QJZl1GlTRkskS1qh93SewAp00X3ZWNzE9dudidrVW+j0Qi75+ewf+9uHFjYg/17d+PIgQWcPXkEj545gUdPH69HN2wuQGGPeLI0kW+kCvZ8h6ZalvoV30vQ6lVAdbyewRUKoyyvAi2ykXaV2oZbP4lWnuOE+QKK/ZGOkMax7HWAt412zAN8sAvUAIs7otJj5wwRYhsZQiqm95yH1z18Gvv2ztvYMK/6PadSnFLdubuMl6/dAlmJzeNEFBTY6RNiAvwn/XrgYExvI4MEA9CU3pSCuACCIGv9AaBgq2xhcanbU7tw5UaVoXs4TpeM4zPV2RmQjc64rUZCp1YDotZ0B2nFhgzaBpel0ElWcoYeyjIyVT7CODDZzL6RJDQ2unEeI6Ts3nPMmuYY+qV7WqQ71tQHavRsmga16e3FJBkUrNwx1WDqmIjgTa9+VXjeRctb3/U3G+O124v1XJXza9mgHaWmsbRI4M7cS69NgJ1lcAQA+I9RMr2wqNGjp/XiONgq9VaXFq6sreNmWcKIw154k0bgGjUXFEsVAvRph6XUkJiE5xDISjOBnI4oP6VUbWkOqf3U8nqv1N/FQlm9Vw0qDgClAyA0Np7Y+Ao8/LszGB/VEGIGlp2mgP4IQmBD38xnLBYVraYIhbQ/IEP3J6cQh8LsouDE4f143cOneyd0+eLUKciH7tU6V2/ewYXL16uhueydVorx7gAAu6O+oiXGG/3NkZ1kIHRKWy26vFtl6NVzeyk6DvchQ91VVxOnQWclATaw+pC4MmNOot8buaLPEYQEd8P1e0KoLoGegTD3UcO8fap35TlLQq+Od17ZoI+MdMYLyUQ278unhFSEdIaeJqeSc7nMF2s7IT2UbWSIcyR40K2g8vpHzuDsiSPB6PkzO0JO91bX1vDn5y9heWUt8FwbOI6Tgau+LA1Vsya9iYKnYEcZHAi7fhyvGHw8TbdxKWruyrfclwyjbgGDI4GPmr2WEoCuiXsa43Qtn/bKwTGYuKK2GnKeKJozEt8qtAeGiLqwNmmtWX8T6quCmNXCfLJsJX3PUQIl0kcXS7r77DgUzYo6COuF+lGnKj6UQzJwxDBIq2M/Ho3w+kfO4IFjB3tzB54zdF1K7zcA3L23iiefOe86rvKajYS3DSONmY5H3jOpsguB6oAMzIuNS0nlqjLWN4GqgeJ9yjBSm+zstASCYvHHOQlKC06hCqgEegPcFzbMNANbEo3EtFWIL1eQKrK1ps65KAGYGwlo0w1sfL3OrUOPqr5ZFmTIjlkVapNpLSM8UHWYM9HNIRmCxsRrlFJw7NB+vPGxs9i9a8544bEbWnplvheX7+GzT51ToaCbs6IvJO4hI+tL+wqwHe8FC+7LwEBFOG1dsBshfDd0DWB/PzKMNH2IhsaRwRGkQ6fIhpNyoQhM/R55LTNoTQWInVJZL73Sf4oZd3/+k5XkCMhRSRIPbiDMs94X+BvJGaEdnXQ+FBYjWBbhMSKAqOXRzolGSwYCKuekq/PomeN486tfZfc4Slj9bdKnrVJw7sIVPP/yVWjEEusXidHsFGbZSYZk0UpvQAZWgdC/+pXLSt/oEhjfnwwj3fSye+YAyl004LhrG3M65UztpKdwZYQHgCa+xYRoISz7ixpDXU9H6Rl7aJ+912RTfTkDOvkrlrbQmJXSTcqonoV+7iOMuVhbcyiWQ+tlmxr6TTJYpAECIMzNTPDE4w/ikdPHuxoS9x2Gdqf52trcwv/zx1+sf0qg81Y7cSDxyEaMcmzcpV0HBXa0fkAGjRLBFgqXw8a+k5H74zZSJ9L3J8Oo71geHYrob2ebJzMhVqTQUNKIsjN2dkSQKkQ3h/JqcGZnGkprOxFaopN68KJQtAiwS3k8Iz9ttNhGm8lEBwy1L6nRlK0z0dNVJCsLwOK89TKkHDW3kcEnri5DQcGBfXvwxOOvsjebuyo8wuT9hlxvZX0dv/XJz9NUJxp3S5zed5FoBZwCivPQkkGjhPPmNhjmPgE8HRQ1awDwimRovA9ald8NqJhnwTw2CFzHXcObejCnWb77KrVuRHNLXSoRS8tq9GDlQLIh8P/Urw52I5e39EXbG7k+X4Y2lfcQDXj+o11pWsS5USGabCKFNuGgEV5hhhxqQAaPqDwsgl2zMzha/9jk0NWaO7CTfOXcS/jzF18OVuOGmHRkTgYDJaXpsrFTe9mQDA2O3cisM71D9etYFbWzBEY7yWB/MIUn1DpGPJnjXNcGw8KPh0pbPXIOXEadsErrnt9XRDD5ya5cERLpsQ6rI/TSAmOthL6lkHzGlxhdtmveuOtM1vkUU35yRFdjdCKw/ORo2k/LMEiGgMYqcyXFfzUor8pxCtU8RiGCj/zen0Q/DIMARCOOiY+rUdwUeqkI7VU0ZGhdeQUxsGagLL3br0SGkZWXdAISDrxxvZfpO1KHkEsiY6B+MAAzbPZ0CQ5QkhCc92uY8s0Zdkrqk1Mc66c4X3n+QXOVbqC8vKA6EvHgrGj/VYNFzSTqI8ggAgjJEAx5exks1aqGvryyiguXrweDbx3VyJc6yp2le/joJ58kXfAYlF676Nhtc+63kmBNWYZ+OzpuYv+ShTVwKGQa9ynDKDqdo5c1LLRuS/870LJxpb7UUFoCcghlCNbONVJomiWRv4jilIsTHVeEuG2bWG5YXa3YOGaHHj2JYp0fOw+O6dkRAAnL0nVWZOlF1bOlQsXlM3p9GfhytQhuLS7js1953l883EgZWt9VJ3/4uadw8coNQ3WXAT5WKkO+xO+GYjLY3j5SQwaOOmHH2r51+jENWpVC9eQVy2DPf/v5cw11aoidUYqktImEN2nqvSAYTeRcWFQDSKMr8HydL4l1TAP0PcwrOBJWxzOHIhkrzHtwqgJ6qKdIo/dMhg7hnFXqm+ZMHRkfUO1HFxCcx1q3+KKFB7m2DNpvTs83NjfxR194Bn/wuafQsj1OmfLkenF5BT/9qx/r/mqr+jrLZ18jwvPVO8JiHaso+V5fBgYDyVEnoHzUFTuT9fkKZBgZmqoxJvTUfwutAESiXtUnwVSFo0PKAdWDC71tTm1fJ6i8fEaEGtGifrYmxMEoCGaF6CbZObQ627QCp/WtTuQvKj/zpewK0VKemE7sqykDUopRZXjq3EX81Ec+hqfPv2TzCb56x2oALC7dwz/7xd/CJ598uvtbEAQ6wbEkF3AGEE/SBq4TYDGWt2Swytl/xP4Z6EPi71cgw3ju7BM/1t2n80AV+UQiU+YenNL0+CRm4IOsyBqX2pQiRQXhk6USaRppUlKOEgES4pKpt1UZ6F79HlbG7N1KXl+q4/vEnzYFqV4XfMT4cLlMUTZgvCKl49T5Ox+xaMhg6gjZOHT179zFy7h+6y5OHD6AE4cPhEcqQeOxtVXw4uXr+Jlf+zh+6iO/i6s3F+l+jEw2NpR26DKzL4EXlMaL29xRLOjtKEOI9hGnK510ZF0i5r9SGcazZ77mx/pr1dy3H+y29WEVrpTGA/GBnY6eEfBjEkrRjJEQ0pboLO/mdiQQnEzPadjgA8oQErvlwVMdgwSiVT+qLIEXNQIy1vhXacjZrJ4DgsoaJsCge8RRTwaI69SONzt4bdVI8eVzF7C4dA+j0cj+Xp+I4O69FTx74TI++qnP43/95d/BL370E7h6azH0SaLqiBILOn7phLMIgVwETVUJO8p2MnTqKaCz5M6bDjnpN/wRxb+ADLLwrg97QsBGWb0cTKzhgUrYdwzj3TAlKOyd3ie5I8AGC/+Zy7O9Oy1xmNX6itq9VAvu1MWNLm8Y2Z+BSnriyNHRQd0EUjrMIzOK/n0g9k31WGCWwV72RlWHVpD2zM/h8bMncfLoQezdvQsjEaysruPyjdt49sIlXLlxp9emf20jA3xsG2xvQ/H+ZeiXF4sSodP/DzLI3nd+uKiXSB1U1DdGlAB12hrJ4xInNPi8fNsa5DD5MsPYRjI2Hq5nhtTx7nU9tjUjQsdE/MlDqjQkaa034jB0i/WobYg4mR929pL6ENdLkkEdQuc7OSVxMoXK+3W0Jt/PV8xWdrK+lNtoi+2caEpkGFlupWlHcYOgPUc73h2ioKKh/rQJTFemO5F9VIbdDzwJyFWJtADdiweKl1taBfhEzstMHvZeyzOJX7oHDcPMl0j8ZJGL0mT5WVYSoNemhE/7rsZRx8L7a8hQYH7CV4g6SrPq24/hlNAmIC031fo5khePlP25qZ9gsPZ+M2DAtMkw8omvHpKDDXLRmrpJVo2Ppedfzc0ejgAmfcmVTPpS0spwANtOk72d10Y603O0nObAfMD5FpWpVLm9n6T6rp7ZqCSbTyPCY2RdOWgoRZ9DSKg7JIMBSolyMbfS6y8QNB5baYeBQ3b02rxPsy9fhPmke2DqZBjxLrReBsRkKLb2zl6llWu4S1YDMy77qZBejUDblu6en4Hi5Vak3JEmm9oWzpMhSCmk26wMktl4pwHIiK4R0groJvGpfYRJWzXkjAHB2EkOu6cyWJ0hGTTi1YhjAKfNIkgVe0CJ+2s4oMneL7dzVsKVUkMCwG54lS9ptJkeGUZsEJwkOappaNF2FHREU4xangcZtggXmcroUBt4OJS+MwbQJXr9oARdzXHspTZkfeG4MDHnswodPKGoRo4Z2vltllezMgMP/nSJ4Gd6lQ5HnWEZQscqe/Rm78VSXpalYZyBZAk+b+lLzzG5OUeHsIAe09Te9dWXYeRnxfkWD5yGiwpQtLKRiTVkIwGDVPETMA/vpV0kt+bO2UEs3DZ5qM5BYbYAPqGvCgtTBNa19dWgX2K7JArUyTsHJxoc4fS3tHZ+yaMaMiRm0DcMbePR0wWjZrnPHg2B60iavbeb+zh7BNeigcjyVZZhZA+sFH3YBoij7J5qUSI7bzBOQuA8H9D7QgNdKqImA++jKDlWsX+cRc35M09UZkvDAHTDplRjj7vBjGaxr4D0pCc+qOe1SVEqbuCTz4glkChVfyZbX4augA2E+eFrCJGBlkeHVJNoOLj7KYPW5e3FPvI5OeHUaIpkGHnK45MSe7WistUwlmFeXSjJqFeYeYpKkuvAkbkVEUH3+Xcjj7TDd+A0TPpNaorCq1D+qXGTdqR77Hjfvoxod8mQpXv3VJXR9J9407+/YWnZgAz9yUk9n9TjcOjqt2+BMHcZVvu4ZYoCnnXwuDjie/n0yDDqA3E9xcnHFhCF5By+F/okO2U/n4uM0m8yRvfkUgMJG6pGssw59VfpSeXRAbh4XU4srZl7oL7KxCrxKww5eBAa5eClSO+beCpWmjAnvgy9tpEhCE6A1Vt14+jDbVmJQY4h2soPDRIvRgyUc8rUzJSmSIZRH+z0aAZ15GEkZkvFQ2F4loIdJYeuxHDmW5m3rEpXn8jTSpH4FpcqVLcCRsqx5ckqAuX84Z2p6njGAB/LVnqUd3LkEpATikVXIceMO9qdcxdqVitFvgzBhmXwts5PSaPfpSY0jmGyxGQUcDxy+x9q6WTyY+muBj8bSYsCzqzrhXL4/sR6emQYmYOQcbgxeJ+F7nX0S2SG0qSAZBziszNoWLRQSwZKUOu5XnRKdx4xJdxXmK20+6dMnV+jwxGnR7w4+oQFCHJKks9JSjLqjo+SdToIpwj6ccJVV4F4HqcGzYygzcsxW6uKeGkvPa5tnKw7gW7YlimUYWQHs2gC2f0U9+aS7EGSddSfnkrRKc2wkqRtiyPngMfb7jN5dukZJykqfzJaqYeR43j+LlE7pCyWU11TyztkUf4k6YT4VDpCO8wZxer9cO4/TnDaMqSXSLcdKJup81hCUTYV7TLS7J89S22SVca6hh4QpKM2UyLDyCaAhGoWtdWrq12bQwf6bipuk25kVp3bNKJFXCHKB9zo1CyovvZTFRnStJQLFnpE1pd2OsH07SIWqUhxhctKFD7jYWG+VGm1rPmcQP5kUGmBYJaBnN9eJbrttSOEwgBAuwkAwydw+238+1A/UlNaspYpk2Hkh+L8hqgRBEsmYyCn6qVHhraApjO9E7mZDzVgRszIpwkTbrBuOWRzNeMnnpnnpT6xRhLaSFVeId2oE0qgDQpWZPQilrPynxf2JUcKa9SnpU4ZNLIM9V7J/ISmTMRXu3rPtKkzcmBlfhpPrTUW1Y1YbyndWGg4/BTJMPLB6AtnL/yundFH/eFOwKsoXWrug2pr6dxLBhKOFDm8VAYcgVUa1l5sZ4oxhvt89jqngGPyAQYYPhBRJ+Gqssq2ilM3pHmDReS4gBDbJhn0HqWhyp8al+MJuWvpq98E1ZdahzRDAv+2QdpUAFwGSXQk6WMKZRjp5JiXVwv8vKt2K/U/fdS01MGueKhD2+vb1u7tVjXk4J1uhsW15cZS21jgaOSEdLPjtyrY5kDk9IUjmTmR9+yrSTFSeSxhmYLXeuWKhj6YfVm7moYgDQOjgW3JoHpJ9UX7MwNk+FWLK15U25q5FWpnLQaiQSvnb1atvAY1TZ8Mo0Lhmu+pA9dxJaE0lVD6tOWkS4QmLLsMG664ExYVg+rzfEJpVdpstqGNKcLr2nKfVa/OXVxn1jfDjdCufTEx3cs5pbPoxQ5Z6VOaVFjvjBxAGqZ+2aAMpIP4PfEY6jAd5bPEtnQ7PNuMHZ43UBwhWqEmp8VgutMjg0WIGF7IK9A9UdYZCB/m00+NHYnxEn92/JPVUUrTY01XXRKtojQkF6KBVKLg4yRKHqwSx8eBpy4jFopwDf3QIMRxrjOErCceRIoUEgioCsQdcxsZ+srrX1E1HImpr9C5ddQzSl15LLbMLNZHWrk2WmysDgzTKcNI/+Qup0w6kewMxjfqWnwra4yiKm+Qga2D6hjzbNQhIhWrFx80UufSB4eIweI0CURq18X7yqgf9eMRxin0v/NtUn4+PCbWJ0dJoZsS6Vk72UaGoCzXRY7oTJPz8HzFAauglG7yCqAxMXRUolMwPxseMMHITo8MI5vsMnBXBpSvYuV0GK3S7wZJHOXcfvu6oY6CcZtxZqOQpAmmp07AkYQjG9NmRxOqJ+keOUtuG8INaZ1lCJEqy0eOkHQReSR+cvssQy+0UIqoPGT1bYfG2yI1Oy+SQQ01vI/Op0yGkWJZv/9quGZjxFhGf/7FyMWD3HuegNux0NnbqNRWsTrjCs8dIJXB67mjMZ/Jbf11GgiC6rJrP1eMUSkpe7i/ThqnqW29fS8dHpLBFNO/WnPdXv/tW7X9tgR27OM+mnsfUyTDyHKtXkbgnuqhWqB/UcgdO4U3wF5UYHMPEQtzQ0YeURscluBHLPiVNAiRgXcTzJmFf+lddRzqmxkr4C2K+qFPfUGzgEQXJkNRGYJeOCrRfaNSXJdofbZl4J+hot7OixP5fhaiAPpXfuIDPdSwRSxfZaDcbqd7UyTDyGy6xNwtrrnX/9TwhDNkQi/O7UTHPjtCsf6sNqFlYcfQlIjyQDu3xDKaE6V0g/rxA2POo5FgpUt9eo11ojYYDLfYBqbzofG2epVFLD7Z2v3T26dQApbfOgAMyWBOJ6y3TgZzzPqdj9X4+LWBkN+20t9ENCEgZAeFv4S5l/atPbolCwPHlMgwKsoYI3fp0LeYkVUjpLxfghYQDCdczC8bgCElQruwEgX+SuWFfppOVdHqSPpViAePKODfgEU+fe5bakTU5xFC+0pc9zNURYVDS0CvtMMQutd1LBu9yqIbzaAMKndWeon9BTMIE1KKioUYsy7UuTMltgPlk7CWh88c3HvMupgmGUZ+uyJxPezn3ldXmUKaZDxUBdCsXbysJwl5Ru+YRagXVKYe2peJwkQ8KdtwVCYn+koT7Y6MMfNrRdnT4Ue9A9s+QMZXdv4knySerYwHtSGDB2d3mn5dQmNKN4kSySD1e0VPbpuNtuHh0rvHqzmpPYHCNMlgDwj5J0UGSlWK9B6D91QmpFDJc5MCwmSyxHuxjMOnCuk04+50oseRzOYR3taOzRty1MhgPBYbmJzvhoUndQApoW04tsL8soxGW0zXxlKhz21kMI9VGYTq9v3X9BjvV4sUP30A8Pur3LRMa73VNuILfKuPLv5cQyyfFhlGvPrJ3sfnZYxudtzgbKkD4QpKx+nzA0XZd1TwwDS/GS/xF5mk7/l+YtvzTD3OrTx2zm/pSuWHWGPBPatUvjj9IX55/AokGjojo0YmH/tBGQIjVq30avicqCGDkabTvazf1C/z3Z8gS39MVTai1V4B+urLMLIxyGHdEnTUQXdDgTLFzpRzn9IoS6L3lki9IUkJNxJNnZJGQtwytovfKxF19DxVNGydJHuIVbRnRYfgxtHABYFOyp2Os6X0uG+xl8RRbLUIUoZlYGUG3fWPOEt2cKptB90kPeSTwJEswnTROgLhiyA+pp7uiP0OIz0lMtgjpIbY8AeEzNtoMHSVKfiOcafeGG/oIb2wgSYShGsHCY0KVb3CivKcQkTSyV49d099atBUxw/KLvXV9d0cysqMx65zRhxhGXJqkMjXaG68ijk1Db7mWNRID1cOykBlgDuu/1Fyr6JL4FRUAaAkGUrQLe/1BJtlYGrEq3gpcjIM9g/0TYMM9gipnbMvjq0a/jWtKghtA7Phh9lrCfeLMaJIR+FTktIs0hUimw2PQhQz6CxQqKTwSeVhqY8iRH5bnK5tW58JvdzAC2zDwuErKqm4bv25AR0hqPK6n7r61ZIh9A2jSSHVVNOEHU7vlI7Ee3xwktmIz4oM6QI12+WTywJ7g+MUymCvoTE1K2IHhE+MS/qtdRJzIapYLTfEsJipEhsaI7ZNAJqYolyfBKayMHD0vSPbNzSxZdgqYxhEOsKiiOad+sA7tQbfJTp5SAPEfIrl78tQNSTOQRSD9F5S1NK6xI85KYFBCfe3RUIirpNnH/+Ox5gu8inUaZFhxMQ19+sMVKB5NvtrHo+wmx0koe9sq5xLsiezzWRbEnVEQkvVhgDIzmAhqdTB6fkq7Ub7SlmIOGTc4diKtlH0Vk9uIYiSUx4LfWeaNrJebH1W5lsyeF+esxu4qPxA1HUoZ3oMZE48qCQgZ+038xNcodIiHmMqGQFqGmTo/iwvR3Nul4zfUL0o02R42og0YdEfjUuRlzqwsJmUYZs7ahw0qdZjHbbbXNMeT8NKz4Yg8F3mzJykMnW60hdEeOhLqm8RINNpKUM7zn3D+m7JED5hovedJl09FhppGBPnf6O1Zrqe2DR5HWJsimQILyrrP93mZHSeoTN1oxzy/xIZY2NiSRh586AnZ9Bowmv25oyDSkhtmB/ro708GAT2H1BnD8c8ihoB/F4ICyURtUbkyH1c8T5y2yjD4HPLqPdS1OKoblPbUs+ahXrOEO/0lsRPUVswFbgd9PdvSuRtSmWoq0zFBTLmnctufGvn1ZBtkqROot89QfQ5hKU0HkGMSY6tnJ9ZyiJ2G7kPXaWy1aoS2+g/hfowRdO8g/0k1XVeSKYc9gt9N5kI6tgvRcm5XJZB1XZCegi+lWTwP+rooqsMAoqkBeDHWXn+pqPJRqlvLCygKEg8VyKw6Sq/OKDqy1fk9GEp51X0r7IKpk6GLkLwhM5GoO5MGxp6CtQL/SL2F4aCZOAyuLcWmCFH1CZn7IVMMcDtbepYm7RRJCkKFFcQs1qYT5atpO8MGLWwt8gAikzipS67OgjrhfpRpyo+lEMycEg1SDNAYSCKffC6u7DDa101ahfZjbvQbnA+0h/GTMdDghq6evVeAI/pkGGkNlk4nDCK2US2BEYYGYOQ2lFvgPvCxnSL2ZJoJKatQny5glSRfpCM6Tn8EIBZvW5DzGu68fU6tw49qtI0ejibAAAPLklEQVT+QfDDvIMrMNQ0LXcy5AzT0zy/OSRD0Jh4DU8DyNCC3qMJ9mWEj40LBd1dF15MCDSYlvIVYDveCxY8HTKMNH2IhsaRAfATl36aKXUdhCIw9XvktcygNRUXXg3fynrplf5TzLjz/KevJNrhpKgkiQd3KOZZ7wt8+ZUR2tFJKs/hUBvLIjxGBBC1PNo50WjJQEDlnOhmoTcXMC1mV0gdSXsByLq+xPpFYjQ7hVl2kiFZtHU+PTJ0f1IrhTXfnVWi3oHmdYqvDvYuoNoJb7xZKlQAn+gQc6a/Tml9hGV/UWPQlx+UnrH3DtPxp8mm+nIGdJKnR1SMpPItJdSz0M99hDEXa2sOxXJovWxTQ79JBos0QAAERdigx8LlML0BCmJO2NsI/A/q0MqdDK3zR73HozmI5Xr6YMpkGPUdi3aJRX872zyZCbEihYZwvoi7ELUjglQhutoX3Vex1bsLtQtb9lIP6RWKFgF2KY9n5KfX3GuUFJOJHtjRvgSIRy369ApbuUaXrAxNMStwhvmcxHotGeLhNTYqOhIjzqeQXlVvvDmGql9ewYl/W8+qNMXpfZd0XolTQB3zKZNhxALYLYV4MxBJ+S0JXMddw5t6MKdZth1fnUaIceXTVyHicprWZweJSuT/qV9Fg0YuXz3b2xu5Pl+GNpX3EA14/qNdaVqk8hqPGeKVXy8S4is41IAMBgzEei9t0DKhe0Qvr7roWFv6HCavaohJRzofs4ip5ArJJj3WzGGmSIaRFuQDUCV0VEKua4Nh4cdDpa0eOQcuo05YpXXP79uJSL1HduWKkEiPdVgdoXcS01groW8pJJ/xJUaX7Zp3rTuTdT7FlJ8c0dUYnQgsPzma9tMyDJIhoLHK3G9RVcLEEzQaoEnvdk8IBgMrjomPq5F2gXupSAkp0rTIMLJyerO0phyKUXG9l+k7UodlMBIZA/WDAZhhs6dLcICShOC8X8OUP3zCTkl9copj/RTnK88/aK7SDZSXF8CfIixe1rGi/VcNFjWTqI8ggwi6Z4cdAUMqsI0MlmqJIObw/s1X1Yzh6JfJh0OUtu+Rql/s2G1z7reSYE3TIkPYqealVGtYaN2W/negZeNKfamhtATkEMoQrJ1rpNA0SyJ/EcUpFyc6rghhe69iuWF1tWLjmB169CSKdX7sPDimZ0cAJCxL11mRpRdVz5YKFZfP6PVl4MvV4o4nUKPIYNXRlp6sheqproVk0H9IhnyJ3w3FZLC9faQpkmHiUaNSFI8DOhcofL8hvEkj8WvrWQdeDSrWl/fd2ktwQcmJeFakfFIKZ80CD37Dj434RBqsNK8I88gWzeA0kY7/dOVIvS8gWYkey+9Bri2D9tvTFzlS2Ak2Nm2EQj9uiMR/CQ3pa8oWuIvWGCo9oBFFpkeGkaFpNcaMnvpvoRWAwBjx75NgqsLRIeWAapT6MJL1qEjI0SX8pRk67Be14RCqyJBy8xBXhegm2Tm0FlKoZ1MaAbRO5C90+v82dyYLEtsgEBX9//9MDlYVDyRPcov70tO2xCYo0GJPTrkkbgFPyUQ6nddVhzVKjDl+Vz8DX1LtaXFxh/yY17cL4M/S5kp/NZ/8mg6/CqQ4oqs9tQTU9PrvDcjbeLog2PTmc9KmWB2Dm2xvKHS5mtWnvrBkyr4MHAsR1V6TbLwKRjk5WhZ70CvH/MKlEJEpuBTbQYIrUhynWmN/0cE/O3xq9a9xmjGafTycXcnFJR6Ct9lrE8b8Uxlf9JvbO1Csxed0+M0I08pA8S53laOGFM9rFUlqDz37XkLebaxY5aAyqsoe193JvLfa0qcM1VYMbC3dHI2zeF4yjZ0Z9uL1MfdvDt3DewSb20nf0pXjoINqbbf7poNsCnvwhHKAVr1qRDaWaCVbHEa9gTPgXWis/1PozEVaJ3gF5PiaDj/WbtpRTgsRQKutb5cEJc4ZHEa7ll1Wja+cnenx+K3gW4sBk2ZQ9I/SwsyBICtWHbDbQS1BBwhLltyBqQzolB6xn61eGxwe5fSKmKTh+dm8iXyct3ke5AZ3HTj5rmdXJvyGZe43Rjk603vLtBScTfj4Ze0p0Ede5s8m/DUdfhpc+9UlO5tQTx24rswitK3BCwptNF24v3EghiIHn2j853HfZPZhxshG4f4D5ZNLTtCIPhqrbRQWw0IefxXdPpHM835DvQ0Kl//HduLt8nzr6R/NCfdIuNSrPtzslO6v3qtQr1+FiZBN9pr6NLe4BslXdPjFduZCTKWdaAOm493K+CVpzzCMUq9QtbKkDHPsXgakI59Y63kJVSKPhv+uiVxdsz5EDZdfkLdZRYftIBcn7JRT+mPwuKPd+8SlT7Zv/60susei+F10EDiMKGmlu2guOdoMxmo2TzA3J83EUIWrglVNSj9WAubnm+cU7kM6/Co96ZDc8iCnWmqTLJDOtjYtmUytVqFGwS6QD7Ixq8zE0JU9UaBv8GTr5785P8kaGGU3yuGDfUSjxvHRw/66AwiJHE3TCY9yGU0xb6ll6p5p3nQwoGTXi9LGwa8RtIwFiqv3vc21dveT5qlfSxHT9mt9ToffPJO+aW8QroERAgejSo2VD49sNTY+dHRaS7hcRtBqTTxn1dsJRykrs9DIROcFBMmEbacxoLNlxwBMRFeG9AXc5CRr82iTtu3Ix8se6ETQw/ekg9u86aCMtzOOAU7dOkil50/kdwlA635e92pZsNHoCAB8hldyxaXPd3T40SHaHN22V2pRPySdwHl+OtGqtmHm6DrRYXeodBhnMDbQBb0zKS2t5hT2og+8rx0XhnA1o9LgBbIaArP1q9vU13PgRwgpMCTecy0q2bLOuw6NsXTv0VxcXPJSl4tzNpLZYt7lyxGY7M7sIIkAgrdB+4gOvzorzlscOKWLDVDa2V0nsYtuULBp1b/XcoQfZRf0Vu08A8Tp9irDDg6k2VyrJvTbYG2KQFub14V+9n5DlaUgfwIcNOaEPxTAkxgi6qLDEGadjqE+lT1LMXSbPA8ascpGc2nzr+41zpXBdekls/zPOvy8BJnacFurj3JFqrPEDN7mnEDgOR/Q/cBA50bU4eC3pYhWikwUUM0/ZcI1b3St5ZWM3M7el2yJZp1XQ3rYiQf1qjUMJXWbnDwjNkAit/2s26nDc4EOQnn4eUPktW4R3UpN0Chwr1MGt0/1D3/Nc3J8XuFLOvjNfUazFELCGS7O8i5rKRUT9ZLCIyvFbLMKmW8ZceE+f1/qSB++WyzD4uyySxSuQtW38qaOep82aCVeS8fPxXLk8P92MOpLX/LabwVxWfaiwzk52c+jHBK+fc7+NxAmy7bax54jC1TVwXEpxK/r39HhdwLxPsW5NzrOg2ZATv69eJ+/z3quC4rfcMaK5NyJhI6qTDYlB79NL7aMBcBZbVlYultFoF5l4kZ4sq5lIqDRTF5Ceq+gyLfnhHnIxc3INx2a4gCsY9WN2Yd9acSmxxttyYNB4mLEy3WWTNdK6UM6/E6wCwAW0WgHBvllpUKeJ9EANsGO33e5JbyrKp8VqkjLjBZnMtizAgbjeHlyq4CaP5itFHgWgMeyRQ91JzNXLARhOLsGArOCYdtq6XmKsrmzFuSuTHnXofqWPDlG/ylNMI5tskQyApzK3N793fapXeUyQ52NxKJACVt2QQ1/Tqy/o4Pf/k3nKGconol7D/3swqBMakjGFD+DQWnRqRYOCqjlufZmAwdP2Aj/Kc1u2ucp05LXdJhxDuJZ6NMWIBCU0K9IxnDqR47jwOQrnK5mnyK8bdWIz3G60JwIev0UZqtpRF09yuPdp8hWEGjDNj+ow88HszCBfH7WyU6P8wIVSrh/VinVn6nu7eR425FfIt67z4jsPJwThprfRCtFGAKn6vfo1oGxqKdCU9cfZJF8MWwCOUUnsMM8UWzfD6639wnOXYd25Hy9BNB005Ix26XpKmLZafba/tJneGVva/RYsfqJ4q/o8PMEEKjmrK2o3n7tgG70y1XKJ8vJ3Jx9LtmirxCxxltLKbfNvbBKJUO2Mm3UgokjyrW08yimt4s4U8FwyWvZlZ94mJRLRtvXrs8JzG+Cyg0Epw4Ifr9K9M/Pv0LoMgCITQOYeYar96m/3/jELmnhLR/T4eeNDoSa3ox9rDZN5EuOaQ60XUvlDB4YO/URb6PtumYMplzfoG2ZstnM8oyn6rDUF+4UrY8O8SVsoyCMRnshWcHpo06kBuY2teSItAaeLp0maEwd9r2c8rSuJFKrXXM3ycHIxEp55lNu2fB5fNRnXM61jGojqXxFh18NxqmcnpXPzQxf+0cFAVdRntK8BtVr6eQygYSZYqaXLUAhsLSh9Xo/G8YCn3IezJFwrN9aBgw+8ESbtM/WNf40nMIQ8wZn5L6A0PsOHXQPZajkk3MVniBc8zS/FdVLrVuZEU1+b5BeDbBKhxh0Ytjjgzr8NDnm8qqe/6otdD18EX7UNPdgbzzU0B686+k33dqO3KKz3DDLWuUsu48Tx6UmxM1H3m1gz4EQ9MlM5iAqzrWa1DMVjzfXnRa11XijYQ3mqevT0ghycTAM7E0H2WW0D/GzAxJ+5XFZl3Zfu1uin3u8ZINbzX9tumVtZvqeDr9EuuY9BfAeVyilUkL0seWkJUIry5Ch40YFYUoNtOd8QrQ2bbpt62NDVFsv97n5Du4sm5k34Sawa59Ws6KcJZ2zFwNy00eZlLQ7kWOtMUzntVcdYIP+95CxtSEdyZm9L24XygpgCjznp6Y/db+1ZFm8SPc7OjhD9PSCqFjp//6YCoQmm3LHEDz7z0d+eB1KmkM0rboMWikaMS+uC1KFwKdI5Bys7ONTwLOXERMZ7mIfDEIf5z1DmHbiICJTRCMgE0QF5h86nMY7P900zMTg1Zib0eGUWnlMLzOHeYyVa9OisxYwfFOHn/7zCksmTSQfh6mNupvcEo0oKn2bDvQOtLHwdOqWkdLt+oNGCi49OAQBs2gCRDbrLF4T9bt9KsMUhfNv3obx5+GxME9mycDN6PTcL/7QoRmrbDEzOmmyDp+fPmAblMZNrgBaiLejEo+B+Wx4wwST/Y4OP092CdxbAMmVvo7DaJv+M0hRKFf+e9oGjJpz2zmnU8SwBOkpCJhJmNlIm4EWaBfjHoJl9m3pBlanDi1TTf0QCMMWXUbIM/tPHY7UghJRMkzz/YXGfyI1g3cNh3rr+B+Yf0yHfwAjBO4Lyccm/wAAAABJRU5ErkJggg=="},{"id":"DigitalGlobe-Standard","name":"DigitalGlobe Standard Imagery","type":"tms","template":"https://{switch:a,b,c}.tiles.mapbox.com/v4/digitalglobe.0a8e44ba/{zoom}/{x}/{y}.png?access_token=pk.eyJ1IjoiZGlnaXRhbGdsb2JlIiwiYSI6ImNqM293Y3Y5ZjAwaWgycW55ZXFncHk0a3QifQ.6Kprj_J4oDmXqV97RricwA","scaleExtent":[0,19],"terms_url":"https://wiki.openstreetmap.org/wiki/DigitalGlobe","terms_text":"Terms & Feedback","default":true,"description":"Standard DigitalGlobe satellite imagery.","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMQAAADECAYAAADApo5rAAAgAElEQVR4nMy9a7Bl2VEm9uU5595bt6puvd9dVa1+6k3rgRCSQLKMEDCBAHsEGptAGE948Bgz88Nhw0w4bBzjmBl7HDE2EzM4PGZgAIMNNkYEDKDBIARIAoQeLSG1uumu7uqq7nq/bt1b9738Y6/M/DL32vdWYzw6u6PrnLP2Wrkyc2V+meux95WFd31fAQR6FdRfRYuF7ujvAhSpdQsgUusLSikQ6e6hfkcpKOJ9AIBo/VBaINRfqd8jd17Lf8HqgspCy8pm6K0Km4pNCYUqimQukHrs/mn1kcuoi979QNsGo02rRNVXjTGf3e9ePRoj2bZe/Oz1a+0j41omLR53+vwqyzBqDoR9casohe6WTmrroPiHVKcA3BkgYgMsXN9csXT3itBNN+lKDp37CUSZLahKIPrGp1FGIQYLeaBIdWhSQnGmjIoqXukYYIQr4IoXCfVPl8oQnaEow/qBUoZl0KZhHKoM3QAL3S9WjwGro+P1CtHLn8a7lhMfYgXFxqtU+mx83m0JKpsWGUadSZCFEdNqHGrodk+otoj9dmSQrhK5paKx+5WQkmpLikjqG2agQrwpkmQEQHHe2AZL11c22FJxxepKsahVTCvFBpadjEe4pHtqyPpbqtu5casuitdXPs2r6XNABuOwqB7EeFMDLUX5T9G4Wg3zqarOZd0n91VcBi1HB2gWu4WjqttXMGiZPhlGqKFGUFCKCyAiHpoCDyV0CL1vdat5mGEWQ0o1GTKrDvOLO5wyZ3XFfN946OxCjK7dFa/p5WpYETn0rnQj6b/pm1LreCjkky6Dyizqt8Y3NJDaIIoAUgqhktQ2xXkWgXDvso0M4nX0vusZNeIqx8S/RnCAxpiN1cdd6Qn15WMSy9lQAv8SywKETJkMk5hjVRhns0ioChLUWfLymJu5ZCWTMWQWiFDmKNRAnaT+o4KZaTBzAsCpIJp48Win6Z71UarlKiB4lLDhU4dlRDNnrTWlmMyayypN0xWlj2Te1BOXlV55loGCB1AEnnGqx1XaharTgMd8Xex3Yd2bIgsNIkd3Zlvp+fxS4dZl6I/rNMkwcu+IA9NLkY2MG4Xxqy0FYaA6BZFwxjQRkxgzDHlpzAOuEGOOIqlOjxUx5HUfLarnwEPEMUIym8go0zQIhdsb/Ft/wTlrbsCmnl2CuShlWIYuChVjS5iizduU7443Q0YNYdXZu2o+mKZ7YVmE+CpG3/otfSlQXIZSaXCEmDYZRoZVRf9hB+w80OYTNFg296Q2yrCFd2png671henVT8rVJd9TmpQWmYqkjbU6Go5Z8b4k/LKQa23E5dGvqkDTDzwkB9rcR5WNUjPWSXFzCXqSUjq5t5FB5xYEZZZmaWTLE0udbzEGampDawrk28XLRdOSKoP4yo5Uw7ZITuUC1R8h+BTKYKtMKkkpahQgb4rLjm4QnYGqpxvcWhsaPpvEqNc7dGqELKpFSih4IspCRkT2ZVZH1IhIpVBkMqJdiFXa6mxhibhEgCqmJ5gzMYqXGgVsUqd9WB4pKFJCVGFJTIaqVNVZUwYwcKH+Fr8tcOmMp84xi8lF4FV1qfM+BzafT6LWs/FnHmiQOHXuutE2KoMvVkyTDKMSDN4N33cB1IPcpW0gCQn4N4qia/XsoqHKL7M581oPaW4c7mgWlUqxfsycKFTHeYaVOu8WSqSmZVrbhikglcGOMSz24askhfrs2nB+avMY0g3zWSyOaAPPi/uxkgyFFV89t6gMjmqdsYlYWqxjY3pQjy/eq42H9ekg5cjqJQrVtjonJcmPYEM2J5syGUYRo/qmFASAV+N1cSgSFL4PsrPCTcElTFZv6GpXCDpmbtFhlIYqMfCMzoEUDTxgEYxBEUNqyiaOOEazGMq7IzJzTK/v0DbxE6mG4sut+VI0DMg6IIONiVYW3aPxSMLqdYMszrJryhkm3hQ9LdoTYLJh6Vexwff83xYTGFegwDBdMozisPiASs9SYzWhQVPyERWJxwaDlnblcsDnC7nfZI0c/qIRuw8VQ66WECHOOF3h+s4k79h0BbTsB5UzqjnL7OimDFbdpVUM5mBIhhYIUG91jNjJ8yyk2DiE4RbltY+ongsGwRAm10a+OOFk5NMqwygyuY0TmIwlerkEetYDCxrNqLImbQQw9Gv3Hipq2NXvITwCKGqw3LqDXRRDsk4IM2jaLbfAbJM6Rxb3Tv9lfIU7ceIehyajq0vOSdiQDApMEXQKdFM0c6a0HECkjkMySbMXDvV8n1d6SC8+cTK9NuNgBbEyhTKMAAR0yrt5bOh+fqREaIeGP0Vm6Q94ECcJV0os5VyzytIJ5hl//xSU/6tteMXfB6nUsOwrRVJ14ImMt2N9eE+KVjqgJEN1Nkc1501qOqD27BtuQm2K67UgGlWSgcvVSHgu6I7E+XgloTNKINSzjnuLJUzH2WmOMKcKTRkqSEyhDJPKghOtlX0y7MR0ct1tu9OGCC8poMTJqtIA7ECf1hfycFUSlBNykpBiwI1KlIdKz42sJnSlqkngxk8TNRRXjq4C2dyuis9Xgdkv2NhNbwWkbFqxA+lSvF8bDLYLEK/meEMyIPZJ48TpikCoHf2GL5Z0KYeYg3fD6vf4CnagSGv5ry5FU59hMk1gS4qdFhkmmiJ4B13rEoh42NKczp0BPriiNWB1IWREDSYy/dI1NCq+XOdKcxRxLWuZGxn3VZXFDieaNhVXoonEjuIDqW3jwIRRNd2oUUBTA9aMpD6MHsU06q+r05ehN80Lk7ioK0/FGJ2ZHnenoMjjg6BzIZ2bBnjcuD7zZW3b0eWrLcOo1I51EIq4Y5TCDWH/x3CoaFaoAoECexYZta1G8ESp1ChSnBaZMBSS2U+L1SeH5rbkqFFvDWcoZJwqOzm+NstoZgfPDNW5K4kIWmnyGR2PBLX/kvodkqHE76IRmnL5YCwl9uX0qQ316X0orOvvalwl0Tb5uu/OB3oOzuM0TTJMzJDrgHW8q3cxQXY8CUKyxxeUcFjPxjVHhhbipggTCEgXxzR6ZMTkf912I6VSFcHHVTzb0xUjR6EYJt1xWmkjy6e5a754taSjI2ZF8QiN1yWw68sgPAg+dlL54fSMQ2Bh/iTYh6vcEIpQXulqDKzMBTWpjJnxMA5VR0L1p0SGUVjXr0ZJm8gKvh1fZNwaGbRO1IdE5uBe3ZtwgYRtas/BQFR1hOjR6xEmyZkOO5A5jRq4Cql1FdmpXx8TdT93Q04PRPlKl9HT9Eg6hMoRx/pv6KKX+lX5ewsTia9sK1wQ+lJ65rwNGRRxVX5C8yBDQwdBNp0fTZEMI5+EOsfOrA5AqeWOZiV80vhz7s36qRZVQA4n1huCYyK3C/rkc3UdTa5j6V9r74F0o6mWsiyqwNin7266VzqPHDqJrvhCxaCfD5T3mjRAtvCXCmIZg3oT72wYLcsDbPyCEWZeqzUWBSIzAGfE7K3Rl+tNpk6GkU4EAfXQevCKiOlqfqE1ehWMHSmuDFX9FAqKhdA2y6TGWb3bEKCzL6vTob/fK+m3nXy1eVB0MQdyGgE9MUmIzwos6bvzTu21TOrxNfOHfqQyPgY81lPVTqghGdhYfKmbeVZhQYPQl6krCK1DX7pnEOYEKqNUYpryhlUdIXouT9z0nS4ZRqUaQuibBSNezMq1I3o8zQzMmGX0zIwkQzUjU8VGYYLnp/xMuB/Wv02WJbZlhWnqh9SWUsJOLHcudlTSq7djnjhFrPcTplg9k0sSbcg2MqheiKSlLamepEmnokkYJ74dx9ZWdUrdrymBUlsfPQajjUyjDCPPodnAkbxYx6pGEsVSRgcgGD0vKVrHAlrGdJwtBou8LR8PSjgjOnFFdR4x46WmVR/eXidofOSsOMlqs+ogQn11ii1Eu1iY8s/urJOOJaVt6lyVX2G+jF4ylDTRHpTBQ4mnGyZ/to40nhV4er6pdAmEijpy/S2apjqxRneJttlmNvLpkmGkDGjeTOAXPiv29dmixE/YWC3C6OS0sxZFWkZNLevSbw6vsO9k2jBjJmczUOI0g0jYRDilN0pSKq8qktLU1a9uIsby1whEOpGKgJL5B3yiXWhlSu/RDwcEFd3ptGTwianSIR6pbdz3MYoISQrpP0d0j4wlTn5LvMdAp+mvH8UGRcw4vtMiw0jqAEk1om7JVIeluoE2AJ1R4vFmcOPwXu8xoheNHooCInasVxT1a8QIKzcmoLj1JxTwaEVr/6QY0jvpz4TrnBLFxoAn1CYD1K4L0Sr0DEXplmNpYqf9AtJ41qLmtpoOEK8UfJsyFK5Ao2uRjuVXsGJoSemnRd00fnEJXaJRMqrniybL4b6O+xTKMPKQxSZvFkffNa0q4GdfC+gTBNrFBzEwD0UNr1MfCqtlvoPMwUIdSesrWxpZzEGoXzVcR5Dq6IRaira2Np4XDkpdkoWQPLobXWz5Lk7soyOaMwt9NyeJ0ckjriZeMihDb9OQZeD5DhTcQDpNR28YKUrUUbhYPYy8yjvivaa3aLsplGESYAjKIFm1OUUnQVe9cwodYAhoj6gyKR2tOJjuqRL6Ux6Ll9gEUoKee5uAhMwdAhNNZY77LtqONeSbakX7oPDMRyvCBqOpwXWoBh/2F1QXLR0oLeXBb7j2ZUgGBzGmxX1wvZ4e69h0m1yk/WoCvGcUj6TY4JEKq7FqyiiIdYmG/RYnMS0y+MZcHYnOMWtoV19wCHAES14WpzbulTx54V1dUyDrM+XGcYUGFiqE7nsIlfCKF4cRNC5R9dc6XT8BqTMf1Fblstq0mlHUEYKiCVqKn6lFGPhKl6KK7CBD1FMCNdJ/0AdTEJcb7MBE3iISAZeWR4rKfyppoHnxwqmTYWTVhb1PjZWbDoyLtVXGggc5AylF4HsepFibEtpUqKTyaJgx4YYjTXXcODllXXnMZBeNS50g1GLmqW0htri/KkOvWYrMgTnlIoFPlqEHwaaugjQE/bHbLo3I/Aw5JBuojk+jGrfvrUROmQwjHizDLhGfqWcmaweWsqWOdKy7ex4JIrPRadz2KCIAPYVsf5G3MT27GySgPF7MsIMzs1wKFiyPokgH9dVXnYe0xeQfNtGMqBd0NSB6lsFCTykRmgldUSftnlmW2FblilbbY9159Dp5JznS074rR5YmUkpVpk+GiaU7EpevSs3hLa9VJvUbAajnA95JXiLzTS06chuciaAQ/bmHy196xmQQbLLAJruJbeO3lQbZ1xKL2JDtd2Y5kbJ8Wagwy2aWQQ7UAoPET4gOpXWT6SQttpJnpaOG1Uo7LK2h/lTHNvbUyLEzGCA4onPfUyLDSOoSoR67tYsMWgBbetXVFHVIB8pmTEqCed+mo0rY7ZcMT6lm+dWhk8N1VZIismFltAi3KZplvnPkUpmDszjS9M7daEN1RpIxfOf+e/f7MvSuHs8llvMKFw8EA1RJ9cN9GgyVOfdpPJMiVU9KPwHwtMhgz1T31t8pl+UVraIELM1wx+z6VCeKhtmtODkjfsbJETLn3bWUFBIjFkcBTifiUpySLCa8v7GyrixVBTt6kFDZESyVjKtQOsiuq+Kf8HEYBI5kG8YXO31DBq4fELLUPRXTiwth53rI2YbAoYTvRN/KxAGtqMwtRyAa+j28WnI6ZBgVtXjx5c2wTAp3LIsQqN5tRwzMghEkpN8MEF0jPz3rfYl3wiRp8qU2oqtL5hPVUPRepm6IzeG3OqIeAbC+WAoybr5v+xXhUVoHHMeN6Jw5jQS19Rk5bE4SJtJZBgJEPUtmTiQqG92nurrzHiJrMOaOZ4HLEPZKbFGjFqlta66vv3WsGCjD9+mSYeSTwaLwH84A+WDwD/UuX/ktwYI8ghiCZ0RzK3aDtifwJTJODNguehXIJ1pQTzFZbU+lKkaRwXfOWTAyTFYc8lyoIQPTUTLkpMYvXyWVKaspP95WBtMDkxG3RENCEsxoIfKl/h1AMSM98x/R3dpQ2uLgEA20ycOUyDCyAGHeFVFL2TdWFJqqE+QdVN9ijx3ZikKt23qAhyJiaktHd/VhCiNVopUab4kYrQKECSzT4r7ZUVRxvNLBY9jHD6sfIDAPQBqgFhkLBYMylL7uMkiYHCCDdecKvFi+rf9XfbJT9mQtbjucPzMdTgHDK2amS4aRepTzUpHJA4a3ScR6E3k2mEqH1+/dJwzCqePqSNy8oomFR+Yk8ZatU+h7trQwea7/G29NqwQpNtZTcZx4od3yGD1CXUFPBmG+8tWSgVILNzquS0wGI/BBD/oGnB4ciLrhChoN9bxIGJ6TgcSde9fldMkw4pTDowXgB4zgKJyXswKyqjLEfpqSgsJUcBeiM8bYzq2HvVUFSBAk6TfxY2RKUkQSQYyFDOE9pgJbmd14yM+bFNLFkM+1+OqQdECGnIZZCpn4FlJnKu+fHnUG7IAkMRwWHlywaLBZhbn+gMzTIEO3U615NwoxI2TjbojBZhIqUwjoyV9SoUWb0k1/g/Fk+k3kMDZjGy3XlaPqxxDEoxBm2wWmg6rxcLKUaPX7oAiokUnbSN3crLoXk82PnvQUY8qiY/IiO8rg7VWxcTLeHARKU/LqjOrV5Jfcno7fSywP85xalFIQ02VzafqrLMOoupEnGgXwZa4Y612ubLnsvbWtGkr67OrSQS4A/uggSc1OXK1BI5f7nRtHXNkofhYLdTxsblOYTZMZVNY/8yJNJOrGWnXEh9Iqz1VhFjirEcRz+j6oLoA6DkfXhgzspUX1qTzQ2CnvOvDqXToWDYSNfWjfrvLQQuh/Lub5nQFX8aCu6DpFMozsL3gqkfAjrKJbWaQCtV9CUjZ+ekbb0NStNxpn7Mr2IFLqIxX6zcNjb66wMN8RN8geLHX3I/gUioyRryy+fudTluavqY4PrETHVSStHpSf5WjLoJbFXaR2dDssNBhYcIUkl2IFg4Hpg1GoUFuXwdLWLEPob7pkGPHNXjiPEFsdmB7sIBE6XhxJGWW1zyBZNYieIL3Y6Chb2DmgfTCK+KOb3gcp0pSUFMh6ykiXVNFL5/hSxIOjWS+UpwbSE5d1RKjYkMEm1tq35mbqnKD+C53b0fEgtAzyljrONUo1ZWD0Ntm1P7pX8rJ1ROtpk2FkD1FUVFKj5/r8Q9GeD0VZiOtxxZ+NSyOH0tD+w71i/bqDM2wXBEMEbE7Eodj3NRCNsGXYpIPsIHl+DfCAaQdep3kgL3Tkn81B20YGizShWUJbvc8gwaz0nM2dTp2xy/Wpk2CEhPAlK9SQjOZaDpp23m2KZBjxfQD2HKz2JkW3n+p3YVruOBYAijqIxNQhyZmPJbgTqkEJ2YLuQDf0NbBKUYICB/TdNG7c1xXjI4cYBHmZ5QAbDVQLObMWbyNDqQgc0FJlqIah38NCAUqilx7cIb0rOxne/BxXR7szm7hRanUVbIsnq/6g1XTJMOpNSETozX3xpKuegAVNTIM8OmFS6YQNPFpA79yQLgeUAl6CtajYq6sMdL8La5J9zWQurhUjlTyWvvPgNaMBj7jxTcNT+zGwoDHvGOI+QTfrPeW7lEEZnLYWCoIe2Q1DaPN6hesVgzJLny3a1ojrWCLGp4534I/SYZtcSycDR/Bpk2ESxgHKt1uUljmw5eMS8Lpq5DQhFPUcuuydqBw2mSSFQJtIpuhiP4lPb0+/RFenYpiNEzZHYT5saAQp4tncKIFIEAB9HdpgWIiVrBbYkfH0eK7TSP0Ui9EU9fisFh+zr7qgMTKg0TEjz9WJe++wJhmc/7kEehpOXAZjV5QCjQd59DTJMCoiYW7byeKRQZ9VJV7JoPTgFC2FshakDq4RrrymP5Log0zr7wUWZv12MVRBQT0tqf/3nanniLUPjVy9B5LYUVgfZJUWZun/EL1IUYVpW//0q1R61pWfPA4MDMhg/XC0Cs5OTw1SdM+TyVL1FZ5TKToZJZ6FAIfmd5pHM99NGeKLkCKfUyLDKCjXWQUnS0UZJvn8ZCKi1yeF8F/q7ISqTIV8EMGa3UkIUVkIQ1AVipDY0i3d4whsU3iufHUeHerASXY8sNEqP/5uHpqAE5xTWhnb0shI6MaaSh6QIRkYnWmlIJgd6aEYSOnNrm04GmM4QjoVI03znFrRuuXnalyG5pyMZJ02GUaWtgSOg0UYAkuwXlAuaJybBoSplK6kt3zGvlgrWmsp5CwJPah/NYze3kIpMfIZi65cD6FkyJUvo+0e7H3mNrmfojKgEXXyEqAPSMt2WlfYM+EUTPlVVLVxc3bcWFwGm0sR+DB7irYuX1/XjuTZSULFXptpk6H7+xCS+kj0bE6gPznH3elqGT8LxUbvXbnBJuNS+fgzf7c2vRtEt9WY7D/MIXSwwNEg1u9dxGQ8/kw0Ut/SEmw7GXIdGsTm+Z4Buj1aua6kgh7thm5aHYb7A31+lWWoZ5mk37ZGBAH8fI5ZZAPLCqInZaVIHxE03bJq4nR0ky8YHD9uamhANDV6iNcNPLEMneDhXj7dG1CiFQkSOaMnhFitq6T/h8qH6lhISZ8ptS0DiBhPEmxfp3meSOsWqltiu4DIOUoy31MmQ3d0QyJvHWPwyCC6/+DWoRtpsT4o1A3FLWdMArMS6nCkUOZKoWcwFMBT6BOG2awIlcmQiKIAWilWLmgolsUiffhDV8k5JP0PKqfv/LjooAy9VSd+ei894iqx3HhSEEn+a1rkFIhTVdMjrRJSNhD5o5Q8dCJTJ4O9l8n5rwY5AG9qxGE7nI23MmDg5jI0nKSfTlhksN/FFMe2bO3DBKt3sxmZO290BPA+ksxJrmi09IBLi746nCAsDOx4tdKFIRnIEWn1PVTRFI1XbYykvmAipzyFnnwmskENJStFDdZaBgRucB+/TIkMtlOt8xld+rNXwMONVjuQXF58a96cApRugVdq/IENV0oxzo21sPpVggaNVtGmSfHKz+CAMDz7+ZhCfXTtVG5SnGq4PubqJyi5L4mpHcKXZjpV8g+mNSBDDxjS6HCEiZtaSpfRN3ZvGiL75NU0f7dv1bMZLK8IMRG4AYogczMtMoxCWKY3aWRUir4Ub9qafqClN3XrnY6YO0/xbyWke4qytthjYU7ApDIChzdsZ3Qt9BkmVvREV8vYggLExiIiV+6LB0mNoh0xJNlBAIMBGRgYepfRct7D3kztg3dzDY1zfqD8FC6i6GdddZXSUKrQQQe2ejRlMozoOB2UPR7fHBUKw14spBDEX4WMprpEjym6b/MF91xbbWoZnHKoLAi1oWXgoJjC7ROsULXQTwPS1P87A6AHi7TcJvrUlg09d5SNQiF2SIa8UsLOyZNCs5+E1NQuGG++1Cgk3y6RDwsJjHguQ3x0tzEPnQIZRuAOdFVJq5rHuRdLdf94jJeF8+MYPMvvHXVgpFbjUSOGb7LEpbzUjuobf/W/YDQWYViBDT4k3S+JRsspSR47IsD9CfqTdTMS/p14DDg1IAMqaATVkjHmCWsDcfubioSabIyBFjPMekD/oj5DZOQJ8xTJ4KddOXSIGzpPZEXLKxO8TR5PfLqB8GZNb23fGE1oaQNfFUZKbMzLo0FZe61LqBA2+9AwPpoLwdt2MsRB8zCgfXLo0DQxh4cUYbVAfboketZ8QAbA/o6CAxfP50rsg4U3HZdYbmzpuCVQBAKKN7A4ysZ1mBYZ6zTJMFIi9clmvymehXFOrl4eUD84np8s9MN5yZh6Rk1LaFxHyZvx5a35fl0WOKRE1VF1IzLkO+KEFLOcRm2lDhQMPDHBkdRoFOvbAxohfiBBgKH1sY0MUHQV7wOUOiQdFPhvT1EZhb1/G30RhAmO+H1jg4ytUB1fDSrOByN1iBDTIUN9c5+Ews7+tFMfM7aFkAKZcw6sN3NRAMdin/FZgELAoF+ov14kQZhQRfQv8Tsty4W5S7jvz2Ko0YpGsjTYQRZDsDq49of7GMG0n6QTcqawJKw0WzJA7aXKIFSoxGwxI93TdCQMo9IpJoIpgfzdHFnIAcz4VReK9PDHCUj1maVpkWEU6NUOunuMSuQU6mgl/SZGfQlMgvMIE9I+SupLUVC92FCE+kS6tB4J2clPCmODU4O2uQ7xr8CeQ28IWR09jmqdLDxA0fHYiIvRhB2DMefUtmE+MiCDsk23HBAqoGlBKfZL7SU4GhSX6aEd5V95DYNOjxwnnoQGQcE5bt6hd02LDHVjjislgyPgDVmCxApWR9iYK+2A2J0xhIN5GTIKIy7YPkh5JTbolcHbV74MJeBlIa0D8SuUxjEd0wNN3uH8NnlACgCipwNKiAZhNS5EiG1kqMoJ8z9VPjoDcbDQZ0OKO2HvT/4ouDAKq2YqOIkbe5in8XcGlIDMDW+YIhlGoCsgedfMaOmR8K6tDpojMz8zUYqYUKIMJ4O2VSXusSgWpCMADYdpT+JB6BJJ9xE1V0BFIDdye8DEcSnwwIYb6XBHSaeUAjKSGm/aRp2V+MkyqO96uaJgalDQjU4SwfXI9dCoJ4Gqv9jY9ocZEa2NITm1zdFt2mSYpGbqP7UCISBAE2RRkHSWS56wVkqKnFo/5cCo5YrUliIU9efqjmoc1N7QXdubAYPaWMfejhyOZfDl2u5XRGcfAG/o/bEM7sk6Qq7H2ZkJ9szvwu5ds9g1N4tdszOYnUwwOzPBaCwYjwJGYWNjE+ubm1hb38Dq6jrura1j6d4KFpdWsLG5GfVp6VfUc6k89PRpoOPgIqEdbEGjO/NWaMC0H9ZHGl8CNNNv/Wa0s018lWWYlIryMUWR+uyDBCQNTqGVzUkqNzRBNgWExyWpPdlO76ivsD87j2ZmMejYXMAcgJSl69zCfamm9Cg7O0vlzZ0J/pRfRXDlpXfmiAZHRLBv724cP7wfxw/tx9GD+3Dy6EGcPn4Yxw/tx7FD+3Fo317sX9iN/Xt3Y25mBrMzY0qdgOWVNSzdW8Htu8u4fmsRV27ewYXLN/D8S1dw8coNvHT1Ji5cuY5rNxexubkJc9IG6LCTmj7JgS2iV7KCoAIAACAASURBVB2oYal90bE7T4fpOx/lsYd1qo34imUPMxOvkZd/4zLsfdeHLbiQL8IP70kz7cvOHRA6NTC8TOhRyEj1d6c/RliiQ5PgZirauhKjtixsYQsRaTTKhZDAaK/ao3K6PRoJzp48gtc/cgaPnT2Bhx44jjPHD+P08UM4eeQg9u2ZDwPJ+zosp17haAj9LgW4fnsRL7x8Fc9duIKnnr+IJ595AX/8xWdx685dOOAwaKVPICrS9JH0m9tU2iGlS2qygc3loH45umhGwOVfBRlk4V0fpiBAiGn0C6UN6TGMYLcaUeC5PN8zhKUb7rbGYzA0oK/MjO5wdGo5I3kjNBqG28EZaFAyz+at3Lj7MR6P8ODJI/j6r3kcb3/Do3j07AmcPnYYxw7tw+5dc1V1ET25fxN1B0cZai8iWLq3ipev3sTT51/G7/3pl/Cbn/gczl28Qipgvesw96zYPxuo47UJGJDGK9VseESjfm7t9A3h/w3JIAvv+nBx4s5yvrhZZIGDUGJLo4b06wywuKOqeqhjsvEmYGOgMrqwg7RCzsA48qrU/PwcvvUdb8Jf+cY344nHH8Th/QvYv3c3ZibjQUPOBs9XdoTtIsVQm61ScHtxGecvXcNv/OFn8bO/9nG8ePl6xZN6CM5S4ipUAoy88hbycdYPkCJB/g4Dku4OWViKEHG+Z0qzMSvW5v9fGWqEiA9ihGO2wYu6zpv2QxHO+gopUk1VdAWK65NDo3q9T40d4XT1Slj5QcjOsz31YqUysYwAKVKxtshhxqMR5nfN4uEHjuM73/u1+ND734ljB/djZjLGaCRxIAau7VKkncq0vNVP6/fG5iZeunoTP/l//w5+9tc/jpt3lrC1teUyqYY5MrPOSA0Y1GWqn0Gr9YlS3+aSaIbyRr9AGq+/fBlsDmHi0LyhKLWC6DCcf3VuHUBB7+mAhs2PAaMxupw7Bp5SYBwwulC34bWGVA0gag9swczMBKePH8YTjz2ID37z1+Pf+trXYd+e3YP9b5WC5XurWF5Zw73VNayur2N9fQPrG5vY3Nqq41gwGo0wHo0wOzPB3OwM5udmsXd+Drvn52y1qSVnC8CGHEivT3z+K/iHP/UR/OmXn8Pi0r0eLQMVS1EKJCILoW9SbQI+vhmzhTgm8WgPT3xbGYWCWD+P+MuUQRbe+WENSKFG6LKUupFRzYkDB/OqdTHUKRHP34fK0PiO9r0mOmcmGBG0Ye67tpuZmeDRMyfwjq95HP/Ov/02fN0bHsP83GzPIDc2t3D99iIuXbuFKzdu4/L123j+pat46eoNvHz9Fq7fWsStxSXcuXsPK2vr2CrdxuRcdYQDC3tw7NB+nDh8AK86dRSvOnUUZ44fxgPHD+HBk0dDnzmNGrpa6dWl67fwz3/5d/BL//qTOH/pGspWhTx7e51RjspS8Kv3THNCOuf0Q42jVOMWpjk0NH1Dh1umy2vOwznEX54MXcrkHLgXVqE8ykUUyBGj8SI6kiudVcrGTLQH07eck21ztRyxE0uRIwKNTqK0zWQ8wmNnT+J9b38j3vf2N+IdX/M45mZnOlXWwdjcKjh38TK+8Mx5PPPiJTz74iWcu3gFL16+jsvXb2Nza6sOqLj6ydHDipnyaf2PceroATx65iSeePxBvPV1D+Mtr3kYp44dhCA6wk6rVXnecmfpHn7zDz+Hf/ZLv4Unnz6Pjc1NbDfPy7qJem4vYoTFjWTn3c+G8de+JBuSB+qQ6TCImpb/EmToJtWJ78yurdX2cva2UnwuFFFqO0QLMvLEqVWhWZAhvk28Nf9hMiePHsR3v+/r8a3vfBPe+NhZWyYFgK2tgpev3cQffu4pfPILz+Arz7+E51+6iis3bmNtfQNu3cLCpDSsfrMBasjg4Rbj0Rinjx/C6x4+jfe+7Q34wLvfgpNHD/UcY7srg8zq+gb++IvP4L/957+MP/7in3fzCqAPSjx+5lhWUMXNluogGRxf0yC1tpbNAGbk0QBLpVU31uj1kwTzfyky0KS6VjBeQtyAu0M1dAFjH9WtocvCGjOfoEIVELSZlBK9D70osZ0ftICoNyBdpZEI/uo3vR1/44Pvw+MPnsL+vbut6dZWwWeeOodf/b1P49kXL2EyGWN+bhazMzNY2D2HmZkJNje3sLh8D9duLuLFy9fwzPlLWFpejaGoxWwzYvbLRiLYv7Abj589iR/4zvfiQ+9/Z5jIA20HGUqxNja38PQLL+GH/sFP4k+/9Fy7X/2itqF2YmKk1ZzGJDbMDXPUCJNgpHFNWYMSbNlEa5L8F5RBFt75fV13Tafrp0mWbljwYzQgL4crI55NYg9XZiUpp4E6Gk5b9bEDraDI2n+tOzszwRsfPYv//Pu/A+9+y2uxe34uoO+txSV8+dxFjEcjPPTAMczNTDAajcwYdUe2VHm3tgq2trawsrqOL527gI99+s/wrz/1JJ67eAX3VtY8lRLeRaUJp90D6dRlEAC75mbxTW9/I/7e3/wQHjx5BJPJuBephybeXAYAz128gu/9u/8TvnzuooFprBdMQG0IoGHs3SNVN8A70WzxqcPPu9+ASNxLslSJMpJWuv1KZLCUycg3vI/2ru2bSh3cIgFFW2BULVUCNFnvXQyozTmE9g7oHzgcCAm98pnJGA+fPo7v+eZ34Ps/8B4cO7Q/IO2wctvLniyv0tBrdW0dn3ryafzMr/8+PvH5r+DStVudYzSvFC0BhOU7uh49cwI/8gPfiW9955vCDjj3v90ycKmT1s98+Rz+03/4k/jScxeo36jP3jywkSol7uOEWwZ4sQaZULJikXbV1oQx2Ncrk2E8d/aJH+tuCd3XyQ1beOeNlgeKE9FORGJ7neToPN2VUw07CBKVUZSuFuv3hlY6e5EgvIfLyijB1aEDC/j2b3wLfvQHvgsffN/XY+/uXY72acBaZVreQlytz/fGoxEePHUU3/7ut+LR0yewvLKKa7cWcW91NcqeE2nOvZMMgODGnbv49Jeeg4jg0TMnsXvXbBiPIV6VX/199OACjh7ch888dQ637y4bDx7FdOxKHA8ethAFKmwGJFe+ksNXsOOIyRmCITjfB0fRWD/y9cplMIfo2rulK/2eoREdpSK1vjuP/nYmwiD1jIlWAKpQjCw8iDDFMj30eHShI9Ovf+QM/ta/9234oQ99C1770OlgwEo7G8/a+gaWllewvLKGra2Cydg34vjiti0nGo1GeOTMCXz9Gx/Dnvk5vHjpOm4tLpsxdYsIrJPSBwX9rIh7d3kFf/bsi9jc2sIbHj2D+bnZZqTIcvHneDzGyaMHsbq+ji88cx6ra+s07Ix89Z9WxNFqbJSA20ArfaAUyCe2DgpFCJihZbU+20Y2bOLplcoge9/1YTrl7KFZiu49sAN5wpSdWZsbhTpgzhDcwNsZgNfJ93JG1cqwBrIuvTe/axZ/5RvejO//wHvwDW96DcZj3/jiiefa+gaeu3gFT527iOcuXsFLV2/g5p0lrK6vo2wVTCZj7J3fhRNHDuB1D5/G217/KM6eONx0qtal9xaX7uGjn3oS//1PfwRfeeElbG01ji6wXKQXB0q/eWj/An7wg+/Df/Z9H8DMZNzjY2gjj/l67sJl/J1/8vP46Cef9JQu9NtaJOEUBcjGYbOAEElq9CuAsIBiHXkDjSCmGonGF/gB4goU2d19yjDpjLjUkAR/BqAnaxTcwSoyn49V8CDElIeYM8H7/TgRroOe0uywRzim3dU5fmQ//sa/+z78tW95J04dPYTRKKJmKQVfPncRv/WJz+H3P/sULl65gTtL97C4vIJ7K6vY2NwKChYRzM/NYP/e3Thx5CDe/ZbX4nu/7Rvw6ledMnbz+j+XAcC+vbvx7e9+K/btmcff/kc/hYuXb9DgkLwWqt0INHr62Auu317ET/zSR/HQA8fwofe/c7DfIScBgAdPHcWHv/09+LNnL+D8pWuuR+WKkY9Qmz/8e7UpHj7L+CSIpjJA55jqLNq3RhDEVE/nrTDeiqeYIRLdvww+qQ4cgwinAaKzSCkyordEHATevj77Qet3ITQISqbvaixaPh6N8IZHTuO//I/+Kt7zta/H3Iw/D7WxuYVbi0v4vT/9Ev63f/X7+PzTL+Du8gpW1zfMQLbLu0Eyzc5McOb4Yfwn3/Mt+J73v2PwiHc3HtEIN7e28Nt/9AV879/9J1hbX6/jMiCk8mAIFysUAU4fO4Rf+Ad/G088/uC2c4fWZ6eXTfwX/+PP4Wd+7eNY29iMOg1RQNmrWYOBXFcqPQHiOSU7hZGE7D0SUO/nyTk48hi9hORQgL9/GWwOYcXqupa7SuycvFeXZbsJc2RSEjM0JAE5OGJp1CxUbnTEnpOq9+MhsI5lH+Ddu2bxgfe8Ff/07/x1vOW1D2My7k6grq6t49kXL+MXfvMP8KM//vP4F7/yuzh38QqWV9a6J9BQHMFMc9oHo7Ub9+bWFm7eXsLvfvqLWFlbxxOPP4g9837sO0/YGaFHoxEeOX0cm1ub3SaZOQ8hSAA1RULiSXVeCpbureL5l6/im77uDdi9a645z8m/ed4zrvz8qz/4LG4tLpsOGEwLj7fEHWAR7oO92eeV5jBSgTfJECIlCCDMJ6TSgNkkPyUH4cUIvCIZfJVJFH39OIHlqVVZ3bJsDLeBYUY2gYW53sTQ0D9utaty8nqzIYSoYApHLKAP6qmjB/G93/aN+Ps//O/jyMF9ALq5wVdeeAkf+b1P47/+iV/EL/32p3D91iKFKphCu76IuD1qV+tayIavdADYKgV/+qXnMDs7wdvf+BjGo1ETpbP+AOCxsyfx2aeexwsvX4sRwRyfQ25d7zPU8M8tFNy6s4y9e3bhra99uDf5z6thmZdSCg4fWMDl67fxqSefqRYe01MIz3dSCFPNkJGXSoMNO+g6yWDpr9ldxAZzCrbwBB5qL8bnfcoQIoS/EsVRnNE9e5p1KpJWikrfeBGI1FSJFaS8SRVXqJwhKAumX7v+X/vQA/hbf+3b8B9/9/sNpV++dgu/8rt/gh//hd/Az/76x3Hp+q3EDynUcj6JitTbKme9L2mkCgq+8Mx5vPHRB/HomROmpyGnUAPdNTeD3bvm8PHPfBkrK2vQKG1zMhFyClqWzqNTBCtr67i3soY3v+YhHD+8f9t+W1GrlIIHjh/G//HRT2B1dc3pk65rQk56IzbC6xXdjmpHrnMbyr4MsT+OGrwiFfkyPrRqKLw/GcazZ574MdeXe6kwKbZBNpYwyJyTspB6mweRBiN0EB0kC8cPAZlDVdqj8Qhve/2j+JH/4Dvxgfe8FXt378LG5ib+4HNfwT/+uV/Hz/767+NLz13A5qZuiFlCGs9MBcCIkSPPw+y5c/1eeVtb38DVW3fw/nd8DfbM72ou6ea5xWg0wt7du/Dsi5fwlRdeMn1pNOhFiGTk2bZuLS7jxJH9ePNrHsIM7WSHyD4QtUQEC7vn8fmnX8BTz79kwBdiAUf9CgQRkf2TT0KDnTibCMtA/YVnJMQNuAjZn84j2LeYzn3KMJ4788SPcZixNWFowqMUnFQ3Ln4swxzIBhru0RVRCw8Gh8LAGFmc5SN+3x0oDuZ4PMa73vQa/L2/+SG884lXY37XHNbWN/Dj//tv4B/99K/ij77w51hc7p4BiMck9DPvk+jg+X3jMa83G4YQPQB3l1fwyOkTeP0jZzB0ZYPcM78LtxaX8AefewrrG5vdWFg/bkThbA/xyyt2axsbEABve90jOHpwXz9SN/jgaDESwWQyxq987NM2HgE0tNBSOG0v4CgQeXV9mS63kUEIBHryAnGCrPXIwGHzWhqnHWQYuYeQIWpHpf4oXSN7UxocnS2lqgauxiHKCssQwlgEiELG5AqSVEvZdF5FBO/92tfjn/7of4i3vu5hzEzGOHfxCv76f/MT+B/+5a/i2QuX62QZxm9mIEwCTcleVmwUOTfWsoRKVV83F5fw23/8JDY2Nl1PZHit/H1mMsYTjz+I17zqFIoNRN+QQ5rGMoiOV1f2J196Fl+sm3YAkFe7hvjQ8jc+9iBe//Dp2Fd1SN8DIH0ofYoC5iQ8lCzSdjIYb9Q3G5ECRTU8yXRzJLoPGbrdKeqjgDbkROz1KzaprQwURnBzktpex5Jva1gtyowOkHlfbeOfKrwvgypqdD92zc3gO979Vvzc3/9hPHjyKO6trOEjH/s0PvQj/xi/+rFPY/neGsmWFElXVE5kqUKVjkYiRUZAI1FEsLm5hecuXMFzFy83c3aWiw3zsbMn8dqHTlekSvw0ZXAdaYqlBrC0vILf/8xTuHnnblhezZty/Ju/H9q3B9/wltdAB9PtncBCUdB4SuNZ1eSpcd/gt5PB9evgU8wAsy6inkr45/5kmACIa7jEiwrjWxGFwlREb8tRMwFKR3wZTMOgp02dQxMi2hvVuF3XbynAvj3z+K73fh3+qx/8IObnZnHlxm38/G/8If6X/+u3cfHqDeN9POqOJkzG3eOak/EY4/GoLsN2uXu33NgtgWo/o9Goe/HtwFXQPSnH8uvjoVtbW9jcKhiPRrh8/TYeO3sy1At0Urp2YGEPHjlzArvn57B0T8866QA0+BHSjemumFF96ovP4Pqtuzi8f6Fp+EPzChHB3vldePOrH8LMZIL1jQ0aLR8HUSQ2oIJH99bR9/BiJq2/vQyhndlFcWMPqRrJYt1XMJOyowyTYny62ZX6r62oaDoEn0DGJyFooAw0+4jo3qoi6e6yKyWTnZ1MsGtuBrvmZrF71yzm52axZ34O73zi1fjBD34zjh3ch43NLZx76Squ3LyNb3r7GzA7M8FkPMbszAQzkzFmZ2YwOzPB7GSM2dlJfVPeDEYjsTdkTMYjTCZjzTgxmYx7b9Hja6tOnu33VsH65ga2tgo2N7ewvrGJPfNzOHPiSGiXI0SeXAPAQ6eO4uC+vVhaXonoVyNj0+BCPVfgsy9ewsUrN/DY2ZO2Q5+voZO94/HIHmd97uIVQ0YDsVb/wSR4nlj/oWHubHlnGQBa+HCD4Y5C8HR6zKz2v70Mky73klCpJGq9yAdaK2YlBFmkn03UupPxCAt75nFg7x7s2zuP/Xt3Y2FP97lvzzz27ZnH3t27sGd+zl73ODc7g12z7hgPnjyKIwcW0G1uCV7zqlN4/MPfgcl4hJnJGOPxuHmmJ//mlZ+h3duh7zu1B/pG3/qdaZ062r3QLM5X4AgYUBgIA6RXrbu+voEnnzmPb3jzazAj48DXTvoQERw5sICHTx/HcxevOGhrBlnISFPKqRhnLKUjDMb2fciAQk5F9VwGW96h/rq2eYVrJxnCu125P95BbPHrIlGgK4CMBAu7d+HowX04dmgfjh06gOOH9uHoof04dnAfjhxYwMKe+e6dprMzmJvp3ms6OzOpr3Lsvs/MjDEzHlsas90xivFohAMLezB0DR20Yzr3m1e3aA0ZfMv4duJHRHDk4D7bQ2nyjLih6WkDaEgU5ASfe/p5bGxuYnam9yrfkCJlOUUEBxb24Mzxw1o5ZiqBExobA0vSQwDNjsmYZWwvg4T9IOWZ+xX2t65cv+f5xjYymIaMUK0UcjGdfUvX7cxkjGOH9uPsySM4c/wwzhw/3IXWE0dw/PB+7J3fFXL1yXhk38fjLjffbhmwtYmVr53u57o7bYy9EuTfbud5J4dp8Z7bHNi7G7tmZ2LIFgdTJwRHYwBsX/4cQcFTz18M850hPlrLrwcW9uDsySOYjEfY2ip2HCd1FxjrltSLPwNjgsL3j1KavJMMMWPRJf8IC6kTZoj4gftVrirARFOODqkdoXfNzuDgwh686oGjeNWp43jo1FGcPXkED548ipNHDmB2ZrJjemDKafweyltNrFSWDa6F6kOhP/++n4gx9LvVT67XcpydUjFuNzc7g8lkHEMz3JACbUF6ETN8wGvRs+cvY70eWmxFhBa46L3JeITv//b34G2vfwTnLl7F8y9dxbMXLuH8pWu4dWepeyv5+gbW1jewsraONe2ndq5THmXGncF5vR8ZisntfuTpkf8IizrUj0WpMC+gtL/Wn7z3a1+PwwcWcPrYITxw7BBOHz+M08cP48yJwzi0b29zgIcMaicDZlpDAzB0DQ3ekLFu53D3K8PQvfuJYENXlqNlmDOTMcZSJ/T1nJUvcCQ+C1kD2Dbc2lbW1nDt1iIOH1gIfOwEQnodObgP7z74Onzjm11nW6Xg9t1lXLxyAy9euo4XL1/H8xev4MKV67h5ZwmLy/ewuLSCxaV7uL20jJXV9ZiGsCnehwy9NKtQWp9DS/3p8QT0ehvNl2DpE+VWmPzLv/dD3RsmtjFgWPv2IO5kfFw+ZEhDqy9D9bcb0KE5wU5OkXloyTfE63ZX5qulKy7b2NzqTr3aDDClSiHWx5vOSuT38o3bvec1WjLsFN31Govg0L69OLRvL97wyBmru7VVcGtxCZeu38Kla7fw8rWb3buqbtzGtZuLuHbrDq7dWsSVG3dwa3HJeb0PGcJNjTYmg6dDfTpULgQuWk4OMhlyhmzA2Ui3SxWyoltovNPKzv2kTPy7xfeQwfHvITocaTLPuT7T2e7aLr1kvtbWN7rddYsC6AGqcOznJVjli8cBwG0zvj4/2+k51891sq7HY8HhAws4tH+vHVsppWB1bR3Xb9/F9VuLuH57EVdvLnbOcuk6Xrx8DRcud1Hm9t17KOk9UaYCRf0QZDr5exHT6qR5Rj6EahGo+02T6riTOZT7Dxla/p7bDA3CTpEgXztFnJ2Q/H6ixJCxb5d3D0XS3H/upyX30soq1jf0xWce6v1JM4I10wenVH2ad5b8LFfms+Xo243vTo6Uo7RINy964NghnDp60O5tbG7hztIy7ty91z2huHQPL1+7iaeefwlPnbuIr7zwEs6/fA0ra+uqxdq2ZjthbtAV6n7FUHbmtl9Ijx59zCGyIQylLa9kPrFT6tNCmFZakem26AwNTL7WNzaxurqOLRSs1ZcQbxVgeWWVHs6J1+bmFpZXVu0FZXyNRLB71xzinpdgftcsxqPuZQRzsxOMR6NtUVd5L6VLOe6trvOow/JnLrMg4cuc/gwwrK6ge0IwZwCtyf0QKA6loUPtW/1wO5FuM/Tw/oWwi765tYWVtXWsrq5jZW0dtxeX8PT5S3jymRfwmS8/h89+5XncvH3X9VGq3CSrRQX2HNJHbVGZqf/UexNmcMgpwlDvEAVy9FCF6Juvu2MNW9jcLPZ9a6vQvYLNzU0srazi7vIKFpdXcHf5Hu4ur2Dp3hqWV1Zwt74BY3llFYtLK1heXcPK6hpW19a7z/UN3Ftdw8raOlZWut8ra+sum2UXldeMIr3ftLTBk7lUv0mP2s7vmsVkNMbs7BhzM91G4/zcbPcsxPwc5ma6TcfFpXv2x05aaI8ez5w4138KgkHkB4XuN7L+Rept157LWvUm4zH2zncvcgCAB44dwuseOYPveu/bAHSAdv7SVXzmy+fwmafO4bNPncOFyzewvLJqY94d8c/gwU6Zogrtm0xaqZFeGUXyvdW1dayub/jn6jpW17ult7X1DaxtbGJtfR13l1dwa3EZt+8u487dZQuPd5bv4e6SGz1/bm2RAMq45s4BHXv6jsbYMW88c4g1JwbiI4hu4XD06crtfUC1mr331vLY6E0FWr/g3spaJ8Ny7MYndeg7F8d/Bh8ba9YNqQwsn+DQ/r1h7IZSvu0i8P2mta1rp1Rzp371+8xkjEdOn8DDDxzHd3/zOwAAl67dwpPPvIAvPHMeXzp3ERcuX8eNO3dx4/Zd3LyzhI3NzToOPMaw77bJzCkTMwDA0Hfp3gru3lvB0vIqFu+tVKRexfK9FdxZ6nK/29XIby8u1+W2zqiXlleweG8Fm5tbPmBsc8aYl9mkyX5zxAG6P3hIdbINBroRxYUJ50STjVnrJf+wolq31MHqoXX4Y45RyDDuLd4tndWIFKMTy6CH7F1ZtW9dfyE8OFLTEga2oblgjvhL91bx9PmXsbK6hoXd81jYM4+F3buwZ/cuzG2zHzVEL/c31G4oTcsynDhyACeOHMD73/EENje3cPXWHTz74mU88+LLePr5l3H+Ujdpv3DlBq7fWrTXiZpy1OhKweSzT53D9epJN+/cxc3FJdxedBS/W52gS1/umUOsrK13qwFZmIH0w+zNxq4OaEn12AgEvmFDuZ6kNi1lRi0C8SQtaqiMWB6QGoD9DTuzs2TN4s3cv1iQyhchUFz37vjKewymAlCfLRlQ+uCgOk3R7uihfT3D3W7Sz2WXrt/C//x/fhRfevYCFupZM3WKfXt248C+PTi4sAeH9u/FwYU9OLCwBwf3dZ+75+fCqeGhifzQ2LXmotvJMB6PcOLwARw/tB/vetOrsbm5hSs3buPFuor1wstX8ecvXsKXn7uIZy9c7pZ+TX+CyQ//d//C/tLNvfqp+TYPtCNkh0T6+J7eMsbyoLKP5IHrlZkaYsoAOOrGao6CLW2qEYUUq58aSeYF0ab8KIsbrw0OSq0X4d6QjOmaw0lMA82xHFQiiwMymLMR6706wMzMGPvTXzxqrSYNIfTS8gqev3gVTz79gvdUnXMyHmHXXHcKeb6eRub/9y/sxqmjB3HqyEGcOHIAJ+3zQO8PUjJvOaLcT5rXkmE8HlkE+bo3PIq19Q3cvHMXV27cweUbt/HM+ZdtLvLshcuYPPn0+QoqES+FJhqsbQ/UA2icr6YhDhhwrd+etLJzUH1Btt50T9Rja5nE+4AjLzt+M5WRHhk6t+nshkFRRJfEm2rX+ZZ+h7FtUwaNSBkwvO6pIwftDeHefXsPpHUtr3ZAaWouzuL6xiY2Nldwd2nF+SHHH4lgRg9wTsbd90l3LP/owX148NRRnD1+GKdPHMHZekLiwZNH7WhQyzH+IjJo+cxkjOOHD+DYof14A87gG978GnzP+9+BpXuruHTtFiaWtRRf1iuaUpQSUmyzaRo3ixfxjQAAIABJREFU71+Nygv9XU3dZy9MQvrGT8yHteLmKwp3+E5lsW8dWDVSlbm7achPRmVSGkk3ZJ/z9j02/LkAVh3pUtMj1UXvD8WYWFkGvYEAGGYcteDxV53CZNx/tqO1qtjSv6bJlhGwzhKPqGOKKsNWKd0S6upaL+159sJl/NEXnrG6CgqTyRhnTxzBI6eP49EzJ/Dw6eN49MxxPHjyKHbNzWCmOpR+smxDMgztr8zNTDA3sxeH9y/gzPHDvA/hw6UpgaOYvu5ePCcWGuyA0LTioYxIiio0mPkYeXA2TT9UYSW+/a0fDkwYqstpkW9u6byaJ54aJ01hltZ4WtRLZdBfXRKbF7B+SvdG9KpPm2/xokFI/2pqWus3ZTD+NToUVyPx/+jZE/aOqE6N2+8xuRq7OjcXl2xjzzfElUYfkX2cq/6IH6kIIDRG2NLHhQXAFja3NvH0Cy/hmfMvB3DTP3559sSR7v962vqBY4ewsHsX9u7unqNZ2L3L5i7ZCXu8JmeZqFYLGaYasw1HUlJPeRzdG5Mlcy6ztr4K2dFyHX43kRmxstukh16EsJSHw1pehrNopmmImGN2/HF/Ka3hUFHUiI35Ss9cpt9ceTbStX6cwPVkCBFWn39nLy8Fr37wFMbj+Cqa7XLzXH7j9l3cvrvkPChYBVBh4ycZlB8FsBBd718GQLC+sYnnLlzBuQuXHagAzM7O4NSRg3jgeHc49czxwzh19CCOHNiHowcXcGj/Ag7v34uD+/ZgZuILq61oUh8hFe8X1WvTpI/MJCC8DyAqAlBZVjIQF0oyUhWvFCavEIQcnD8ZsVqeoQZV+cvOwOgfUyyE9NBQO0dEUq5oH50lxzQP6PUddAJSNB3ayc+79+ZiQn1TlFaNz++aw+MPntw2rWhdOi4ra+u4dvMOVtc2+ilzYMdcnXQKFNPBMA7tJEPIOtCvs7a+gedfvornX75qdMajMQ7u24Pjhw/4w2oH9+P4kf04deQQTh/vjpEcP3QAc7MTk3li3kwdSOjUPwoLY4ZIvGsYNAOXlB5FZfqKSuxLHdTuFQRn6oFrdlCl0vqbTyxrcEgtQ7U976WHotUwLZ6K85nCSCMKKaBWtA7zGO3H+Q7LvT0ZAjsIY1kN6aEHjuHYwf1RL9I/umGt0qT17vIKrty8XfvhQdcP5c15YmDK0QJZl1GlTRkskS1qh93SewAp00X3ZWNzE9dudidrVW+j0Qi75+ewf+9uHFjYg/17d+PIgQWcPXkEj545gUdPH69HN2wuQGGPeLI0kW+kCvZ8h6ZalvoV30vQ6lVAdbyewRUKoyyvAi2ykXaV2oZbP4lWnuOE+QKK/ZGOkMax7HWAt412zAN8sAvUAIs7otJj5wwRYhsZQiqm95yH1z18Gvv2ztvYMK/6PadSnFLdubuMl6/dAlmJzeNEFBTY6RNiAvwn/XrgYExvI4MEA9CU3pSCuACCIGv9AaBgq2xhcanbU7tw5UaVoXs4TpeM4zPV2RmQjc64rUZCp1YDotZ0B2nFhgzaBpel0ElWcoYeyjIyVT7CODDZzL6RJDQ2unEeI6Ts3nPMmuYY+qV7WqQ71tQHavRsmga16e3FJBkUrNwx1WDqmIjgTa9+VXjeRctb3/U3G+O124v1XJXza9mgHaWmsbRI4M7cS69NgJ1lcAQA+I9RMr2wqNGjp/XiONgq9VaXFq6sreNmWcKIw154k0bgGjUXFEsVAvRph6XUkJiE5xDISjOBnI4oP6VUbWkOqf3U8nqv1N/FQlm9Vw0qDgClAyA0Np7Y+Ao8/LszGB/VEGIGlp2mgP4IQmBD38xnLBYVraYIhbQ/IEP3J6cQh8LsouDE4f143cOneyd0+eLUKciH7tU6V2/ewYXL16uhueydVorx7gAAu6O+oiXGG/3NkZ1kIHRKWy26vFtl6NVzeyk6DvchQ91VVxOnQWclATaw+pC4MmNOot8buaLPEYQEd8P1e0KoLoGegTD3UcO8fap35TlLQq+Od17ZoI+MdMYLyUQ278unhFSEdIaeJqeSc7nMF2s7IT2UbWSIcyR40K2g8vpHzuDsiSPB6PkzO0JO91bX1vDn5y9heWUt8FwbOI6Tgau+LA1Vsya9iYKnYEcZHAi7fhyvGHw8TbdxKWruyrfclwyjbgGDI4GPmr2WEoCuiXsa43Qtn/bKwTGYuKK2GnKeKJozEt8qtAeGiLqwNmmtWX8T6quCmNXCfLJsJX3PUQIl0kcXS7r77DgUzYo6COuF+lGnKj6UQzJwxDBIq2M/Ho3w+kfO4IFjB3tzB54zdF1K7zcA3L23iiefOe86rvKajYS3DSONmY5H3jOpsguB6oAMzIuNS0nlqjLWN4GqgeJ9yjBSm+zstASCYvHHOQlKC06hCqgEegPcFzbMNANbEo3EtFWIL1eQKrK1ps65KAGYGwlo0w1sfL3OrUOPqr5ZFmTIjlkVapNpLSM8UHWYM9HNIRmCxsRrlFJw7NB+vPGxs9i9a8544bEbWnplvheX7+GzT51ToaCbs6IvJO4hI+tL+wqwHe8FC+7LwEBFOG1dsBshfDd0DWB/PzKMNH2IhsaRwRGkQ6fIhpNyoQhM/R55LTNoTQWInVJZL73Sf4oZd3/+k5XkCMhRSRIPbiDMs94X+BvJGaEdnXQ+FBYjWBbhMSKAqOXRzolGSwYCKuekq/PomeN486tfZfc4Slj9bdKnrVJw7sIVPP/yVWjEEusXidHsFGbZSYZk0UpvQAZWgdC/+pXLSt/oEhjfnwwj3fSye+YAyl004LhrG3M65UztpKdwZYQHgCa+xYRoISz7ixpDXU9H6Rl7aJ+912RTfTkDOvkrlrbQmJXSTcqonoV+7iOMuVhbcyiWQ+tlmxr6TTJYpAECIMzNTPDE4w/ikdPHuxoS9x2Gdqf52trcwv/zx1+sf0qg81Y7cSDxyEaMcmzcpV0HBXa0fkAGjRLBFgqXw8a+k5H74zZSJ9L3J8Oo71geHYrob2ebJzMhVqTQUNKIsjN2dkSQKkQ3h/JqcGZnGkprOxFaopN68KJQtAiwS3k8Iz9ttNhGm8lEBwy1L6nRlK0z0dNVJCsLwOK89TKkHDW3kcEnri5DQcGBfXvwxOOvsjebuyo8wuT9hlxvZX0dv/XJz9NUJxp3S5zed5FoBZwCivPQkkGjhPPmNhjmPgE8HRQ1awDwimRovA9ald8NqJhnwTw2CFzHXcObejCnWb77KrVuRHNLXSoRS8tq9GDlQLIh8P/Urw52I5e39EXbG7k+X4Y2lfcQDXj+o11pWsS5USGabCKFNuGgEV5hhhxqQAaPqDwsgl2zMzha/9jk0NWaO7CTfOXcS/jzF18OVuOGmHRkTgYDJaXpsrFTe9mQDA2O3cisM71D9etYFbWzBEY7yWB/MIUn1DpGPJnjXNcGw8KPh0pbPXIOXEadsErrnt9XRDD5ya5cERLpsQ6rI/TSAmOthL6lkHzGlxhdtmveuOtM1vkUU35yRFdjdCKw/ORo2k/LMEiGgMYqcyXFfzUor8pxCtU8RiGCj/zen0Q/DIMARCOOiY+rUdwUeqkI7VU0ZGhdeQUxsGagLL3br0SGkZWXdAISDrxxvZfpO1KHkEsiY6B+MAAzbPZ0CQ5QkhCc92uY8s0Zdkrqk1Mc66c4X3n+QXOVbqC8vKA6EvHgrGj/VYNFzSTqI8ggAgjJEAx5exks1aqGvryyiguXrweDbx3VyJc6yp2le/joJ58kXfAYlF676Nhtc+63kmBNWYZ+OzpuYv+ShTVwKGQa9ynDKDqdo5c1LLRuS/870LJxpb7UUFoCcghlCNbONVJomiWRv4jilIsTHVeEuG2bWG5YXa3YOGaHHj2JYp0fOw+O6dkRAAnL0nVWZOlF1bOlQsXlM3p9GfhytQhuLS7js1953l883EgZWt9VJ3/4uadw8coNQ3WXAT5WKkO+xO+GYjLY3j5SQwaOOmHH2r51+jENWpVC9eQVy2DPf/v5cw11aoidUYqktImEN2nqvSAYTeRcWFQDSKMr8HydL4l1TAP0PcwrOBJWxzOHIhkrzHtwqgJ6qKdIo/dMhg7hnFXqm+ZMHRkfUO1HFxCcx1q3+KKFB7m2DNpvTs83NjfxR194Bn/wuafQsj1OmfLkenF5BT/9qx/r/mqr+jrLZ18jwvPVO8JiHaso+V5fBgYDyVEnoHzUFTuT9fkKZBgZmqoxJvTUfwutAESiXtUnwVSFo0PKAdWDC71tTm1fJ6i8fEaEGtGifrYmxMEoCGaF6CbZObQ627QCp/WtTuQvKj/zpewK0VKemE7sqykDUopRZXjq3EX81Ec+hqfPv2TzCb56x2oALC7dwz/7xd/CJ598uvtbEAQ6wbEkF3AGEE/SBq4TYDGWt2Swytl/xP4Z6EPi71cgw3ju7BM/1t2n80AV+UQiU+YenNL0+CRm4IOsyBqX2pQiRQXhk6USaRppUlKOEgES4pKpt1UZ6F79HlbG7N1KXl+q4/vEnzYFqV4XfMT4cLlMUTZgvCKl49T5Ox+xaMhg6gjZOHT179zFy7h+6y5OHD6AE4cPhEcqQeOxtVXw4uXr+Jlf+zh+6iO/i6s3F+l+jEw2NpR26DKzL4EXlMaL29xRLOjtKEOI9hGnK510ZF0i5r9SGcazZ77mx/pr1dy3H+y29WEVrpTGA/GBnY6eEfBjEkrRjJEQ0pboLO/mdiQQnEzPadjgA8oQErvlwVMdgwSiVT+qLIEXNQIy1vhXacjZrJ4DgsoaJsCge8RRTwaI69SONzt4bdVI8eVzF7C4dA+j0cj+Xp+I4O69FTx74TI++qnP43/95d/BL370E7h6azH0SaLqiBILOn7phLMIgVwETVUJO8p2MnTqKaCz5M6bDjnpN/wRxb+ADLLwrg97QsBGWb0cTKzhgUrYdwzj3TAlKOyd3ie5I8AGC/+Zy7O9Oy1xmNX6itq9VAvu1MWNLm8Y2Z+BSnriyNHRQd0EUjrMIzOK/n0g9k31WGCWwV72RlWHVpD2zM/h8bMncfLoQezdvQsjEaysruPyjdt49sIlXLlxp9emf20jA3xsG2xvQ/H+ZeiXF4sSodP/DzLI3nd+uKiXSB1U1DdGlAB12hrJ4xInNPi8fNsa5DD5MsPYRjI2Hq5nhtTx7nU9tjUjQsdE/MlDqjQkaa034jB0i/WobYg4mR929pL6ENdLkkEdQuc7OSVxMoXK+3W0Jt/PV8xWdrK+lNtoi+2caEpkGFlupWlHcYOgPUc73h2ioKKh/rQJTFemO5F9VIbdDzwJyFWJtADdiweKl1taBfhEzstMHvZeyzOJX7oHDcPMl0j8ZJGL0mT5WVYSoNemhE/7rsZRx8L7a8hQYH7CV4g6SrPq24/hlNAmIC031fo5khePlP25qZ9gsPZ+M2DAtMkw8omvHpKDDXLRmrpJVo2Ppedfzc0ejgAmfcmVTPpS0spwANtOk72d10Y603O0nObAfMD5FpWpVLm9n6T6rp7ZqCSbTyPCY2RdOWgoRZ9DSKg7JIMBSolyMbfS6y8QNB5baYeBQ3b02rxPsy9fhPmke2DqZBjxLrReBsRkKLb2zl6llWu4S1YDMy77qZBejUDblu6en4Hi5Vak3JEmm9oWzpMhSCmk26wMktl4pwHIiK4R0groJvGpfYRJWzXkjAHB2EkOu6cyWJ0hGTTi1YhjAKfNIkgVe0CJ+2s4oMneL7dzVsKVUkMCwG54lS9ptJkeGUZsEJwkOappaNF2FHREU4xangcZtggXmcroUBt4OJS+MwbQJXr9oARdzXHspTZkfeG4MDHnswodPKGoRo4Z2vltllezMgMP/nSJ4Gd6lQ5HnWEZQscqe/Rm78VSXpalYZyBZAk+b+lLzzG5OUeHsIAe09Te9dWXYeRnxfkWD5yGiwpQtLKRiTVkIwGDVPETMA/vpV0kt+bO2UEs3DZ5qM5BYbYAPqGvCgtTBNa19dWgX2K7JArUyTsHJxoc4fS3tHZ+yaMaMiRm0DcMbePR0wWjZrnPHg2B60iavbeb+zh7BNeigcjyVZZhZA+sFH3YBoij7J5qUSI7bzBOQuA8H9D7QgNdKqImA++jKDlWsX+cRc35M09UZkvDAHTDplRjj7vBjGaxr4D0pCc+qOe1SVEqbuCTz4glkChVfyZbX4augA2E+eFrCJGBlkeHVJNoOLj7KYPW5e3FPvI5OeHUaIpkGHnK45MSe7WistUwlmFeXSjJqFeYeYpKkuvAkbkVEUH3+Xcjj7TDd+A0TPpNaorCq1D+qXGTdqR77Hjfvoxod8mQpXv3VJXR9J9407+/YWnZgAz9yUk9n9TjcOjqt2+BMHcZVvu4ZYoCnnXwuDjie/n0yDDqA3E9xcnHFhCF5By+F/okO2U/n4uM0m8yRvfkUgMJG6pGssw59VfpSeXRAbh4XU4srZl7oL7KxCrxKww5eBAa5eClSO+beCpWmjAnvgy9tpEhCE6A1Vt14+jDbVmJQY4h2soPDRIvRgyUc8rUzJSmSIZRH+z0aAZ15GEkZkvFQ2F4loIdJYeuxHDmW5m3rEpXn8jTSpH4FpcqVLcCRsqx5ckqAuX84Z2p6njGAB/LVnqUd3LkEpATikVXIceMO9qdcxdqVitFvgzBhmXwts5PSaPfpSY0jmGyxGQUcDxy+x9q6WTyY+muBj8bSYsCzqzrhXL4/sR6emQYmYOQcbgxeJ+F7nX0S2SG0qSAZBziszNoWLRQSwZKUOu5XnRKdx4xJdxXmK20+6dMnV+jwxGnR7w4+oQFCHJKks9JSjLqjo+SdToIpwj6ccJVV4F4HqcGzYygzcsxW6uKeGkvPa5tnKw7gW7YlimUYWQHs2gC2f0U9+aS7EGSddSfnkrRKc2wkqRtiyPngMfb7jN5dukZJykqfzJaqYeR43j+LlE7pCyWU11TyztkUf4k6YT4VDpCO8wZxer9cO4/TnDaMqSXSLcdKJup81hCUTYV7TLS7J89S22SVca6hh4QpKM2UyLDyCaAhGoWtdWrq12bQwf6bipuk25kVp3bNKJFXCHKB9zo1CyovvZTFRnStJQLFnpE1pd2OsH07SIWqUhxhctKFD7jYWG+VGm1rPmcQP5kUGmBYJaBnN9eJbrttSOEwgBAuwkAwydw+238+1A/UlNaspYpk2Hkh+L8hqgRBEsmYyCn6qVHhraApjO9E7mZDzVgRszIpwkTbrBuOWRzNeMnnpnnpT6xRhLaSFVeId2oE0qgDQpWZPQilrPynxf2JUcKa9SnpU4ZNLIM9V7J/ISmTMRXu3rPtKkzcmBlfhpPrTUW1Y1YbyndWGg4/BTJMPLB6AtnL/yundFH/eFOwKsoXWrug2pr6dxLBhKOFDm8VAYcgVUa1l5sZ4oxhvt89jqngGPyAQYYPhBRJ+Gqssq2ilM3pHmDReS4gBDbJhn0HqWhyp8al+MJuWvpq98E1ZdahzRDAv+2QdpUAFwGSXQk6WMKZRjp5JiXVwv8vKt2K/U/fdS01MGueKhD2+vb1u7tVjXk4J1uhsW15cZS21jgaOSEdLPjtyrY5kDk9IUjmTmR9+yrSTFSeSxhmYLXeuWKhj6YfVm7moYgDQOjgW3JoHpJ9UX7MwNk+FWLK15U25q5FWpnLQaiQSvnb1atvAY1TZ8Mo0Lhmu+pA9dxJaE0lVD6tOWkS4QmLLsMG664ExYVg+rzfEJpVdpstqGNKcLr2nKfVa/OXVxn1jfDjdCufTEx3cs5pbPoxQ5Z6VOaVFjvjBxAGqZ+2aAMpIP4PfEY6jAd5bPEtnQ7PNuMHZ43UBwhWqEmp8VgutMjg0WIGF7IK9A9UdYZCB/m00+NHYnxEn92/JPVUUrTY01XXRKtojQkF6KBVKLg4yRKHqwSx8eBpy4jFopwDf3QIMRxrjOErCceRIoUEgioCsQdcxsZ+srrX1E1HImpr9C5ddQzSl15LLbMLNZHWrk2WmysDgzTKcNI/+Qup0w6kewMxjfqWnwra4yiKm+Qga2D6hjzbNQhIhWrFx80UufSB4eIweI0CURq18X7yqgf9eMRxin0v/NtUn4+PCbWJ0dJoZsS6Vk72UaGoCzXRY7oTJPz8HzFAauglG7yCqAxMXRUolMwPxseMMHITo8MI5vsMnBXBpSvYuV0GK3S7wZJHOXcfvu6oY6CcZtxZqOQpAmmp07AkYQjG9NmRxOqJ+keOUtuG8INaZ1lCJEqy0eOkHQReSR+cvssQy+0UIqoPGT1bYfG2yI1Oy+SQQ01vI/Op0yGkWJZv/9quGZjxFhGf/7FyMWD3HuegNux0NnbqNRWsTrjCs8dIJXB67mjMZ/Jbf11GgiC6rJrP1eMUSkpe7i/ThqnqW29fS8dHpLBFNO/WnPdXv/tW7X9tgR27OM+mnsfUyTDyHKtXkbgnuqhWqB/UcgdO4U3wF5UYHMPEQtzQ0YeURscluBHLPiVNAiRgXcTzJmFf+lddRzqmxkr4C2K+qFPfUGzgEQXJkNRGYJeOCrRfaNSXJdofbZl4J+hot7OixP5fhaiAPpXfuIDPdSwRSxfZaDcbqd7UyTDyGy6xNwtrrnX/9TwhDNkQi/O7UTHPjtCsf6sNqFlYcfQlIjyQDu3xDKaE6V0g/rxA2POo5FgpUt9eo11ojYYDLfYBqbzofG2epVFLD7Z2v3T26dQApbfOgAMyWBOJ6y3TgZzzPqdj9X4+LWBkN+20t9ENCEgZAeFv4S5l/atPbolCwPHlMgwKsoYI3fp0LeYkVUjpLxfghYQDCdczC8bgCElQruwEgX+SuWFfppOVdHqSPpViAePKODfgEU+fe5bakTU5xFC+0pc9zNURYVDS0CvtMMQutd1LBu9yqIbzaAMKndWeon9BTMIE1KKioUYsy7UuTMltgPlk7CWh88c3HvMupgmGUZ+uyJxPezn3ldXmUKaZDxUBdCsXbysJwl5Ru+YRagXVKYe2peJwkQ8KdtwVCYn+koT7Y6MMfNrRdnT4Ue9A9s+QMZXdv4knySerYwHtSGDB2d3mn5dQmNKN4kSySD1e0VPbpuNtuHh0rvHqzmpPYHCNMlgDwj5J0UGSlWK9B6D91QmpFDJc5MCwmSyxHuxjMOnCuk04+50oseRzOYR3taOzRty1MhgPBYbmJzvhoUndQApoW04tsL8soxGW0zXxlKhz21kMI9VGYTq9v3X9BjvV4sUP30A8Pur3LRMa73VNuILfKuPLv5cQyyfFhlGvPrJ3sfnZYxudtzgbKkD4QpKx+nzA0XZd1TwwDS/GS/xF5mk7/l+YtvzTD3OrTx2zm/pSuWHWGPBPatUvjj9IX55/AokGjojo0YmH/tBGQIjVq30avicqCGDkabTvazf1C/z3Z8gS39MVTai1V4B+urLMLIxyGHdEnTUQXdDgTLFzpRzn9IoS6L3lki9IUkJNxJNnZJGQtwytovfKxF19DxVNGydJHuIVbRnRYfgxtHABYFOyp2Os6X0uG+xl8RRbLUIUoZlYGUG3fWPOEt2cKptB90kPeSTwJEswnTROgLhiyA+pp7uiP0OIz0lMtgjpIbY8AeEzNtoMHSVKfiOcafeGG/oIb2wgSYShGsHCY0KVb3CivKcQkTSyV49d099atBUxw/KLvXV9d0cysqMx65zRhxhGXJqkMjXaG68ijk1Db7mWNRID1cOykBlgDuu/1Fyr6JL4FRUAaAkGUrQLe/1BJtlYGrEq3gpcjIM9g/0TYMM9gipnbMvjq0a/jWtKghtA7Phh9lrCfeLMaJIR+FTktIs0hUimw2PQhQz6CxQqKTwSeVhqY8iRH5bnK5tW58JvdzAC2zDwuErKqm4bv25AR0hqPK6n7r61ZIh9A2jSSHVVNOEHU7vlI7Ee3xwktmIz4oM6QI12+WTywJ7g+MUymCvoTE1K2IHhE+MS/qtdRJzIapYLTfEsJipEhsaI7ZNAJqYolyfBKayMHD0vSPbNzSxZdgqYxhEOsKiiOad+sA7tQbfJTp5SAPEfIrl78tQNSTOQRSD9F5S1NK6xI85KYFBCfe3RUIirpNnH/+Ox5gu8inUaZFhxMQ19+sMVKB5NvtrHo+wmx0koe9sq5xLsiezzWRbEnVEQkvVhgDIzmAhqdTB6fkq7Ub7SlmIOGTc4diKtlH0Vk9uIYiSUx4LfWeaNrJebH1W5lsyeF+esxu4qPxA1HUoZ3oMZE48qCQgZ+038xNcodIiHmMqGQFqGmTo/iwvR3Nul4zfUL0o02R42og0YdEfjUuRlzqwsJmUYZs7ahw0qdZjHbbbXNMeT8NKz4Yg8F3mzJykMnW60hdEeOhLqm8RINNpKUM7zn3D+m7JED5hovedJl09FhppGBPnf6O1Zrqe2DR5HWJsimQILyrrP93mZHSeoTN1oxzy/xIZY2NiSRh586AnZ9Bowmv25oyDSkhtmB/ro708GAT2H1BnD8c8ihoB/F4ICyURtUbkyH1c8T5y2yjD4HPLqPdS1OKoblPbUs+ahXrOEO/0lsRPUVswFbgd9PdvSuRtSmWoq0zFBTLmnctufGvn1ZBtkqROot89QfQ5hKU0HkGMSY6tnJ9ZyiJ2G7kPXaWy1aoS2+g/hfowRdO8g/0k1XVeSKYc9gt9N5kI6tgvRcm5XJZB1XZCegi+lWTwP+rooqsMAoqkBeDHWXn+pqPJRqlvLCygKEg8VyKw6Sq/OKDqy1fk9GEp51X0r7IKpk6GLkLwhM5GoO5MGxp6CtQL/SL2F4aCZOAyuLcWmCFH1CZn7IVMMcDtbepYm7RRJCkKFFcQs1qYT5atpO8MGLWwt8gAikzipS67OgjrhfpRpyo+lEMycEg1SDNAYSCKffC6u7DDa101ahfZjbvQbnA+0h/GTMdDghq6evVeAI/pkGGkNlk4nDCK2US2BEYYGYOQ2lFvgPvCxnSL2ZJoJKatQny5glSRfpCM6Tn8EIBZvW5DzGu68fU6tw49qtI0ejibAAAPLklEQVT+QfDDvIMrMNQ0LXcy5AzT0zy/OSRD0Jh4DU8DyNCC3qMJ9mWEj40LBd1dF15MCDSYlvIVYDveCxY8HTKMNH2IhsaRAfATl36aKXUdhCIw9XvktcygNRUXXg3fynrplf5TzLjz/KevJNrhpKgkiQd3KOZZ7wt8+ZUR2tFJKs/hUBvLIjxGBBC1PNo50WjJQEDlnOhmoTcXMC1mV0gdSXsByLq+xPpFYjQ7hVl2kiFZtHU+PTJ0f1IrhTXfnVWi3oHmdYqvDvYuoNoJb7xZKlQAn+gQc6a/Tml9hGV/UWPQlx+UnrH3DtPxp8mm+nIGdJKnR1SMpPItJdSz0M99hDEXa2sOxXJovWxTQ79JBos0QAAERdigx8LlML0BCmJO2NsI/A/q0MqdDK3zR73HozmI5Xr6YMpkGPUdi3aJRX872zyZCbEihYZwvoi7ELUjglQhutoX3Vex1bsLtQtb9lIP6RWKFgF2KY9n5KfX3GuUFJOJHtjRvgSIRy369ApbuUaXrAxNMStwhvmcxHotGeLhNTYqOhIjzqeQXlVvvDmGql9ewYl/W8+qNMXpfZd0XolTQB3zKZNhxALYLYV4MxBJ+S0JXMddw5t6MKdZth1fnUaIceXTVyHicprWZweJSuT/qV9Fg0YuXz3b2xu5Pl+GNpX3EA14/qNdaVqk8hqPGeKVXy8S4is41IAMBgzEei9t0DKhe0Qvr7roWFv6HCavaohJRzofs4ip5ArJJj3WzGGmSIaRFuQDUCV0VEKua4Nh4cdDpa0eOQcuo05YpXXP79uJSL1HduWKkEiPdVgdoXcS01groW8pJJ/xJUaX7Zp3rTuTdT7FlJ8c0dUYnQgsPzma9tMyDJIhoLHK3G9RVcLEEzQaoEnvdk8IBgMrjomPq5F2gXupSAkp0rTIMLJyerO0phyKUXG9l+k7UodlMBIZA/WDAZhhs6dLcICShOC8X8OUP3zCTkl9copj/RTnK88/aK7SDZSXF8CfIixe1rGi/VcNFjWTqI8ggwi6Z4cdAUMqsI0MlmqJIObw/s1X1Yzh6JfJh0OUtu+Rql/s2G1z7reSYE3TIkPYqealVGtYaN2W/negZeNKfamhtATkEMoQrJ1rpNA0SyJ/EcUpFyc6rghhe69iuWF1tWLjmB169CSKdX7sPDimZ0cAJCxL11mRpRdVz5YKFZfP6PVl4MvV4o4nUKPIYNXRlp6sheqproVk0H9IhnyJ3w3FZLC9faQpkmHiUaNSFI8DOhcofL8hvEkj8WvrWQdeDSrWl/fd2ktwQcmJeFakfFIKZ80CD37Dj434RBqsNK8I88gWzeA0kY7/dOVIvS8gWYkey+9Bri2D9tvTFzlS2Ak2Nm2EQj9uiMR/CQ3pa8oWuIvWGCo9oBFFpkeGkaFpNcaMnvpvoRWAwBjx75NgqsLRIeWAapT6MJL1qEjI0SX8pRk67Be14RCqyJBy8xBXhegm2Tm0FlKoZ1MaAbRO5C90+v82dyYLEtsgEBX9//9MDlYVDyRPcov70tO2xCYo0GJPTrkkbgFPyUQ6nddVhzVKjDl+Vz8DX1LtaXFxh/yY17cL4M/S5kp/NZ/8mg6/CqQ4oqs9tQTU9PrvDcjbeLog2PTmc9KmWB2Dm2xvKHS5mtWnvrBkyr4MHAsR1V6TbLwKRjk5WhZ70CvH/MKlEJEpuBTbQYIrUhynWmN/0cE/O3xq9a9xmjGafTycXcnFJR6Ct9lrE8b8Uxlf9JvbO1Csxed0+M0I08pA8S53laOGFM9rFUlqDz37XkLebaxY5aAyqsoe193JvLfa0qcM1VYMbC3dHI2zeF4yjZ0Z9uL1MfdvDt3DewSb20nf0pXjoINqbbf7poNsCnvwhHKAVr1qRDaWaCVbHEa9gTPgXWis/1PozEVaJ3gF5PiaDj/WbtpRTgsRQKutb5cEJc4ZHEa7ll1Wja+cnenx+K3gW4sBk2ZQ9I/SwsyBICtWHbDbQS1BBwhLltyBqQzolB6xn61eGxwe5fSKmKTh+dm8iXyct3ke5AZ3HTj5rmdXJvyGZe43Rjk603vLtBScTfj4Ze0p0Ede5s8m/DUdfhpc+9UlO5tQTx24rswitK3BCwptNF24v3EghiIHn2j853HfZPZhxshG4f4D5ZNLTtCIPhqrbRQWw0IefxXdPpHM835DvQ0Kl//HduLt8nzr6R/NCfdIuNSrPtzslO6v3qtQr1+FiZBN9pr6NLe4BslXdPjFduZCTKWdaAOm493K+CVpzzCMUq9QtbKkDHPsXgakI59Y63kJVSKPhv+uiVxdsz5EDZdfkLdZRYftIBcn7JRT+mPwuKPd+8SlT7Zv/60susei+F10EDiMKGmlu2guOdoMxmo2TzA3J83EUIWrglVNSj9WAubnm+cU7kM6/Co96ZDc8iCnWmqTLJDOtjYtmUytVqFGwS6QD7Ixq8zE0JU9UaBv8GTr5785P8kaGGU3yuGDfUSjxvHRw/66AwiJHE3TCY9yGU0xb6ll6p5p3nQwoGTXi9LGwa8RtIwFiqv3vc21dveT5qlfSxHT9mt9ToffPJO+aW8QroERAgejSo2VD49sNTY+dHRaS7hcRtBqTTxn1dsJRykrs9DIROcFBMmEbacxoLNlxwBMRFeG9AXc5CRr82iTtu3Ix8se6ETQw/ekg9u86aCMtzOOAU7dOkil50/kdwlA635e92pZsNHoCAB8hldyxaXPd3T40SHaHN22V2pRPySdwHl+OtGqtmHm6DrRYXeodBhnMDbQBb0zKS2t5hT2og+8rx0XhnA1o9LgBbIaArP1q9vU13PgRwgpMCTecy0q2bLOuw6NsXTv0VxcXPJSl4tzNpLZYt7lyxGY7M7sIIkAgrdB+4gOvzorzlscOKWLDVDa2V0nsYtuULBp1b/XcoQfZRf0Vu08A8Tp9irDDg6k2VyrJvTbYG2KQFub14V+9n5DlaUgfwIcNOaEPxTAkxgi6qLDEGadjqE+lT1LMXSbPA8ascpGc2nzr+41zpXBdekls/zPOvy8BJnacFurj3JFqrPEDN7mnEDgOR/Q/cBA50bU4eC3pYhWikwUUM0/ZcI1b3St5ZWM3M7el2yJZp1XQ3rYiQf1qjUMJXWbnDwjNkAit/2s26nDc4EOQnn4eUPktW4R3UpN0Chwr1MGt0/1D3/Nc3J8XuFLOvjNfUazFELCGS7O8i5rKRUT9ZLCIyvFbLMKmW8ZceE+f1/qSB++WyzD4uyySxSuQtW38qaOep82aCVeS8fPxXLk8P92MOpLX/LabwVxWfaiwzk52c+jHBK+fc7+NxAmy7bax54jC1TVwXEpxK/r39HhdwLxPsW5NzrOg2ZATv69eJ+/z3quC4rfcMaK5NyJhI6qTDYlB79NL7aMBcBZbVlYultFoF5l4kZ4sq5lIqDRTF5Ceq+gyLfnhHnIxc3INx2a4gCsY9WN2Yd9acSmxxttyYNB4mLEy3WWTNdK6UM6/E6wCwAW0WgHBvllpUKeJ9EANsGO33e5JbyrKp8VqkjLjBZnMtizAgbjeHlyq4CaP5itFHgWgMeyRQ91JzNXLARhOLsGArOCYdtq6XmKsrmzFuSuTHnXofqWPDlG/ylNMI5tskQyApzK3N793fapXeUyQ52NxKJACVt2QQ1/Tqy/o4Pf/k3nKGconol7D/3swqBMakjGFD+DQWnRqRYOCqjlufZmAwdP2Aj/Kc1u2ucp05LXdJhxDuJZ6NMWIBCU0K9IxnDqR47jwOQrnK5mnyK8bdWIz3G60JwIev0UZqtpRF09yuPdp8hWEGjDNj+ow88HszCBfH7WyU6P8wIVSrh/VinVn6nu7eR425FfIt67z4jsPJwThprfRCtFGAKn6vfo1oGxqKdCU9cfZJF8MWwCOUUnsMM8UWzfD6639wnOXYd25Hy9BNB005Ix26XpKmLZafba/tJneGVva/RYsfqJ4q/o8PMEEKjmrK2o3n7tgG70y1XKJ8vJ3Jx9LtmirxCxxltLKbfNvbBKJUO2Mm3UgokjyrW08yimt4s4U8FwyWvZlZ94mJRLRtvXrs8JzG+Cyg0Epw4Ifr9K9M/Pv0LoMgCITQOYeYar96m/3/jELmnhLR/T4eeNDoSa3ox9rDZN5EuOaQ60XUvlDB4YO/URb6PtumYMplzfoG2ZstnM8oyn6rDUF+4UrY8O8SVsoyCMRnshWcHpo06kBuY2teSItAaeLp0maEwd9r2c8rSuJFKrXXM3ycHIxEp55lNu2fB5fNRnXM61jGojqXxFh18NxqmcnpXPzQxf+0cFAVdRntK8BtVr6eQygYSZYqaXLUAhsLSh9Xo/G8YCn3IezJFwrN9aBgw+8ESbtM/WNf40nMIQ8wZn5L6A0PsOHXQPZajkk3MVniBc8zS/FdVLrVuZEU1+b5BeDbBKhxh0Ytjjgzr8NDnm8qqe/6otdD18EX7UNPdgbzzU0B686+k33dqO3KKz3DDLWuUsu48Tx6UmxM1H3m1gz4EQ9MlM5iAqzrWa1DMVjzfXnRa11XijYQ3mqevT0ghycTAM7E0H2WW0D/GzAxJ+5XFZl3Zfu1uin3u8ZINbzX9tumVtZvqeDr9EuuY9BfAeVyilUkL0seWkJUIry5Ch40YFYUoNtOd8QrQ2bbpt62NDVFsv97n5Du4sm5k34Sawa59Ws6KcJZ2zFwNy00eZlLQ7kWOtMUzntVcdYIP+95CxtSEdyZm9L24XygpgCjznp6Y/db+1ZFm8SPc7OjhD9PSCqFjp//6YCoQmm3LHEDz7z0d+eB1KmkM0rboMWikaMS+uC1KFwKdI5Bys7ONTwLOXERMZ7mIfDEIf5z1DmHbiICJTRCMgE0QF5h86nMY7P900zMTg1Zib0eGUWnlMLzOHeYyVa9OisxYwfFOHn/7zCksmTSQfh6mNupvcEo0oKn2bDvQOtLHwdOqWkdLt+oNGCi49OAQBs2gCRDbrLF4T9bt9KsMUhfNv3obx5+GxME9mycDN6PTcL/7QoRmrbDEzOmmyDp+fPmAblMZNrgBaiLejEo+B+Wx4wwST/Y4OP092CdxbAMmVvo7DaJv+M0hRKFf+e9oGjJpz2zmnU8SwBOkpCJhJmNlIm4EWaBfjHoJl9m3pBlanDi1TTf0QCMMWXUbIM/tPHY7UghJRMkzz/YXGfyI1g3cNh3rr+B+Yf0yHfwAjBO4Lyccm/wAAAABJRU5ErkJggg=="},{"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","endDate":"2000-01-01T00:00:00.000Z","startDate":"2000-01-01T00:00:00.000Z","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","endDate":"2005-01-01T00:00:00.000Z","startDate":"2005-01-01T00:00:00.000Z","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","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","description":"French address registry or Base Adresses Nationale"},{"id":"FR-Cadastre","name":"FR-Cadastre","type":"tms","template":"http://tms.cadastre.openstreetmap.fr/*/tout/{zoom}/{x}/{y}.png","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","description":"French land registry","icon":"https://svn.openstreetmap.org/applications/editors/josm/plugins/cadastre-fr/images/cadastre_small.png"},{"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.","icon":"http://www.freemap.sk/index.php?c=core.download&filename=/JOSM/freemap.png"},{"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.","icon":"http://www.freemap.sk/index.php?c=core.download&filename=/JOSM/freemap.png"},{"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.","icon":"http://www.freemap.sk/index.php?c=core.download&filename=/JOSM/freemap.png"},{"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.","icon":"http://www.freemap.sk/index.php?c=core.download&filename=/JOSM/freemap.png"},{"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,"icon":"http://i.imgur.com/aFlvMpM.png"},{"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","scaleExtent":[0,19],"polygon":[[[-48.2444,-16.0508],[-48.2444,-15.5005],[-47.5695,-15.5005],[-47.5695,-16.0508],[-48.2444,-16.0508]]],"description":"Addresses data from IBGE","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}","endDate":"2016-03-27T00:00:00.000Z","startDate":"2016-03-27T00:00:00.000Z","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","description":"Supplementing incomplete coverage in other sources (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2014-07-31T00:00:00.000Z","startDate":"2014-07-31T00:00:00.000Z","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","description":"Recent summer image of the Alaska Range for mapping natural features (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2014-03-16T00:00:00.000Z","startDate":"2014-03-16T00:00:00.000Z","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","description":"Missing in older pre-2011 images (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-01-01T00:00:00.000Z","startDate":"2014-01-01T00:00:00.000Z","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","description":"Missing Islands in OSM (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2013-10-18T00:00:00.000Z","startDate":"2013-10-18T00:00:00.000Z","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,"description":"For more accurate coastline and glacier mapping (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-09-29T00:00:00.000Z","startDate":"2016-09-29T00:00:00.000Z","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","description":"Up-to-date image for glacier mapping - beware of some fresh snow at higher altitudes (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-12-10T00:00:00.000Z","startDate":"2015-12-10T00:00:00.000Z","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","description":"Missing in other image sources (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-09-21T00:00:00.000Z","startDate":"2016-09-21T00:00:00.000Z","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","description":"Up-to-date image for glacier mapping (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-12-21T00:00:00.000Z","startDate":"2015-12-21T00:00:00.000Z","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","description":"Patchy and partly cloudy coverage in usual sources (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-03-11T00:00:00.000Z","startDate":"2016-03-11T00:00:00.000Z","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","description":"Recent image, only old and poor images in other sources currently (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2014-09-02T00:00:00.000Z","startDate":"2014-09-02T00:00:00.000Z","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","description":"Coastline mostly mapped meanwhile (false color IR)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2013-08-27T00:00:00.000Z","startDate":"2013-08-27T00:00:00.000Z","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","description":"Missing islets and inaccurate coast (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2012-02-05T00:00:00.000Z","startDate":"2012-02-05T00:00:00.000Z","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","description":"2007 ASTER image offering better glacier coverage than common sources (true color with estimated blue)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-01-09T00:00:00.000Z","startDate":"2016-01-09T00:00:00.000Z","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","description":"Fairly clear up-to-date image for updating glacier edges (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2017-03-27T00:00:00.000Z","startDate":"2017-01-25T00:00:00.000Z","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","description":"Sentinel-2 images of Enderby Land and Kemp Coast (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-12-13T00:00:00.000Z","startDate":"2015-12-13T00:00:00.000Z","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","description":"Image from after the 2014/2015 eruption (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-01-01T00:00:00.000Z","startDate":"2013-01-01T00:00:00.000Z","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","description":"Landsat mosaic of Greenland (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-04-12T00:00:00.000Z","startDate":"2016-04-12T00:00:00.000Z","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","description":"Recent image of Heard island with interior mostly cloud covered but mostly well visible coast (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2013-09-16T00:00:00.000Z","startDate":"2013-09-16T00:00:00.000Z","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","description":"A lot of very coarse coastlines could be improved here, much snow cover though so no use for glacier mapping (false color IR)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-08-07T00:00:00.000Z","startDate":"2016-08-07T00:00:00.000Z","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","description":"State of bridge construction in August 2016 (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-07-17T00:00:00.000Z","startDate":"2016-07-17T00:00:00.000Z","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","description":"Latest images north of the regular Landsat limit (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2013-11-16T00:00:00.000Z","startDate":"2013-11-16T00:00:00.000Z","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","description":"Missing in other image sources (true color with estimated blue)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-10-13T00:00:00.000Z","startDate":"2015-10-13T00:00:00.000Z","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","description":"Missing in other image sources (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2013-05-17T00:00:00.000Z","startDate":"2013-05-17T00:00:00.000Z","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","description":"First available image north of the regular Landsat limit, mostly with seasonal snow cover so difficult to interpret (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-06-13T00:00:00.000Z","startDate":"2016-06-13T00:00:00.000Z","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","description":"Up-to-date image for glacier mapping (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-08-02T00:00:00.000Z","startDate":"2016-08-02T00:00:00.000Z","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","description":"Up-to-date image for glacier mapping (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-06-08T00:00:00.000Z","startDate":"2015-06-08T00:00:00.000Z","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","description":"Many missing islands in OSM (mostly mapped meanwhile) (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-09-25T00:00:00.000Z","startDate":"2016-09-25T00:00:00.000Z","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","description":"Up-to-date low tide imagery of the coast for updating mapping of tidalflats and shoals (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-08-12T00:00:00.000Z","startDate":"2016-08-12T00:00:00.000Z","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","description":"Up-to-date late summer imagery with few clouds - caution: not all visible snow is glaciers (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2012-07-09T00:00:00.000Z","startDate":"2012-07-09T00:00:00.000Z","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","description":"Assembled from July 2012 ASTER imagery (true color with estimated blue)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2012-07-15T00:00:00.000Z","startDate":"2012-07-08T00:00:00.000Z","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","description":"Assembled from July 2016 ASTER imagery (true color with estimated blue)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-08-21T00:00:00.000Z","startDate":"2015-08-21T00:00:00.000Z","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","description":"Up-to-date low tide imagery of the coast for updating mapping of tidalflats and shoals (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-08-21T00:00:00.000Z","startDate":"2015-08-21T00:00:00.000Z","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","description":"Up-to-date low tide imagery of the coast for updating mapping of tidalflats and shoals (false color IR)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2012-08-13T00:00:00.000Z","startDate":"2005-06-21T00:00:00.000Z","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","description":"Assembled from mostly 2012 ASTER imagery, some 2005 images mainly in the northeast (true color with estimated blue)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2013-03-13T00:00:00.000Z","startDate":"2013-03-13T00:00:00.000Z","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","description":"Glaciers of Northwest Heard Island (mapped meanwhile) (false color IR)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-06-07T00:00:00.000Z","startDate":"2016-06-07T00:00:00.000Z","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","description":"Images of the new locks (but partly cloudy) (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-12-30T00:00:00.000Z","startDate":"2016-12-30T00:00:00.000Z","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","description":"New locks with less clouds than in the Sentinel-2 image - make sure to check image alignment (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-09-30T00:00:00.000Z","startDate":"2016-09-30T00:00:00.000Z","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","description":"Sentinel-2 image of the Pechora Sea coast in autumn 2016 (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-02-02T00:00:00.000Z","startDate":"2016-02-02T00:00:00.000Z","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","description":"Outside regular Landsat coverage and therefore not in LIMA and Bing/Mapbox (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-08-31T00:00:00.000Z","startDate":"2015-08-31T00:00:00.000Z","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","description":"Late summer imagery where usual sources are severely limited by clouds and snow (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2011-04-15T00:00:00.000Z","startDate":"2011-04-15T00:00:00.000Z","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","description":"Icebridge DMS image of the settlement - alignment might be poor","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-01-01T00:00:00.000Z","startDate":"2015-01-01T00:00:00.000Z","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","description":"Land/water distinction difficult to properly map based on Bing/Mapbox images (false color IR)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-08-28T00:00:00.000Z","startDate":"2015-08-28T00:00:00.000Z","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","description":"Late summer imagery where usual sources are severely limited by clouds and snow (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-02-09T00:00:00.000Z","startDate":"2015-02-09T00:00:00.000Z","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","description":"Recent image of most of the remaining Rwenzori Mountains glaciers (false color IR)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-07-02T00:00:00.000Z","startDate":"2016-07-02T00:00:00.000Z","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","description":"Up-to-date image for glacier mapping (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2014-02-05T00:00:00.000Z","startDate":"2014-02-05T00:00:00.000Z","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","description":"Missing in other image sources (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-12-13T00:00:00.000Z","startDate":"2015-12-13T00:00:00.000Z","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","description":"Missing in other image sources (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2013-09-27T00:00:00.000Z","startDate":"2013-09-27T00:00:00.000Z","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","description":"Missing islands and coarse coastline due to cloud cover in Bing, lakes could also use additional detail (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-02-04T00:00:00.000Z","startDate":"2016-02-04T00:00:00.000Z","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","description":"Outside regular Landsat coverage and therefore not in LIMA and Bing/Mapbox (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-01-01T00:00:00.000Z","startDate":"2016-01-01T00:00:00.000Z","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","description":"Sentinel-2 mosaic of Svalbard (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2011-05-07T00:00:00.000Z","startDate":"2011-05-07T00:00:00.000Z","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","description":"Icebridge DMS image - alignment might be poor","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-09-25T00:00:00.000Z","startDate":"2015-09-25T00:00:00.000Z","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","description":"Icebridge DMS aerial images from Thule Airbase - alignment might be poor","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-10-06T00:00:00.000Z","startDate":"2015-10-06T00:00:00.000Z","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","description":"Icebridge DMS aerial images from Thule Airbase - alignment might be poor","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2015-09-25T00:00:00.000Z","startDate":"2015-09-25T00:00:00.000Z","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","description":"Icebridge DMS aerial images from Thule Airbase - alignment might be poor","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-08-12T00:00:00.000Z","startDate":"2016-08-12T00:00:00.000Z","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","description":"Up-to-date late summer imagery with few clouds (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2014-12-24T00:00:00.000Z","startDate":"2014-12-24T00:00:00.000Z","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","description":"Coarse coastline due to cloud cover in Bing/Mapbox (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-01-31T00:00:00.000Z","startDate":"2016-01-31T00:00:00.000Z","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","description":"Image from after the 2015 eruption (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-06-23T00:00:00.000Z","startDate":"2016-06-23T00:00:00.000Z","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","description":"Recent image showing newest features (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2013-10-09T00:00:00.000Z","startDate":"2013-10-09T00:00:00.000Z","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","description":"Represents approximately minimum snow cover so can be well used for glacier mapping (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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}","endDate":"2016-05-10T00:00:00.000Z","startDate":"2016-05-10T00:00:00.000Z","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","description":"Poor and outdated imagery in other sources (true color)","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAADWElEQVQ4y13TS2gcdQDH8e/szGQ372Tz2irGpoS0KSapoqjRQ4knD0WweLRCCXiQXuJFMR6EYMVC0IsPyKVFsJpWbQ0KQmL14KPWirGmZjdmk+w7mX1kZ2d2dv7/mfFUsX5Pv8Pv+lH4X6/NvTPc239gOlXyp7ZzlaEg8EGYyVaZWY7dc+/CuTde+fu/f+XOeP3iLT2bTMxN9NVm1PZhbfKBGC/OXsDzHJr1EEf6ilSMLZFrxObHJk/OfvDqCQmgArz3TUJfXZm/3K53nZ4YPRw69czjXPrqR+LJHJ4rUFXA3qG33Va3cpknU2vxY1pz9yWzlPZVgL6xobNGXp7u6T9Geq/O+U+usHRtE6du0aJncSyXtnCOcqVC0ZTIhnM44itNhpFeVs5+kRxe//OP22VDar4ncRwHz85TKtY40H2D4n6KwNMRgUPIC9ES0mj2NNwK4rfE2qhWyBnT1YrUQkqA3hwmpIYw63law4JcaR/hR9GVAh2tOmEUHunpwKkJVm10VdOntbptP+VJiaIoKIDv7zPQbVDxJIPRPkRkh8CN0KFrjHdGiXW3kkuXSRYEakid0qQrDkrhEgQ+tZpNtVTmoQdNrGgB6XjUpEJzSxvCgnhOZ+RQFKtcZV8IpO8NhXxfIoWLY9tUS0XePxXHMNrY3BxkOx+lXVX54dc+VjdaiHabXPg6RcMSWFULT3poEGxJ0eit1Wq06w4FMURPl8NObo9MvgnTaOGF402M399DrDNEPJHnl99rZIoWvudvaeGwtux53sOPjffy9pn7CHdKnn5WJ/5XnudnrjF2tJ/F61mGBiIc7fe4mXT5ds0lu1tE8f1lbSDWu5DZyb98fMLVwp0dgINv5Bjpcfj50yloUsAo8Ob8T/iVBociLrtlC9+tCwgW1O8++7A09dxLbUvfrzzRpV7nSCyK0qRDOEwjlUYr7iH2DPx6hXevpLi5YXNjfRsCcQ4aiwrAlxuB/tHCx5fTyaUTg/1pJke6eHR0GF9AKZtnv1BlYSWFWYBEepdyuXwV5EmQ8l9Mn9929asXF+c21xMz5b1NreHewvNcHAc0qRGpQyqfFZZZnQc5C1LepfFOZ946P5xJbkybRmbKzm8f3C3b2GZlyzYLy9WqteD5jbs4/wOHuM2qT5aWEQAAAABJRU5ErkJggg=="},{"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","icon":"http://nls.tileserver.com/nls70-nq8.png"},{"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","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAB3RJTUUH3gQOFR0YB1KT3QAAAAlwSFlzAAAewQAAHsEBw2lUUwAAAARnQU1BAACxjwv8YQUAAAS/SURBVHjandN7TFNXHAfwzrn/lm3ZHy7LYrJkybK5zMw9fCEoPjbeChoHTtBVRF7l1ZZSaG8flCtvsFVpoZZHC5Y6jDM+UScDaxF5lIfSAaMIlVKBS8EZN4d+d9voZpbMFX/JN7nnnvM7n5xzcxmM5wrPlX1yFmP2adgmXKHc78bsU+j9ZRT3HzzE+D0n7tjuYdo5h38X47/q+UWD1nE0tw/gktEC66gdN/tG0Dc4hnEHhdG7DujOdqGHxi4ae2AZti8ccJXZYoOxawRPnjzGwcpmzM8//ntOe86MickZTEw7ka+99nJAZ/8YWjqs7ufc6ibM/fbQ/fzHo0eoOduJ8UkKljt2nLhk9hj4/Wlm6VA9A2NUa/ew6wNQE1OzVGvPEGUZvkvZHVNUo2mA6ugfpvoGrNT8/Dz1tMfd/yJgKZ13h6zjzFbzvbwO8wDZaR4kzeZbZG/fIHnTbCOvdzrI9h472dnVT97oociO23NkW+9M3pDVsc/V69rjRYA7Su11/dvbfkRJvDeOcMORuj8CpelLkJO6BVs4vQhj3QD5fTQS2PXYndQAblw2yrUt9c/6/xeoqzulK+VEoCTtawgSM5HCr0Nsmg48ngJhYiukonNIybeg8MQEFIZBFBWIoa4z1XoMaOrbtbHci2BtW4RachnOlO/GZW0SjuZEY2eWGYVEFfYJ+kDo/4ThdDPExadQcbxb5zmgb6/xYZlAxPtDmByFS2U+EHM5yBOyEZZ8HkzeZaQmyxFZROGkgUQIMQSNvkPrMXBM31YdFqNDJK8ZHE4FYgSt2Jl0GpKUGAhFjTiQ2QJDgRBGdSTIvEJ8IXDSQJvngEbfWrWacGJDzn1sJ34FkSqFQbgWTcUrcLWIATlnBzYSE8hOOIBQzk9YK56jgRs1CzlBVXD6bcijCYSwTYjhXUFD7nrUlHyFc6pPUCL4BpskUwhn6iGPSMYG3igN3KxeCKDZyulGddReBKV3YbNkGidkIWhQLMeFiuUoE3ths8iOfXFnoQ5nwTt9xHVFVZ5f0XGjxks0A++sIWyNqYM0TYp6qS9+UHxOn+BjqMQfwF8wgg2x5+ErccCboKA5bloAUGc8tk40i2CmGuGhgQhjX0MZwUY5uRJVuX6QcpPhm2TErlBfBLAa4S2epYHrlZ5fke4K6SVyIjRejz1REfhO2Ab2wavgZJ8EU9gEUek1MDMvIIa5DUFpzVhHzECtbRR4DJRrDP5f8h04ILwAmTQLAkEWCgsLIJVIIcwS4uhRBSQSCfi8FGzP6sbKjLsoV+tWewwolUfe+pR1y7GD1YDd4cGIi4uFgM/HulWr4LdpI5ITE5EQH49dOwMRmtmND/ebLMoy+WueA2VyBmO9opSTcx6HimWQHypGBicF+6MjwdzzLSQEH6UlBSjKFyNS1AnGMm6Csuwww2NApVK6hkv2JMptmTkGiPNqEcc+jFiuGsy0SrD4lciQ1kJW3ICAqJIWeu1ilUq1EEDlHr/6vr/XxozBuQD6jw6UUXRm6DgRQCeQfIA1iaZ+BuP191xrXwpw1RtL16zwSfi5PVg2hZAcyp0gqQOr9548TU+/82zdywGvLH429eZnO8rPBNMbB4ps+MhPpvyna9ELgb8ASvKZeuq+E9sAAAAASUVORK5CYII="},{"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","icon":"http://nls.tileserver.com/nls70-nq8.png"},{"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","endDate":"2011-01-01T00:00:00.000Z","startDate":"2011-01-01T00:00:00.000Z","scaleExtent":[14,19],"polygon":[[[8.222923278808594,47.604774168947614],[8.244209289550781,47.613569753973955],[8.294334411621094,47.60986653003798],[8.300857543945312,47.58625231278527],[8.329353332519531,47.569808674020344],[8.382568359375,47.56702895728551],[8.398017883300781,47.57490443821351],[8.424797058105469,47.56795554592218],[8.415184020996094,47.54663986006874],[8.389778137207031,47.5262428287156],[8.372268676757812,47.51233121261258],[8.358535766601562,47.503286684046664],[8.36402893066406,47.48078455918],[8.371238708496094,47.481016589036074],[8.373985290527344,47.47011007802331],[8.368148803710938,47.46825342516445],[8.387031555175781,47.44852243794931],[8.380851745605469,47.447593738482304],[8.384284973144531,47.4355191531953],[8.376388549804688,47.431803338643334],[8.377761840820312,47.42808726171425],[8.389434814453125,47.42739046807988],[8.391494750976562,47.41902822496511],[8.380165100097656,47.40462347023052],[8.364715576171875,47.4016026187529],[8.367118835449219,47.39881398671558],[8.380851745605469,47.39788440990287],[8.39424133300781,47.39439835079049],[8.399734497070312,47.372314620566925],[8.40728759765625,47.37068703239024],[8.404197692871094,47.34417352612498],[8.416213989257812,47.33416935720614],[8.414497375488281,47.32602502961836],[8.452606201171875,47.33254059215931],[8.444023132324219,47.31927592106609],[8.427543640136719,47.29925625338924],[8.390121459960938,47.28854494625744],[8.41175079345703,47.247076403108416],[8.393898010253906,47.227728840642065],[8.404884338378906,47.194845099780174],[8.401451110839844,47.17757880776958],[8.409690856933594,47.17314466448546],[8.412437438964844,47.13976002139446],[8.379478454589844,47.13929295458033],[8.361968994140625,47.14559801038333],[8.342742919921875,47.177112073280966],[8.3056640625,47.24987305653909],[8.295021057128906,47.26268916206698],[8.300514221191406,47.26991141830738],[8.278884887695312,47.28225686421767],[8.259315490722656,47.285983225286174],[8.243522644042969,47.280859411143915],[8.240432739257812,47.27130916053537],[8.228759765625,47.27270686584952],[8.219146728515625,47.25336866567523],[8.204727172851562,47.245444953748034],[8.203353881835938,47.22679624955806],[8.180007934570312,47.22143353240336],[8.171768188476562,47.2279619858493],[8.155975341796875,47.23961793870555],[8.175888061523436,47.24218190428504],[8.17657470703125,47.25406775981567],[8.136062622070312,47.24730946320093],[8.12164306640625,47.24218190428504],[8.10791015625,47.2447457457832],[8.097267150878906,47.259427174956194],[8.077354431152344,47.2603591917818],[8.059844970703125,47.25569894358661],[8.062591552734375,47.24614415248379],[8.016586303710938,47.242881146090085],[8.015899658203125,47.258961160390896],[7.997016906738281,47.2796948387185],[7.951698303222655,47.274337475394645],[7.960968017578125,47.25430078914495],[7.933845520019531,47.237053849043896],[7.911529541015624,47.24381345414034],[7.859344482421875,47.23425651880584],[7.83977508544922,47.23425651880584],[7.826042175292968,47.24427960201268],[7.828102111816407,47.25966018070071],[7.82398223876953,47.26548499105541],[7.8408050537109375,47.273405704663965],[7.848701477050781,47.28551744450745],[7.860374450683594,47.30461109337307],[7.871704101562499,47.31136207506936],[7.8888702392578125,47.31136207506936],[7.897453308105469,47.31904317780638],[7.895393371582031,47.327653995607086],[7.908439636230469,47.340451266106996],[7.9259490966796875,47.332773275955894],[7.94757843017578,47.331609846720866],[7.94757843017578,47.316715688820764],[8.007316589355467,47.33905535093827],[8.004913330078125,47.34533667855891],[8.011093139648438,47.35719936945847],[8.024139404296875,47.36719917429931],[8.032722473144531,47.38393878966209],[8.026885986328125,47.39602520707679],[8.010749816894531,47.3955603961201],[8.004570007324219,47.40671472747142],[7.975730895996094,47.41507892620099],[7.9657745361328125,47.42181578692778],[7.985343933105469,47.425764580393924],[7.971954345703124,47.46105827584221],[7.957534790039062,47.457344265054225],[7.940711975097656,47.46221885041022],[7.946891784667968,47.48403288391224],[7.907066345214844,47.48588897929538],[7.8936767578125,47.50653361720931],[7.873420715332031,47.51325876844644],[7.875480651855468,47.52253342509336],[7.865180969238281,47.51975120023913],[7.856254577636718,47.533660849056794],[7.833251953125,47.5325018525392],[7.834281921386719,47.51465007145751],[7.789649963378906,47.49377665301097],[7.789649963378906,47.518128167602484],[7.7515411376953125,47.52461999690649],[7.731285095214843,47.53203824675999],[7.708969116210937,47.54015075619555],[7.740898132324219,47.54362716173679],[7.761497497558593,47.54895720250044],[7.781410217285156,47.55289644950155],[7.797546386718749,47.55915229204993],[7.805442810058593,47.56563904359584],[7.814369201660155,47.575136052077276],[7.819175720214843,47.58648387645128],[7.8325653076171875,47.586715439092906],[7.843208312988281,47.581620824334166],[7.859344482421875,47.58602074809481],[7.8847503662109375,47.58764167941513],[7.903633117675781,47.58092606572345],[7.911872863769532,47.56749225365282],[7.90740966796875,47.55776216936179],[7.917709350585938,47.545712894408624],[7.929382324218749,47.54640812019053],[7.941741943359374,47.54432241518175],[7.9520416259765625,47.54965238525127],[7.9561614990234375,47.55683540041267],[7.9767608642578125,47.55544521625339],[7.997360229492187,47.556603705614094],[8.019676208496094,47.54965238525127],[8.049888610839844,47.55637200979099],[8.058815002441406,47.56285910557121],[8.072891235351562,47.56355410390809],[8.086967468261719,47.557067094186735],[8.100700378417969,47.56216409801383],[8.105506896972656,47.57976811421671],[8.113059997558594,47.583473468887405],[8.133659362792969,47.58301031389572],[8.138809204101562,47.59042030203756],[8.15185546875,47.59551406038282],[8.166275024414062,47.5941249027327],[8.177261352539062,47.6017648134425],[8.193740844726562,47.616346999837226],[8.2012939453125,47.62120682516921],[8.219490051269531,47.61958693358351],[8.223953247070312,47.61102381568743],[8.222923278808594,47.604774168947614]]],"terms_text":"AGIS OF2011"},{"id":"Aargau-AGIS-2014","name":"Kanton Aargau 25cm (AGIS 2014)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/AGIS2014/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","endDate":"2014-01-01T00:00:00.000Z","startDate":"2014-01-01T00:00:00.000Z","scaleExtent":[8,19],"polygon":[[[8.222923278808594,47.604774168947614],[8.244209289550781,47.613569753973955],[8.294334411621094,47.60986653003798],[8.300857543945312,47.58625231278527],[8.329353332519531,47.569808674020344],[8.382568359375,47.56702895728551],[8.398017883300781,47.57490443821351],[8.424797058105469,47.56795554592218],[8.415184020996094,47.54663986006874],[8.389778137207031,47.5262428287156],[8.372268676757812,47.51233121261258],[8.358535766601562,47.503286684046664],[8.36402893066406,47.48078455918],[8.371238708496094,47.481016589036074],[8.373985290527344,47.47011007802331],[8.368148803710938,47.46825342516445],[8.387031555175781,47.44852243794931],[8.380851745605469,47.447593738482304],[8.384284973144531,47.4355191531953],[8.376388549804688,47.431803338643334],[8.377761840820312,47.42808726171425],[8.389434814453125,47.42739046807988],[8.391494750976562,47.41902822496511],[8.380165100097656,47.40462347023052],[8.364715576171875,47.4016026187529],[8.367118835449219,47.39881398671558],[8.380851745605469,47.39788440990287],[8.39424133300781,47.39439835079049],[8.399734497070312,47.372314620566925],[8.40728759765625,47.37068703239024],[8.404197692871094,47.34417352612498],[8.416213989257812,47.33416935720614],[8.414497375488281,47.32602502961836],[8.452606201171875,47.33254059215931],[8.444023132324219,47.31927592106609],[8.427543640136719,47.29925625338924],[8.390121459960938,47.28854494625744],[8.41175079345703,47.247076403108416],[8.393898010253906,47.227728840642065],[8.404884338378906,47.194845099780174],[8.401451110839844,47.17757880776958],[8.409690856933594,47.17314466448546],[8.412437438964844,47.13976002139446],[8.379478454589844,47.13929295458033],[8.361968994140625,47.14559801038333],[8.342742919921875,47.177112073280966],[8.3056640625,47.24987305653909],[8.295021057128906,47.26268916206698],[8.300514221191406,47.26991141830738],[8.278884887695312,47.28225686421767],[8.259315490722656,47.285983225286174],[8.243522644042969,47.280859411143915],[8.240432739257812,47.27130916053537],[8.228759765625,47.27270686584952],[8.219146728515625,47.25336866567523],[8.204727172851562,47.245444953748034],[8.203353881835938,47.22679624955806],[8.180007934570312,47.22143353240336],[8.171768188476562,47.2279619858493],[8.155975341796875,47.23961793870555],[8.175888061523436,47.24218190428504],[8.17657470703125,47.25406775981567],[8.136062622070312,47.24730946320093],[8.12164306640625,47.24218190428504],[8.10791015625,47.2447457457832],[8.097267150878906,47.259427174956194],[8.077354431152344,47.2603591917818],[8.059844970703125,47.25569894358661],[8.062591552734375,47.24614415248379],[8.016586303710938,47.242881146090085],[8.015899658203125,47.258961160390896],[7.997016906738281,47.2796948387185],[7.951698303222655,47.274337475394645],[7.960968017578125,47.25430078914495],[7.933845520019531,47.237053849043896],[7.911529541015624,47.24381345414034],[7.859344482421875,47.23425651880584],[7.83977508544922,47.23425651880584],[7.826042175292968,47.24427960201268],[7.828102111816407,47.25966018070071],[7.82398223876953,47.26548499105541],[7.8408050537109375,47.273405704663965],[7.848701477050781,47.28551744450745],[7.860374450683594,47.30461109337307],[7.871704101562499,47.31136207506936],[7.8888702392578125,47.31136207506936],[7.897453308105469,47.31904317780638],[7.895393371582031,47.327653995607086],[7.908439636230469,47.340451266106996],[7.9259490966796875,47.332773275955894],[7.94757843017578,47.331609846720866],[7.94757843017578,47.316715688820764],[8.007316589355467,47.33905535093827],[8.004913330078125,47.34533667855891],[8.011093139648438,47.35719936945847],[8.024139404296875,47.36719917429931],[8.032722473144531,47.38393878966209],[8.026885986328125,47.39602520707679],[8.010749816894531,47.3955603961201],[8.004570007324219,47.40671472747142],[7.975730895996094,47.41507892620099],[7.9657745361328125,47.42181578692778],[7.985343933105469,47.425764580393924],[7.971954345703124,47.46105827584221],[7.957534790039062,47.457344265054225],[7.940711975097656,47.46221885041022],[7.946891784667968,47.48403288391224],[7.907066345214844,47.48588897929538],[7.8936767578125,47.50653361720931],[7.873420715332031,47.51325876844644],[7.875480651855468,47.52253342509336],[7.865180969238281,47.51975120023913],[7.856254577636718,47.533660849056794],[7.833251953125,47.5325018525392],[7.834281921386719,47.51465007145751],[7.789649963378906,47.49377665301097],[7.789649963378906,47.518128167602484],[7.7515411376953125,47.52461999690649],[7.731285095214843,47.53203824675999],[7.708969116210937,47.54015075619555],[7.740898132324219,47.54362716173679],[7.761497497558593,47.54895720250044],[7.781410217285156,47.55289644950155],[7.797546386718749,47.55915229204993],[7.805442810058593,47.56563904359584],[7.814369201660155,47.575136052077276],[7.819175720214843,47.58648387645128],[7.8325653076171875,47.586715439092906],[7.843208312988281,47.581620824334166],[7.859344482421875,47.58602074809481],[7.8847503662109375,47.58764167941513],[7.903633117675781,47.58092606572345],[7.911872863769532,47.56749225365282],[7.90740966796875,47.55776216936179],[7.917709350585938,47.545712894408624],[7.929382324218749,47.54640812019053],[7.941741943359374,47.54432241518175],[7.9520416259765625,47.54965238525127],[7.9561614990234375,47.55683540041267],[7.9767608642578125,47.55544521625339],[7.997360229492187,47.556603705614094],[8.019676208496094,47.54965238525127],[8.049888610839844,47.55637200979099],[8.058815002441406,47.56285910557121],[8.072891235351562,47.56355410390809],[8.086967468261719,47.557067094186735],[8.100700378417969,47.56216409801383],[8.105506896972656,47.57976811421671],[8.113059997558594,47.583473468887405],[8.133659362792969,47.58301031389572],[8.138809204101562,47.59042030203756],[8.15185546875,47.59551406038282],[8.166275024414062,47.5941249027327],[8.177261352539062,47.6017648134425],[8.193740844726562,47.616346999837226],[8.2012939453125,47.62120682516921],[8.219490051269531,47.61958693358351],[8.223953247070312,47.61102381568743],[8.222923278808594,47.604774168947614]]],"terms_text":"AGIS OF2014"},{"id":"Aargau-AGIS-2016","name":"Kanton Aargau 25cm (AGIS 2016)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/AGIS2016/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","endDate":"2016-01-01T00:00:00.000Z","startDate":"2016-01-01T00:00:00.000Z","scaleExtent":[8,19],"polygon":[[[8.222923278808594,47.604774168947614],[8.244209289550781,47.613569753973955],[8.294334411621094,47.60986653003798],[8.300857543945312,47.58625231278527],[8.329353332519531,47.569808674020344],[8.382568359375,47.56702895728551],[8.398017883300781,47.57490443821351],[8.424797058105469,47.56795554592218],[8.415184020996094,47.54663986006874],[8.389778137207031,47.5262428287156],[8.372268676757812,47.51233121261258],[8.358535766601562,47.503286684046664],[8.36402893066406,47.48078455918],[8.371238708496094,47.481016589036074],[8.373985290527344,47.47011007802331],[8.368148803710938,47.46825342516445],[8.387031555175781,47.44852243794931],[8.380851745605469,47.447593738482304],[8.384284973144531,47.4355191531953],[8.376388549804688,47.431803338643334],[8.377761840820312,47.42808726171425],[8.389434814453125,47.42739046807988],[8.391494750976562,47.41902822496511],[8.380165100097656,47.40462347023052],[8.364715576171875,47.4016026187529],[8.367118835449219,47.39881398671558],[8.380851745605469,47.39788440990287],[8.39424133300781,47.39439835079049],[8.399734497070312,47.372314620566925],[8.40728759765625,47.37068703239024],[8.404197692871094,47.34417352612498],[8.416213989257812,47.33416935720614],[8.414497375488281,47.32602502961836],[8.452606201171875,47.33254059215931],[8.444023132324219,47.31927592106609],[8.427543640136719,47.29925625338924],[8.390121459960938,47.28854494625744],[8.41175079345703,47.247076403108416],[8.393898010253906,47.227728840642065],[8.404884338378906,47.194845099780174],[8.401451110839844,47.17757880776958],[8.409690856933594,47.17314466448546],[8.412437438964844,47.13976002139446],[8.379478454589844,47.13929295458033],[8.361968994140625,47.14559801038333],[8.342742919921875,47.177112073280966],[8.3056640625,47.24987305653909],[8.295021057128906,47.26268916206698],[8.300514221191406,47.26991141830738],[8.278884887695312,47.28225686421767],[8.259315490722656,47.285983225286174],[8.243522644042969,47.280859411143915],[8.240432739257812,47.27130916053537],[8.228759765625,47.27270686584952],[8.219146728515625,47.25336866567523],[8.204727172851562,47.245444953748034],[8.203353881835938,47.22679624955806],[8.180007934570312,47.22143353240336],[8.171768188476562,47.2279619858493],[8.155975341796875,47.23961793870555],[8.175888061523436,47.24218190428504],[8.17657470703125,47.25406775981567],[8.136062622070312,47.24730946320093],[8.12164306640625,47.24218190428504],[8.10791015625,47.2447457457832],[8.097267150878906,47.259427174956194],[8.077354431152344,47.2603591917818],[8.059844970703125,47.25569894358661],[8.062591552734375,47.24614415248379],[8.016586303710938,47.242881146090085],[8.015899658203125,47.258961160390896],[7.997016906738281,47.2796948387185],[7.951698303222655,47.274337475394645],[7.960968017578125,47.25430078914495],[7.933845520019531,47.237053849043896],[7.911529541015624,47.24381345414034],[7.859344482421875,47.23425651880584],[7.83977508544922,47.23425651880584],[7.826042175292968,47.24427960201268],[7.828102111816407,47.25966018070071],[7.82398223876953,47.26548499105541],[7.8408050537109375,47.273405704663965],[7.848701477050781,47.28551744450745],[7.860374450683594,47.30461109337307],[7.871704101562499,47.31136207506936],[7.8888702392578125,47.31136207506936],[7.897453308105469,47.31904317780638],[7.895393371582031,47.327653995607086],[7.908439636230469,47.340451266106996],[7.9259490966796875,47.332773275955894],[7.94757843017578,47.331609846720866],[7.94757843017578,47.316715688820764],[8.007316589355467,47.33905535093827],[8.004913330078125,47.34533667855891],[8.011093139648438,47.35719936945847],[8.024139404296875,47.36719917429931],[8.032722473144531,47.38393878966209],[8.026885986328125,47.39602520707679],[8.010749816894531,47.3955603961201],[8.004570007324219,47.40671472747142],[7.975730895996094,47.41507892620099],[7.9657745361328125,47.42181578692778],[7.985343933105469,47.425764580393924],[7.971954345703124,47.46105827584221],[7.957534790039062,47.457344265054225],[7.940711975097656,47.46221885041022],[7.946891784667968,47.48403288391224],[7.907066345214844,47.48588897929538],[7.8936767578125,47.50653361720931],[7.873420715332031,47.51325876844644],[7.875480651855468,47.52253342509336],[7.865180969238281,47.51975120023913],[7.856254577636718,47.533660849056794],[7.833251953125,47.5325018525392],[7.834281921386719,47.51465007145751],[7.789649963378906,47.49377665301097],[7.789649963378906,47.518128167602484],[7.7515411376953125,47.52461999690649],[7.731285095214843,47.53203824675999],[7.708969116210937,47.54015075619555],[7.740898132324219,47.54362716173679],[7.761497497558593,47.54895720250044],[7.781410217285156,47.55289644950155],[7.797546386718749,47.55915229204993],[7.805442810058593,47.56563904359584],[7.814369201660155,47.575136052077276],[7.819175720214843,47.58648387645128],[7.8325653076171875,47.586715439092906],[7.843208312988281,47.581620824334166],[7.859344482421875,47.58602074809481],[7.8847503662109375,47.58764167941513],[7.903633117675781,47.58092606572345],[7.911872863769532,47.56749225365282],[7.90740966796875,47.55776216936179],[7.917709350585938,47.545712894408624],[7.929382324218749,47.54640812019053],[7.941741943359374,47.54432241518175],[7.9520416259765625,47.54965238525127],[7.9561614990234375,47.55683540041267],[7.9767608642578125,47.55544521625339],[7.997360229492187,47.556603705614094],[8.019676208496094,47.54965238525127],[8.049888610839844,47.55637200979099],[8.058815002441406,47.56285910557121],[8.072891235351562,47.56355410390809],[8.086967468261719,47.557067094186735],[8.100700378417969,47.56216409801383],[8.105506896972656,47.57976811421671],[8.113059997558594,47.583473468887405],[8.133659362792969,47.58301031389572],[8.138809204101562,47.59042030203756],[8.15185546875,47.59551406038282],[8.166275024414062,47.5941249027327],[8.177261352539062,47.6017648134425],[8.193740844726562,47.616346999837226],[8.2012939453125,47.62120682516921],[8.219490051269531,47.61958693358351],[8.223953247070312,47.61102381568743],[8.222923278808594,47.604774168947614]]],"terms_text":"AGIS OF2016","best":true},{"id":"Basel-Landschaft-2015","name":"Kanton Basel-Landschaft 10cm (2015)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/KTBASELLANDSCHAFT2015/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[18,21],"polygon":[[[7.370281219482422,47.413684985326796],[7.357578277587891,47.41507892620101],[7.357921600341797,47.41827323486739],[7.353544235229492,47.4196089792119],[7.344875335693359,47.42402250214274],[7.339725494384765,47.42971307765559],[7.332687377929687,47.430235650685475],[7.32685089111328,47.4319194618196],[7.325280543317693,47.43489176778178],[7.33050406703179,47.44175856152086],[7.338990092194756,47.44109169292469],[7.344964876980962,47.43607806019703],[7.352656881264292,47.43435807026775],[7.38119797480828,47.432081698142134],[7.375988960266113,47.414309359238985],[7.378145456314087,47.41399717320828],[7.382040023803711,47.41330745332341],[7.388391494750976,47.41397539271845],[7.413708184603623,47.410929293287566],[7.420743520414262,47.411098781635985],[7.427483310496426,47.41448047082256],[7.438105529405026,47.412739349590474],[7.448396898794484,47.41507114537187],[7.455576414208223,47.42792319548619],[7.45061852232364,47.43534476535272],[7.437842682352891,47.446323188615104],[7.425422575234655,47.443283894442736],[7.420904049355535,47.44594415975335],[7.422417620777747,47.45071647996838],[7.428795928789581,47.45387944195848],[7.430028776685507,47.459491697398036],[7.445765194338128,47.46197276972992],[7.44717015944249,47.456958090215814],[7.456512189239691,47.44925575541638],[7.492356675875099,47.458972279610066],[7.530679075390223,47.46118857622267],[7.527445320030451,47.473906165741866],[7.536326693749955,47.48383279861684],[7.536231113003725,47.49105266753894],[7.532603895549507,47.490968962664795],[7.531789123586811,47.49739885661967],[7.520038351186771,47.49678264400428],[7.512226152318425,47.49891674929323],[7.509348758631863,47.508884893812876],[7.499082452238831,47.51627805213703],[7.497870355425969,47.52124757864722],[7.502278119030558,47.514906577969604],[7.517459288006065,47.51728104695845],[7.522200236749534,47.514091442409054],[7.530955756497733,47.52904526885427],[7.519353655277215,47.53471778813415],[7.510751927105658,47.528989768842564],[7.50229842095598,47.52840455858729],[7.4980383403841,47.536152181750076],[7.505454651706732,47.54438188661593],[7.516758242758337,47.545408295649786],[7.527317399933993,47.552778846515565],[7.554658254426867,47.564368052237306],[7.5645783501094,47.55703599040843],[7.561243624111692,47.55172275211291],[7.558752685660356,47.55235329499035],[7.555882119169953,47.54433555917895],[7.564785321950861,47.54568625396918],[7.587263056821628,47.54190064304111],[7.582688476068778,47.53246814131337],[7.589482524394103,47.5279230654027],[7.590248428005343,47.51978966346127],[7.594781326929009,47.51929395578897],[7.613780785019665,47.53925099543145],[7.622303281783164,47.53977428916004],[7.622854488041502,47.550040256825795],[7.617740918118178,47.554366555487356],[7.617617220103555,47.558648485827725],[7.632727781497729,47.5614887674157],[7.639973682410965,47.55816478484801],[7.648995462809379,47.548295861439875],[7.661308760240334,47.544832242956765],[7.665860164458853,47.53745814872834],[7.674674254363578,47.5337535789565],[7.694938989531916,47.532496041115465],[7.71346844906592,47.53978344629896],[7.715956243413761,47.53582195507857],[7.723622825374551,47.536754165368905],[7.727157067196862,47.53293048764033],[7.733221863174538,47.53275465944404],[7.737974130690588,47.52732498381306],[7.749022330706917,47.5249849998809],[7.757861753102653,47.52605097450287],[7.787633628417415,47.52011695778467],[7.790143521321244,47.51864117486466],[7.788870069574476,47.50682929074843],[7.792799480290271,47.500684271209245],[7.786625359342518,47.49312139201968],[7.798890147748131,47.49565149600841],[7.798162871694108,47.49939947973339],[7.799400121334925,47.497477088945935],[7.807418124234862,47.4971384859743],[7.814709929059118,47.504801278976316],[7.831976267472122,47.51473657456054],[7.833207588232065,47.53382387257594],[7.846527268275818,47.53266095290337],[7.852330295179702,47.53523506225097],[7.862569292788096,47.52692027402488],[7.86395674074442,47.519309183202445],[7.876658649367283,47.52269034821798],[7.87567113137545,47.51319304945735],[7.893993798731052,47.50605656803392],[7.904769180395594,47.49217505264052],[7.904821911502771,47.48490926161113],[7.93328835504665,47.48140776210853],[7.947015241408695,47.48488995686335],[7.940027875634228,47.462021295570224],[7.948854362289874,47.46377967418039],[7.957614193951437,47.45880646812721],[7.957849013566705,47.451279351685564],[7.946784554043733,47.44319336966537],[7.950032053627354,47.431716361052416],[7.96183169437885,47.421834282667845],[7.956570351591289,47.41968057428149],[7.955037646053525,47.415605646331336],[7.948388855309641,47.4162657867356],[7.934927870271696,47.41176694218953],[7.936722434714782,47.408057452805856],[7.932661510641391,47.40527495151619],[7.909737672400531,47.398520997340924],[7.890221593189976,47.407141074214024],[7.883331964118422,47.40609724771633],[7.883443085719068,47.4012049891245],[7.877702761222016,47.401257097623],[7.869136696167237,47.3955142728722],[7.879434713089799,47.38799354849815],[7.878812180597903,47.38351047538804],[7.862650230995195,47.38198499163919],[7.840119046365023,47.374763282921705],[7.830547227518145,47.36512144155488],[7.80216648325237,47.36109584064414],[7.796366151294341,47.3534705803715],[7.793560892325092,47.33905227137494],[7.78528803737905,47.3378822997136],[7.768963133383802,47.33891408469915],[7.766419194330703,47.342734660857005],[7.751518928544542,47.3443274446774],[7.734153146629586,47.35776074638933],[7.727913718160677,47.36885889855421],[7.701953574259492,47.37244716296033],[7.644203220263186,47.36720838530677],[7.641761060331779,47.38046937860509],[7.635580022356337,47.38059279713257],[7.633316986492583,47.38291397270416],[7.633305398225418,47.38533959871929],[7.637251158279386,47.38606854199808],[7.63272275093214,47.41003108104519],[7.664054730400831,47.41001995588381],[7.679802017668389,47.41751395224505],[7.686578998003315,47.43366406703297],[7.682972441800632,47.43872228466388],[7.684853783500164,47.447843589969715],[7.692273418589347,47.45421309996921],[7.698831030331891,47.45585888435835],[7.699930658071183,47.46190517358485],[7.709877972706822,47.469384739707586],[7.699760966314013,47.48063247960835],[7.668326578902932,47.48634665620256],[7.666120855554305,47.49686816039971],[7.65217109717027,47.49581439933043],[7.648646287658441,47.49183004211102],[7.655389581170213,47.49020559719241],[7.650513795302598,47.48826095607083],[7.655925875394832,47.48739459757455],[7.644422678687097,47.485637798180356],[7.640965961473804,47.482734093980326],[7.607299799570857,47.48939839412024],[7.608850381582776,47.48352506892989],[7.605631268762133,47.47935909729055],[7.608148977008936,47.475213682276376],[7.604494899927722,47.47044546774548],[7.618872436050056,47.4674530520825],[7.626072253389216,47.462913883669614],[7.62217338539308,47.46195224188912],[7.616464591762502,47.445234574416695],[7.615798850305441,47.432747890966844],[7.592069133423196,47.43271179535717],[7.581206884670679,47.42878068945942],[7.578423275099778,47.434906655087865],[7.568904367023134,47.43689695884281],[7.56829539909203,47.42233486107083],[7.58074128785892,47.414703988151935],[7.525235194936931,47.41163289737562],[7.531172340312734,47.40352507464003],[7.518616677418122,47.38822295597742],[7.511295677347134,47.38974369796625],[7.502255661148456,47.384806980223004],[7.492327480628366,47.385231761698726],[7.478410241257615,47.39055778320416],[7.47746817801916,47.401277162725364],[7.464484018734026,47.40251498235377],[7.460919593518167,47.40068414452088],[7.450020783333588,47.40392739156406],[7.44951323519806,47.39975827367453],[7.443401098004909,47.40231427489849],[7.441311347159463,47.40017886074712],[7.443566657511773,47.38890284041263],[7.437324174770898,47.3808884773088],[7.411692544769116,47.38057235919037],[7.416276198506335,47.384788794341716],[7.414494030814171,47.39429988358522],[7.398935569419335,47.39683906243558],[7.395920463999715,47.40338304393273],[7.388693876865087,47.403019088497395],[7.384054886906365,47.4123601395877],[7.379679679870605,47.4128137535428],[7.375844120979309,47.41401169352981],[7.370281219482422,47.413684985326796]]],"terms_url":"http://www.geo.bl.ch/fileadmin/user_upload/Geodaten/Nutzungsbedingungen_GBD_BL_V3p1.pdf","terms_text":"Geodaten des Kantons Basel-Landschaft 2015","best":true},{"id":"KTBASELSTADT2015","name":"Kanton Basel-Stadt 2015","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/KTBASELSTADT2015/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,21],"polygon":[[[7.492,47.4817],[7.492,47.6342],[7.784,47.6342],[7.784,47.4817],[7.492,47.4817]]],"terms_text":"Kanton Basel-Stadt OF 2015"},{"id":"Solothurn-sogis2014-tms","name":"Kanton Solothurn 25cm (SOGIS 2014-2015)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/sogis2014/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[15,19],"polygon":[[[7.3404127,47.2175697],[7.4154818,47.2402115],[7.4173645,47.2537956],[7.4658424,47.2646513],[7.4946766,47.2882287],[7.5328638,47.294534],[7.5483333,47.3163566],[7.5709479,47.3263111],[7.5604584,47.342492],[7.5388991,47.3476266],[7.5396485,47.3601134],[7.5217459,47.3651488],[7.5237238,47.3720704],[7.4634937,47.3702566],[7.4361035,47.3781317],[7.4434011,47.4023143],[7.4774682,47.4012772],[7.4792364,47.3897076],[7.5022557,47.384807],[7.5213659,47.3912021],[7.5311724,47.4035251],[7.5252352,47.4116329],[7.5807413,47.414704],[7.5682954,47.4223349],[7.5689044,47.436897],[7.5812069,47.4287807],[7.6157989,47.4327479],[7.6260723,47.4629139],[7.6044949,47.4704455],[7.6072998,47.4893984],[7.640966,47.4827341],[7.6559259,47.4873946],[7.6521711,47.4958144],[7.6661209,47.4968682],[7.6683266,47.4863467],[7.699761,47.4806325],[7.709878,47.4693848],[7.6848538,47.4478436],[7.6798021,47.417514],[7.6327228,47.4100311],[7.633317,47.382914],[7.6417611,47.3804694],[7.6442033,47.3672084],[7.7279138,47.3688589],[7.751519,47.3443275],[7.7935609,47.3390523],[7.8021665,47.3610959],[7.8788122,47.3835105],[7.8691367,47.3955143],[7.883332,47.4060973],[7.9097377,47.398521],[7.9550377,47.4156057],[7.9618317,47.4218343],[7.9467846,47.4431934],[7.9682836,47.4628082],[7.9872707,47.4287435],[7.9854653,47.4227641],[7.9827035,47.4283325],[7.9631993,47.4223547],[8.0072617,47.4065858],[8.0100022,47.395418],[8.0265612,47.3956224],[8.0313669,47.3836856],[8.0038366,47.3453146],[8.0051906,47.3367516],[7.9479701,47.3171432],[7.9478307,47.3325169],[7.9192088,47.3339507],[7.9078055,47.341719],[7.889098,47.3114878],[7.8611018,47.3061239],[7.8418057,47.2744707],[7.8166423,47.2616706],[7.8028241,47.2684079],[7.7861469,47.256098],[7.7746009,47.267869],[7.7568187,47.258095],[7.7326672,47.2591133],[7.684769,47.2939919],[7.6482742,47.2819898],[7.5801066,47.2763483],[7.5936981,47.2662199],[7.5959384,47.245569],[7.6261802,47.2263143],[7.6405558,47.2297944],[7.6484666,47.2189525],[7.6472258,47.2017823],[7.6715278,47.1949714],[7.6711002,47.1845216],[7.6779881,47.1819259],[7.6728612,47.1683945],[7.6600808,47.1684026],[7.6451021,47.1489207],[7.6155322,47.1565739],[7.5861404,47.1475453],[7.5810534,47.16013],[7.5634674,47.1683541],[7.5257686,47.162205],[7.5203336,47.1588879],[7.5297508,47.1487369],[7.5097234,47.1255457],[7.4613252,47.1082327],[7.4750945,47.0867101],[7.454461,47.074927],[7.4354156,47.0801664],[7.4340002,47.1005003],[7.3820271,47.0957398],[7.3704914,47.1209312],[7.4401788,47.1237276],[7.4217922,47.1358605],[7.447783,47.1550805],[7.4728074,47.1525609],[7.4970383,47.1700873],[7.4804964,47.171738],[7.4708545,47.181324],[7.4757226,47.1906485],[7.4497638,47.1895691],[7.4476258,47.1810839],[7.4332849,47.1847269],[7.4118135,47.1624212],[7.3842442,47.1601249],[7.3821749,47.1651186],[7.391911,47.1662739],[7.3835137,47.1803011],[7.3654609,47.1944525],[7.3544799,47.1915316],[7.3404127,47.2175697]],[[7.420816,47.4803666],[7.4349836,47.4981011],[7.4707584,47.480734],[7.487277,47.4820136],[7.5116652,47.5026958],[7.5317892,47.4973989],[7.5366964,47.4850517],[7.5274454,47.4739062],[7.5306791,47.4611886],[7.4565122,47.4492558],[7.445214,47.4623781],[7.4557367,47.4733767],[7.420816,47.4803666]],[[7.3759458,47.4140995],[7.3821514,47.4330266],[7.4209041,47.4459442],[7.4378427,47.4463232],[7.4555765,47.4279232],[7.4437574,47.413444],[7.3759458,47.4140995]],[[7.6744234,47.1539707],[7.6853662,47.1662986],[7.7007985,47.1617746],[7.6901531,47.1525567],[7.6744234,47.1539707]]],"terms_text":"Orthofoto WMS Solothurn","best":true,"icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAIVBMVEX///+LKCbMAABycnL+/v7v7+9sbGz39/fz8/Pw8PD8/Pz60siYAAAAAWJLR0QAiAUdSAAAAAd0SU1FB+AIGAsXN84mS+sAAAA4SURBVAjXY2AUBAMBBkYlMCCXwcwABgZYGCwGIJo5AMQGAjYgLgYxLICY05iBwRisjsvY2IGBAQAGpQmjMKkg/wAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNi0wOC0yNFQxMToyMzo1NS0wNDowMLEFqzIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTYtMDgtMjRUMTE6MjM6NTUtMDQ6MDDAWBOOAAAAAElFTkSuQmCC"},{"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","endDate":"2012-05-14T00:00:00.000Z","startDate":"2012-05-13T00:00:00.000Z","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]]],"description":"High quality aerial imagery taken for the City of Kelowna"},{"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","endDate":"2013-09-03T00:00:00.000Z","startDate":"2013-09-03T00:00:00.000Z","scaleExtent":[5,14],"polygon":[[[-60.8550011,6.1765004],[-60.4762612,7.9188291],[-62.161689,8.2778675],[-62.5322549,6.5375488],[-60.8550011,6.1765004]]],"description":"Recent Landsat imagery"},{"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","endDate":"2013-09-12T00:00:00.000Z","startDate":"2013-09-12T00:00:00.000Z","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]]],"description":"Recent lower-resolution landsat imagery for southwest British Columbia"},{"id":"LINZ_NZ_Aerial_Imagery","name":"LINZ NZ Aerial Imagery","type":"tms","template":"https://tiles-a.data-cdn.linz.govt.nz/services;key=3197c6d0e5cb494a95d58dc2de3216c2/tiles/v4/set=2/EPSG:3857/{zoom}/{x}/{y}.png","scaleExtent":[0,21],"polygon":[[[167.2503662109375,-47.21956811231548],[167.244873046875,-47.28016067076474],[167.5030517578125,-47.37975438400816],[168.2501220703125,-47.15610477504402],[168.7445068359375,-46.79629898997744],[169.3267822265625,-46.75491661928188],[169.78271484375,-46.604167162931844],[170.4254150390625,-46.11132565729794],[170.804443359375,-45.95114968669139],[170.9527587890625,-45.440862671781744],[171.309814453125,-44.91035917458493],[171.40869140625,-44.39061697878681],[172.562255859375,-43.92954993561458],[172.90283203125,-43.96909818325171],[173.1610107421875,-43.90976594390799],[173.2598876953125,-43.69567969789881],[172.9742431640625,-43.53660274231031],[172.760009765625,-43.37710501700071],[173.1500244140625,-43.17714134663171],[173.704833984375,-42.63395872267314],[174.36401367187497,-41.78360106648077],[174.320068359375,-41.409775832009544],[174.84741210937497,-41.52914198872309],[175.0726318359375,-41.70572851523751],[175.506591796875,-41.672911819602085],[176.2261962890625,-41.10832999732831],[176.8304443359375,-40.42604212826493],[177.17102050781247,-39.67337039176559],[177.0391845703125,-39.39375459224347],[177.4456787109375,-39.18117526158747],[177.60498046875,-39.3300485529424],[177.978515625,-39.368279149160124],[178.3355712890625,-38.65977773071253],[178.7091064453125,-37.74465712069938],[178.626708984375,-37.54457732085582],[178.3135986328125,-37.43125050179357],[177.6214599609375,-37.37888785004525],[177.0391845703125,-37.39634613318924],[176.561279296875,-37.37015718405751],[176.3360595703125,-37.05956083025124],[176.0064697265625,-36.29741818650809],[175.6768798828125,-36.05354012833974],[174.671630859375,-35.1782983520012],[173.1939697265625,-34.28445325435288],[172.6776123046875,-34.234512362369856],[172.386474609375,-34.40237742424137],[172.4798583984375,-34.71903991764788],[172.9852294921875,-35.32184842037683],[173.56201171875,-36.142310873529986],[174.30908203125,-37.077093191754415],[174.5562744140625,-38.052416771864834],[174.4793701171875,-38.655488159952995],[174.3255615234375,-38.865374851611634],[173.7982177734375,-38.95940879245421],[173.60595703125,-39.232253141714885],[173.6993408203125,-39.56335316582929],[174.5892333984375,-39.95606977009003],[174.9847412109375,-40.216635475391215],[174.9847412109375,-40.49291502689579],[174.7210693359375,-40.805493843894155],[174.1497802734375,-40.65147128144056],[173.2818603515625,-40.43440488077009],[172.5897216796875,-40.350730565917885],[172.0843505859375,-40.534676780615406],[171.7657470703125,-40.826280356677124],[171.57348632812497,-41.3974150664646],[171.2823486328125,-41.652392884268124],[170.8758544921875,-42.53284428171312],[170.35400390625,-42.87193842444846],[168.277587890625,-43.92954993561458],[167.6239013671875,-44.47691085722324],[166.55273437499997,-45.38687734827038],[166.27258300781247,-45.916765867649],[166.4813232421875,-46.22545288226937],[167.6788330078125,-46.471916320870406],[167.2503662109375,-47.21956811231548]]],"terms_url":"http://www.linz.govt.nz/data/licensing-and-using-data/attributing-elevation-or-aerial-imagery-data","terms_text":"Sourced from LINZ CC-BY 3.0","best":true},{"id":"LINZ_NZ_Topo50_Gridless_Maps","name":"LINZ NZ Topo50 Gridless Maps","type":"tms","template":"https://tiles-a.data-cdn.linz.govt.nz/services;key=3197c6d0e5cb494a95d58dc2de3216c2/tiles/v4/layer=2343/EPSG:3857/{zoom}/{x}/{y}.png","scaleExtent":[0,21],"polygon":[[[167.2503662109375,-47.21956811231548],[167.244873046875,-47.28016067076474],[167.5030517578125,-47.37975438400816],[168.2501220703125,-47.15610477504402],[168.7445068359375,-46.79629898997744],[169.3267822265625,-46.75491661928188],[169.78271484375,-46.604167162931844],[170.4254150390625,-46.11132565729794],[170.804443359375,-45.95114968669139],[170.9527587890625,-45.440862671781744],[171.309814453125,-44.91035917458493],[171.40869140625,-44.39061697878681],[172.562255859375,-43.92954993561458],[172.90283203125,-43.96909818325171],[173.1610107421875,-43.90976594390799],[173.2598876953125,-43.69567969789881],[172.9742431640625,-43.53660274231031],[172.760009765625,-43.37710501700071],[173.1500244140625,-43.17714134663171],[173.704833984375,-42.63395872267314],[174.36401367187497,-41.78360106648077],[174.320068359375,-41.409775832009544],[174.84741210937497,-41.52914198872309],[175.0726318359375,-41.70572851523751],[175.506591796875,-41.672911819602085],[176.2261962890625,-41.10832999732831],[176.8304443359375,-40.42604212826493],[177.17102050781247,-39.67337039176559],[177.0391845703125,-39.39375459224347],[177.4456787109375,-39.18117526158747],[177.60498046875,-39.3300485529424],[177.978515625,-39.368279149160124],[178.3355712890625,-38.65977773071253],[178.7091064453125,-37.74465712069938],[178.626708984375,-37.54457732085582],[178.3135986328125,-37.43125050179357],[177.6214599609375,-37.37888785004525],[177.0391845703125,-37.39634613318924],[176.561279296875,-37.37015718405751],[176.3360595703125,-37.05956083025124],[176.0064697265625,-36.29741818650809],[175.6768798828125,-36.05354012833974],[174.671630859375,-35.1782983520012],[173.1939697265625,-34.28445325435288],[172.6776123046875,-34.234512362369856],[172.386474609375,-34.40237742424137],[172.4798583984375,-34.71903991764788],[172.9852294921875,-35.32184842037683],[173.56201171875,-36.142310873529986],[174.30908203125,-37.077093191754415],[174.5562744140625,-38.052416771864834],[174.4793701171875,-38.655488159952995],[174.3255615234375,-38.865374851611634],[173.7982177734375,-38.95940879245421],[173.60595703125,-39.232253141714885],[173.6993408203125,-39.56335316582929],[174.5892333984375,-39.95606977009003],[174.9847412109375,-40.216635475391215],[174.9847412109375,-40.49291502689579],[174.7210693359375,-40.805493843894155],[174.1497802734375,-40.65147128144056],[173.2818603515625,-40.43440488077009],[172.5897216796875,-40.350730565917885],[172.0843505859375,-40.534676780615406],[171.7657470703125,-40.826280356677124],[171.57348632812497,-41.3974150664646],[171.2823486328125,-41.652392884268124],[170.8758544921875,-42.53284428171312],[170.35400390625,-42.87193842444846],[168.277587890625,-43.92954993561458],[167.6239013671875,-44.47691085722324],[166.55273437499997,-45.38687734827038],[166.27258300781247,-45.916765867649],[166.4813232421875,-46.22545288226937],[167.6788330078125,-46.471916320870406],[167.2503662109375,-47.21956811231548]]],"terms_url":"https://data.linz.govt.nz/layer/2343-nz-mainland-topo50-gridless-maps/","terms_text":"Sourced from the LINZ Data Service and licensed by LINZ for re-use under the Creative Commons Attribution 3.0 New Zealand licence."},{"id":"ORT10LT","name":"Lithuania - NŽT ORT10LT","type":"tms","template":"http://ort10lt.openmap.lt/g16/{zoom}/{x}/{y}.jpeg","endDate":"2016-01-01T00:00:00.000Z","startDate":"2010-01-01T00:00:00.000Z","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","scaleExtent":[0,16],"overzoom":false,"terms_url":"http://www.mapbox.com/about/maps/","terms_text":"Terms & Feedback","default":true,"description":"Shows major features to help orient you.","overlay":true},{"id":"londrina2011","name":"Londrina Ortofoto 2011","type":"tms","template":"https://siglon.londrina.pr.gov.br/arcgis/rest/services/Imagens/Ortofotos_2011_Paranacidade/MapServer/WMTS/tile/1.0.0/Imagens_Ortofotos_2011_Paranacidade/default/GoogleMapsCompatible/{zoom}/{y}/{x}","polygon":[[[-51.10903142008701,-23.392750890870328],[-51.110147219037096,-23.39111628244602],[-51.111981850003126,-23.389599820448623],[-51.11358044657587,-23.38976722295012],[-51.120999436701226,-23.38592675938185],[-51.12224934611127,-23.385109415587607],[-51.12483499560139,-23.383504255873166],[-51.12538216624037,-23.38186953335707],[-51.12482426676533,-23.37770385409619],[-51.12445948633935,-23.375054689723584],[-51.124373655650885,-23.372297138974446],[-51.12244246516032,-23.37032742475139],[-51.12302182230749,-23.366427304263887],[-51.128557901713755,-23.36548180323493],[-51.12832186732048,-23.358843408308623],[-51.12477062258506,-23.35475580404945],[-51.12703440699343,-23.35091432623551],[-51.12411616358548,-23.34679692655685],[-51.12025378260435,-23.347811512977742],[-51.1176466754421,-23.33969460448754],[-51.11264703783877,-23.341290443649072],[-51.109396200513004,-23.33488726938344],[-51.10756156954697,-23.334089313725826],[-51.10485790286019,-23.333980949007543],[-51.10252974543546,-23.334187827029368],[-51.09986899409291,-23.331015661953632],[-51.09801290545476,-23.329360589233605],[-51.09998701128955,-23.32830645478855],[-51.10322711977927,-23.325321337105603],[-51.10472915682748,-23.323193291476684],[-51.104664783811145,-23.321291814470847],[-51.10514758143378,-23.318444474199904],[-51.1063599399084,-23.3157547161216],[-51.10660670313775,-23.31467091543279],[-51.11050127062705,-23.311665785493048],[-51.111584883068964,-23.30842411016493],[-51.099504213666904,-23.309468549142686],[-51.09740136179941,-23.308631027972474],[-51.09511611971892,-23.307448636164267],[-51.09201548609798,-23.3049360186679],[-51.09036324534495,-23.3037141796735],[-51.09204767260616,-23.29874787986134],[-51.09269140276969,-23.297496421894902],[-51.09407542262125,-23.292953629109174],[-51.10073802981369,-23.293318240761657],[-51.10101697955121,-23.28870632248831],[-51.10068438563339,-23.28837126237015],[-51.10084531817427,-23.28777997775132],[-51.09937546763423,-23.28663682004102],[-51.09631774935752,-23.277914991984613],[-51.10285161051725,-23.273016720553397],[-51.10835550341534,-23.27033590016574],[-51.11309764895328,-23.268404099092194],[-51.13160489115448,-23.265338785827712],[-51.13188384089201,-23.262007272160396],[-51.1317336371872,-23.255058136908826],[-51.13290308031759,-23.254683563301587],[-51.132956724497895,-23.250750476893938],[-51.13473771128364,-23.2512729236245],[-51.13533852610292,-23.25133206840842],[-51.13516686472599,-23.24359373640034],[-51.13534925493897,-23.24117849627157],[-51.137516479822814,-23.24219388826517],[-51.13884685549409,-23.243495156026544],[-51.14108918223035,-23.24521044413634],[-51.1471724322756,-23.243179698340864],[-51.14761231455401,-23.23828015040167],[-51.149082165094036,-23.235884531292832],[-51.14976881060179,-23.236811236789336],[-51.15138886484666,-23.23853646924079],[-51.15289090189487,-23.238842079520833],[-51.15383503946804,-23.238950521710013],[-51.15820167574391,-23.238142132361276],[-51.16045473131624,-23.238161849232945],[-51.160347442955654,-23.24658068718069],[-51.15912435564498,-23.2478326235554],[-51.16131303820094,-23.247773477219496],[-51.166591625541805,-23.245939927797],[-51.17193458589902,-23.245821633420345],[-51.17205260309565,-23.249557713480034],[-51.174241285651625,-23.248404370116877],[-51.17514250788055,-23.2493211310392],[-51.176859121649926,-23.248157927934038],[-51.179466228812196,-23.251686936561047],[-51.18135450395853,-23.253806268366073],[-51.18273852381009,-23.253628837227893],[-51.18378994974384,-23.253264116924615],[-51.18495939287424,-23.253303546194683],[-51.18626831087339,-23.252150235227905],[-51.18665454897149,-23.247477745146526],[-51.191182117788244,-23.249143693933142],[-51.19141815218154,-23.252859966234126],[-51.19369266542598,-23.252781107419985],[-51.1938428691308,-23.26073575534214],[-51.20096681627374,-23.26054847664639],[-51.20126722368338,-23.24259807127726],[-51.209936123218775,-23.242775517090898],[-51.21090171846407,-23.26988252079656],[-51.21968863519614,-23.27221839365197],[-51.225965004290465,-23.2745345140599],[-51.22934458764894,-23.27860487489667],[-51.234515886629225,-23.28160089636689],[-51.23497722657975,-23.283246708422755],[-51.235073786104266,-23.285444377831148],[-51.23371122392482,-23.285897704227196],[-51.232155542696304,-23.28801649191402],[-51.22870085748543,-23.292293383844925],[-51.227402668322334,-23.294599300809004],[-51.22679112466699,-23.295476327114592],[-51.225600223864475,-23.29657013833941],[-51.22392652543933,-23.297210654251764],[-51.220482569064515,-23.30072850975029],[-51.21863720926242,-23.301300029310937],[-51.21668456109974,-23.30211788923888],[-51.21423838647836,-23.30441378240661],[-51.210966091480465,-23.306965823153238],[-51.22328279527583,-23.318296686707587],[-51.224387865389886,-23.31459209321986],[-51.22521398576639,-23.312887551432937],[-51.22511742624187,-23.312582111000477],[-51.22521398576639,-23.312513140483127],[-51.2255251220121,-23.312532846348883],[-51.22595427545445,-23.312385052284572],[-51.22616885217561,-23.31183328632629],[-51.22935531648505,-23.314887676277397],[-51.22802494081377,-23.31661189768144],[-51.227885465945,-23.31901591762422],[-51.22767088922384,-23.320227763653186],[-51.22723100694544,-23.321508564518947],[-51.2273919394863,-23.322227778055023],[-51.22725246461755,-23.322848466059934],[-51.230331640566384,-23.325577488448165],[-51.23046038659909,-23.326710459617892],[-51.229537706698046,-23.32789268010374],[-51.229162197436,-23.330503379743732],[-51.229290943468705,-23.33178408156439],[-51.22681258233914,-23.334473515196468],[-51.2260186484708,-23.336571826694826],[-51.22473118814376,-23.33839427691611],[-51.22210262330938,-23.340226553005806],[-51.22257469209598,-23.34196029634743],[-51.22380850824271,-23.343388647432523],[-51.22384069475089,-23.345309509145306],[-51.22440932306201,-23.347003784611864],[-51.2245380690947,-23.348294177581966],[-51.22404454263601,-23.34968305981433],[-51.22350810083308,-23.35010661675208],[-51.22381923707877,-23.35076657486812],[-51.22304676088255,-23.35174173085325],[-51.22259614976809,-23.35296312824164],[-51.22586844476598,-23.35480505304304],[-51.22650144609346,-23.36705763453823],[-51.22354028734128,-23.369145582171885],[-51.22366903337377,-23.37968330666716],[-51.220375280703756,-23.381633186264455],[-51.216469984378406,-23.38170212087667],[-51.21416328462579,-23.379949201028825],[-51.2092816642191,-23.37395167630701],[-51.20738266023672,-23.368141007697016],[-51.20628831895872,-23.36723491438801],[-51.20472190889416,-23.366269721227162],[-51.198230963078665,-23.366683376299132],[-51.19297383340994,-23.366506095711998],[-51.18986247095292,-23.3654424072124],[-51.18806002649507,-23.36464463523902],[-51.18718026193825,-23.3645264463904],[-51.18579624208668,-23.363738518041337],[-51.183038931219606,-23.36359078095478],[-51.18071077379488,-23.3637582163071],[-51.179069261877906,-23.361581540240305],[-51.177642326682125,-23.35836078207346],[-51.16683838877106,-23.356262814974126],[-51.166141014427254,-23.358538073547532],[-51.16475699457568,-23.360389770338585],[-51.16076586756186,-23.359217688669915],[-51.15983245882475,-23.36660458495632],[-51.162042599052846,-23.36861374957437],[-51.16276143106877,-23.374158492021696],[-51.158448438973174,-23.37580315788644],[-51.155047397942575,-23.376305417047273],[-51.15396378550066,-23.37903334042617],[-51.15298746141932,-23.381052164536694],[-51.15118501696147,-23.382076336717283],[-51.149167995782435,-23.382509637949354],[-51.14721534761976,-23.382155118864866],[-51.14517686876862,-23.382588419839323],[-51.14410398516276,-23.38376029492248],[-51.14512322458833,-23.388083341091015],[-51.141797285410156,-23.389402876058366],[-51.14030597719799,-23.38880219385971],[-51.14068148646006,-23.391608636504017],[-51.14127157244328,-23.393538646762796],[-51.14093897852546,-23.394434713394368],[-51.140456180902824,-23.39536031431835],[-51.13939402613302,-23.395104297688697],[-51.13738773379004,-23.393154616350518],[-51.13608954462695,-23.389796764546077],[-51.13428710016909,-23.389757375749994],[-51.132162790629465,-23.390072485790583],[-51.13172290835106,-23.39285920758337],[-51.12259266886514,-23.38864463742227],[-51.12228153261944,-23.391657871809155],[-51.11882684740854,-23.393174310244916],[-51.115683298443365,-23.393351555162592],[-51.10903142008701,-23.392750890870328]],[[-51.13829432042955,-23.41600741009485],[-51.133310776080314,-23.418665600378624],[-51.132087688769644,-23.416440600302334],[-51.13002238782791,-23.418291487939495],[-51.12868664773901,-23.419010176689888],[-51.12824140104259,-23.42102839134528],[-51.12696466955051,-23.421860280620358],[-51.12532852205271,-23.422692164660027],[-51.1244541219139,-23.420969322085504],[-51.1215144208339,-23.424109801147612],[-51.12063465627703,-23.423268081315832],[-51.11970661195797,-23.423120410617486],[-51.11977098497433,-23.42156985833077],[-51.1188000253111,-23.421545246243184],[-51.11643431696008,-23.420836416154565],[-51.11942766222045,-23.419167696990424],[-51.11787198099193,-23.416775337218567],[-51.116546969738685,-23.41730697646229],[-51.115699391690086,-23.415702207051474],[-51.115120034542905,-23.413088261827834],[-51.119078975048524,-23.411114231305813],[-51.119599323597356,-23.41169512115064],[-51.12052200349841,-23.41489489238112],[-51.12147686990764,-23.417139608782644],[-51.12308619531643,-23.418626220171642],[-51.12754939111684,-23.41653905242448],[-51.12803218873949,-23.417395582795194],[-51.13119719537679,-23.415574218468866],[-51.13080022844262,-23.414766903017576],[-51.13278506311348,-23.41264029239725],[-51.13521514448077,-23.411055157619415],[-51.13585887464424,-23.410956701416854],[-51.13682446988958,-23.411188073376714],[-51.137205343569626,-23.411576974270133],[-51.13730190309418,-23.41324086645236],[-51.137430649126884,-23.414707830961888],[-51.13829432042955,-23.41600741009485]],[[-51.18929065852,-23.61469318354],[-51.18868716149,-23.61385268133],[-51.18817754178,-23.61338573333],[-51.18731118826,-23.61301708899],[-51.18628926663,-23.61314488581],[-51.18401743559,-23.61395590119],[-51.18348904042,-23.61396573165],[-51.18183143525,-23.61283522407],[-51.18140496401,-23.61344471632],[-51.18062980561,-23.61313505529],[-51.18001021533,-23.61409352754],[-51.17865838198,-23.61328742827],[-51.18064589886,-23.61060367181],[-51.17972321896,-23.61018095058],[-51.18061639456,-23.60849005203],[-51.1821157494,-23.60850479833],[-51.18260927586,-23.60775273479],[-51.18319936184,-23.60804274673],[-51.18415154605,-23.60627808786],[-51.18511177687,-23.60666149766],[-51.18649043231,-23.60469528171],[-51.18902243762,-23.60610112912],[-51.18821241049,-23.60741848294],[-51.18918873458,-23.60801816947],[-51.188899056,-23.60953211999],[-51.18962325244,-23.60992535103],[-51.1911896625,-23.6111935131],[-51.1901489654,-23.61244691705],[-51.19054056792,-23.6127565797],[-51.19029380469,-23.61377895281],[-51.18929065852,-23.61469318354]],[[-51.08005769639,-23.52984412096],[-51.07962317853,-23.52205317842],[-51.08468182473,-23.52194496764],[-51.08581908135,-23.52404030606],[-51.0858941832,-23.52703569673],[-51.08579494147,-23.52777346722],[-51.08530141501,-23.52806365581],[-51.08513511805,-23.52856533627],[-51.08512438922,-23.52981952906],[-51.08470864682,-23.53023759067],[-51.08343459754,-23.53023759067],[-51.08329512267,-23.52978018202],[-51.08005769639,-23.52984412096]]],"terms_url":"http://siglon.londrina.pr.gov.br/","terms_text":"Prefeitura do Londrinas, PR"},{"id":"NSW_LPI_BaseMap","name":"LPI NSW Base Map","type":"tms","template":"https://maps.six.nsw.gov.au/arcgis/rest/services/public/NSW_Base_Map/MapServer/tile/{zoom}/{y}/{x}","scaleExtent":[0,19],"polygon":[[[140.9948644,-28.952966],[148.9611382,-28.8997729],[148.9870097,-28.4862285],[151.013609,-28.4786485],[151.1084711,-28.7032909],[151.8759917,-28.683118],[151.9334839,-28.4078753],[152.25544,-28.2332683],[153.0660798,-28.2104723],[153.1408196,-28.1090981],[153.4735137,-28.1164808],[153.3576523,-27.693606],[159.4938303,-27.699252],[159.4856997,-37.8474137],[149.5256879,-37.8281502],[149.9159578,-37.4869999],[148.0485886,-36.8131741],[147.9680996,-36.1567945],[146.7147701,-36.2866613],[145.3004625,-36.1567945],[144.5300673,-36.1475101],[142.8397973,-35.0254303],[142.356863,-34.7802471],[141.9774146,-34.4016159],[140.9950258,-34.1371824],[140.9948644,-28.952966]]],"terms_url":"http://spatialservices.finance.nsw.gov.au/mapping_and_imagery/lpi_web_services","terms_text":"© Land and Property Information 2017"},{"id":"NSW_LPI_Imagery","name":"LPI NSW Imagery","type":"tms","template":"https://maps.six.nsw.gov.au/arcgis/rest/services/public/NSW_Imagery/MapServer/tile/{zoom}/{y}/{x}","scaleExtent":[0,21],"polygon":[[[140.9868688,-28.9887829],[148.9951472,-28.9727491],[148.9966717,-28.4915066],[151.0029027,-28.4930697],[151.0029027,-28.7261663],[151.4915093,-28.7323921],[151.4918687,-28.7155337],[151.9228213,-28.719635],[151.9251607,-28.4897139],[151.9955886,-28.4898718],[151.9989947,-28.1192742],[152.4967606,-28.122091],[152.4968241,-28.1146398],[153.0044563,-28.1154389],[153.0044563,-28.120397],[153.5038629,-28.119345],[153.5039264,-28.1227063],[153.5919395,-28.1223619],[153.5926582,-28.1776872],[153.6111186,-28.1757867],[153.6113881,-28.1825173],[153.7426846,-28.2162084],[153.7787253,-28.710911],[152.6237954,-32.5877239],[152.3123961,-32.6328837],[151.4141942,-33.5790388],[150.8929925,-35.2648721],[150.4620695,-35.7777256],[150.0156501,-37.5103569],[149.9918121,-37.5126787],[149.519778,-37.5130704],[149.5199577,-37.5216919],[149.4462958,-37.5353701],[149.063344,-37.5357975],[148.9836635,-37.5217631],[148.9816872,-37.5191982],[148.9863847,-37.2584972],[148.4875376,-37.265846],[148.4824774,-37.0092669],[147.994386,-37.014339],[147.988288,-36.5332184],[147.9529707,-36.5260725],[147.9486513,-36.0685992],[147.5034997,-36.0716798],[147.5047701,-36.2651047],[146.4919996,-36.266129],[146.4922536,-36.2565],[145.9929826,-36.2534267],[145.9965866,-36.0188147],[145.9831568,-36.0187058],[145.9624506,-36.0219026],[145.946236,-36.0120936],[145.9454275,-36.0060259],[145.5041534,-36.0013564],[145.5037941,-36.0109125],[145.0072008,-36.0036213],[145.0035404,-36.1520424],[144.4860806,-36.1423149],[144.4874127,-36.0137522],[143.9874676,-36.0024134],[143.9932853,-35.5723753],[143.4971691,-35.5837101],[143.4917967,-35.4065648],[143.4613438,-35.3674934],[143.4585591,-35.3555888],[143.4897755,-35.3396522],[143.4895509,-35.332214],[143.4316994,-35.2570613],[143.2505542,-35.2606556],[143.2438356,-35.0132729],[142.9933305,-35.0177207],[142.9919767,-34.7961882],[142.4971375,-34.8032323],[142.4973172,-34.8007613],[142.4211401,-34.8017571],[142.4209155,-34.7838306],[142.2330892,-34.7859191],[142.2307707,-34.7807542],[142.2269959,-34.5061271],[141.9975302,-34.5083733],[141.9945959,-34.2526687],[141.4982345,-34.2556921],[141.498171,-34.2522794],[140.9945397,-34.2528411],[140.9868688,-28.9887829]]],"terms_url":"http://spatialservices.finance.nsw.gov.au/mapping_and_imagery/lpi_web_services","terms_text":"© Land and Property Information 2017","best":true},{"id":"NSW_LPI_TopographicMap","name":"LPI NSW Topographic Map","type":"tms","template":"https://maps.six.nsw.gov.au/arcgis/rest/services/public/NSW_Topo_Map/MapServer/tile/{zoom}/{y}/{x}","scaleExtent":[0,16],"polygon":[[[140.9988422,-28.9992444],[148.9502438,-28.9993736],[148.9498845,-28.9665265],[148.9998308,-28.9665265],[149.0000917,-28.8165829],[149.1000729,-28.8165829],[149.0997046,-28.7488533],[148.9998504,-28.7497444],[148.9998169,-28.5000304],[151.0000514,-28.5005192],[151.0005904,-28.7325849],[151.0239466,-28.7327424],[151.0241262,-28.7418794],[151.0329297,-28.7418794],[151.033828,-28.7505431],[151.999984,-28.7495314],[151.999984,-28.7164478],[152.0334014,-28.7166053],[152.0332217,-28.683196],[152.0000739,-28.6833537],[151.9998769,-28.6416273],[151.9829886,-28.6413908],[151.9831683,-28.624912],[151.9331321,-28.6247543],[151.9334122,-28.500071],[151.9998875,-28.5002289],[151.9998556,-28.3749591],[152.2499739,-28.3750718],[152.2499356,-28.2500066],[152.9997192,-28.2498563],[152.9998989,-28.2832447],[153.1165002,-28.2834029],[153.11659,-28.2498563],[153.1666262,-28.2500146],[153.166716,-28.2331582],[153.2499898,-28.2332373],[153.2500265,-28.1249689],[153.6249628,-28.1250833],[153.6248398,-28.4999134],[153.7497955,-28.4999924],[153.7495877,-28.7497976],[153.6248117,-28.7501127],[153.6249745,-28.9999333],[153.4997672,-29.0000612],[153.4998417,-29.4995077],[153.3747962,-29.500055],[153.3754111,-29.8750302],[153.4999113,-29.8751403],[153.4999113,-30.0000922],[153.2498947,-29.9997621],[153.250025,-30.1917704],[153.2748185,-30.1916151],[153.2748185,-30.2168467],[153.2166077,-30.2166139],[153.2166077,-30.250065],[153.250025,-30.250065],[153.2497502,-30.3751935],[153.1243608,-30.3749743],[153.1246457,-30.6250359],[153.0331676,-30.6250482],[153.0333884,-30.8750837],[153.1249214,-30.8750291],[153.1249344,-31.1250505],[153.0082433,-31.1249736],[153.0082914,-31.2499759],[153.0000019,-31.250003],[152.9999392,-31.6249919],[152.8749386,-31.6250491],[152.8749572,-31.749954],[152.7832899,-31.7500034],[152.7831966,-31.8748579],[152.749914,-31.8750105],[152.7500397,-32.0000207],[152.6249044,-31.9999446],[152.6249078,-32.5000047],[152.4999757,-32.4999569],[152.5000336,-32.5666443],[152.4166699,-32.5663415],[152.4167598,-32.6249954],[152.3498477,-32.624991],[152.3498477,-32.6332294],[152.2830786,-32.6332218],[152.2832583,-32.6249755],[152.2494816,-32.6249755],[152.2498101,-32.874906],[151.8745693,-32.8750443],[151.8748535,-33.0000091],[151.7497706,-33.0001533],[151.7504669,-33.2500398],[151.6252418,-33.2497393],[151.6250828,-33.3751621],[151.499585,-33.3751442],[151.5003127,-33.6249385],[151.3741466,-33.6243658],[151.3727902,-34.001962],[151.2477819,-34.0011194],[151.2477819,-34.2493114],[150.9957327,-34.2501515],[151.0008143,-34.62483],[150.8717407,-34.6265026],[150.872757,-35.1242738],[150.7670589,-35.1234425],[150.7690916,-35.2463774],[150.6257894,-35.2496974],[150.6280314,-35.3751485],[150.4999742,-35.3751485],[150.4959088,-35.6275034],[150.3719169,-35.6250251],[150.3749658,-35.7537957],[150.2672351,-35.7513213],[150.2652024,-35.8741232],[150.2479249,-35.870829],[150.2458922,-36.374885],[150.1229166,-36.374885],[150.1259656,-36.6224345],[150.0253491,-36.6240658],[150.0283981,-36.7471337],[149.9928266,-36.7495768],[150.0040062,-37.1224477],[150.0588879,-37.1273097],[150.0568553,-37.37809],[149.9979083,-37.3732441],[149.9999409,-37.4830073],[149.987745,-37.4846202],[149.9857123,-37.5080043],[148.0684571,-36.80624],[147.9930603,-36.1379955],[147.8148345,-36.0055567],[147.3893924,-36.0113701],[147.3822059,-36.1310306],[146.9972549,-36.1275479],[146.9886311,-36.2528271],[146.4956356,-36.2447132],[146.5042595,-36.126387],[145.0011817,-36.0079505],[145.0154103,-36.2542074],[144.5072465,-36.2476506],[144.4991158,-36.0211037],[143.9965422,-35.9810531],[143.3382568,-35.2331794],[142.4097581,-34.7669434],[142.0361436,-34.3758837],[140.9965216,-34.1385805],[140.9988422,-28.9992444]]],"terms_url":"http://spatialservices.finance.nsw.gov.au/mapping_and_imagery/lpi_web_services","terms_text":"© Land and Property Information 2017"},{"id":"Mapbox","name":"Mapbox Satellite","type":"tms","template":"https://{switch:a,b,c}.tiles.mapbox.com/v4/openstreetmap.map-inh7ifmo/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJncjlmd0t3In0.DmZsIeOW-3x-C5eX-wAqTw","scaleExtent":[0,19],"terms_url":"http://www.mapbox.com/about/maps/","terms_text":"Terms & Feedback","default":true,"description":"Satellite and aerial imagery.","icon":"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgODAuNDcgMjAuMDIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDgwLjQ3IDIwLjAyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PHN0eWxlIHR5cGU9InRleHQvY3NzIj4uc3Qwe29wYWNpdHk6MC42O2ZpbGw6I0ZGRkZGRjtlbmFibGUtYmFja2dyb3VuZDpuZXcgICAgO30uc3Qxe29wYWNpdHk6MC42O2VuYWJsZS1iYWNrZ3JvdW5kOm5ldyAgICA7fTwvc3R5bGU+PGc+PHBhdGggY2xhc3M9InN0MCIgZD0iTTc5LjI5LDEzLjYxYzAsMC4xMS0wLjA5LDAuMi0wLjIsMC4yaC0xLjUzYy0wLjEyLDAtMC4yMy0wLjA2LTAuMjktMC4xNmwtMS4zNy0yLjI4bC0xLjM3LDIuMjhjLTAuMDYsMC4xLTAuMTcsMC4xNi0wLjI5LDAuMTZoLTEuNTNjLTAuMDQsMC0wLjA4LTAuMDEtMC4xMS0wLjAzYy0wLjA5LTAuMDYtMC4xMi0wLjE4LTAuMDYtMC4yN2MwLDAsMCwwLDAsMGwyLjMxLTMuNWwtMi4yOC0zLjQ3Yy0wLjAyLTAuMDMtMC4wMy0wLjA3LTAuMDMtMC4xMWMwLTAuMTEsMC4wOS0wLjIsMC4yLTAuMmgxLjUzYzAuMTIsMCwwLjIzLDAuMDYsMC4yOSwwLjE2bDEuMzQsMi4yNWwxLjMzLTIuMjRjMC4wNi0wLjEsMC4xNy0wLjE2LDAuMjktMC4xNmgxLjUzYzAuMDQsMCwwLjA4LDAuMDEsMC4xMSwwLjAzYzAuMDksMC4wNiwwLjEyLDAuMTgsMC4wNiwwLjI3YzAsMCwwLDAsMCwwTDc2Ljk2LDEwbDIuMzEsMy41Qzc5LjI4LDEzLjUzLDc5LjI5LDEzLjU3LDc5LjI5LDEzLjYxeiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik02My4wOSw5LjE2Yy0wLjM3LTEuNzktMS44Ny0zLjEyLTMuNjYtMy4xMmMtMC45OCwwLTEuOTMsMC40LTIuNiwxLjEyVjMuMzdjMC0wLjEyLTAuMS0wLjIyLTAuMjItMC4yMmgtMS4zM2MtMC4xMiwwLTAuMjIsMC4xLTAuMjIsMC4yMnYxMC4yMWMwLDAuMTIsMC4xLDAuMjIsMC4yMiwwLjIyaDEuMzNjMC4xMiwwLDAuMjItMC4xLDAuMjItMC4yMnYtMC43YzAuNjgsMC43MSwxLjYyLDEuMTIsMi42LDEuMTJjMS43OSwwLDMuMjktMS4zNCwzLjY2LTMuMTNDNjMuMjEsMTAuMyw2My4yMSw5LjcyLDYzLjA5LDkuMTZMNjMuMDksOS4xNnogTTU5LjEyLDEyLjQxYy0xLjI2LDAtMi4yOC0xLjA2LTIuMy0yLjM2VjkuOTljMC4wMi0xLjMxLDEuMDQtMi4zNiwyLjMtMi4zNnMyLjMsMS4wNywyLjMsMi4zOVM2MC4zOSwxMi40MSw1OS4xMiwxMi40MXoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNNjguMjYsNi4wNGMtMS44OS0wLjAxLTMuNTQsMS4yOS0zLjk2LDMuMTNjLTAuMTIsMC41Ni0wLjEyLDEuMTMsMCwxLjY5YzAuNDIsMS44NSwyLjA3LDMuMTYsMy45NywzLjE0YzIuMjQsMCw0LjA2LTEuNzgsNC4wNi0zLjk5UzcwLjUxLDYuMDQsNjguMjYsNi4wNHogTTY4LjI0LDEyLjQyYy0xLjI3LDAtMi4zLTEuMDctMi4zLTIuMzlzMS4wMy0yLjQsMi4zLTIuNHMyLjMsMS4wNywyLjMsMi4zOVM2OS41MSwxMi40MSw2OC4yNCwxMi40Mkw2OC4yNCwxMi40MnoiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNNTkuMTIsNy42M2MtMS4yNiwwLTIuMjgsMS4wNi0yLjMsMi4zNnYwLjA2YzAuMDIsMS4zMSwxLjA0LDIuMzYsMi4zLDIuMzZzMi4zLTEuMDcsMi4zLTIuMzlTNjAuMzksNy42Myw1OS4xMiw3LjYzeiBNNTkuMTIsMTEuMjNjLTAuNiwwLTEuMDktMC41My0xLjExLTEuMTlWMTBjMC4wMS0wLjY2LDAuNTEtMS4xOSwxLjExLTEuMTlzMS4xMSwwLjU0LDEuMTEsMS4yMVM1OS43NCwxMS4yMyw1OS4xMiwxMS4yM3oiLz48cGF0aCBjbGFzcz0ic3QxIiBkPSJNNjguMjQsNy42M2MtMS4yNywwLTIuMywxLjA3LTIuMywyLjM5czEuMDMsMi4zOSwyLjMsMi4zOXMyLjMtMS4wNywyLjMtMi4zOVM2OS41MSw3LjYzLDY4LjI0LDcuNjN6IE02OC4yNCwxMS4yM2MtMC42MSwwLTEuMTEtMC41NC0xLjExLTEuMjFzMC41LTEuMiwxLjExLTEuMnMxLjExLDAuNTQsMS4xMSwxLjIxUzY4Ljg1LDExLjIzLDY4LjI0LDExLjIzeiIvPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik00My41Niw2LjI0aC0xLjMzYy0wLjEyLDAtMC4yMiwwLjEtMC4yMiwwLjIydjAuN2MtMC42OC0wLjcxLTEuNjItMS4xMi0yLjYtMS4xMmMtMi4wNywwLTMuNzUsMS43OC0zLjc1LDMuOTlzMS42OSwzLjk5LDMuNzUsMy45OWMwLjk5LDAsMS45My0wLjQxLDIuNi0xLjEzdjAuN2MwLDAuMTIsMC4xLDAuMjIsMC4yMiwwLjIyaDEuMzNjMC4xMiwwLDAuMjItMC4xLDAuMjItMC4yMlY2LjQ0YzAtMC4xMS0wLjA5LTAuMjEtMC4yMS0wLjIxQzQzLjU3LDYuMjQsNDMuNTcsNi4yNCw0My41Niw2LjI0eiBNNDIuMDIsMTAuMDVjLTAuMDEsMS4zMS0xLjA0LDIuMzYtMi4zLDIuMzZzLTIuMy0xLjA3LTIuMy0yLjM5czEuMDMtMi40LDIuMjktMi40YzEuMjcsMCwyLjI4LDEuMDYsMi4zLDIuMzZMNDIuMDIsMTAuMDV6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTM5LjcyLDcuNjNjLTEuMjcsMC0yLjMsMS4wNy0yLjMsMi4zOXMxLjAzLDIuMzksMi4zLDIuMzlzMi4yOC0xLjA2LDIuMy0yLjM2VjkuOTlDNDIsOC42OCw0MC45OCw3LjYzLDM5LjcyLDcuNjN6IE0zOC42MiwxMC4wMmMwLTAuNjcsMC41LTEuMjEsMS4xMS0xLjIxYzAuNjEsMCwxLjA5LDAuNTMsMS4xMSwxLjE5djAuMDRjLTAuMDEsMC42NS0wLjUsMS4xOC0xLjExLDEuMThTMzguNjIsMTAuNjgsMzguNjIsMTAuMDJ6Ii8+PHBhdGggY2xhc3M9InN0MCIgZD0iTTQ5LjkxLDYuMDRjLTAuOTgsMC0xLjkzLDAuNC0yLjYsMS4xMlY2LjQ1YzAtMC4xMi0wLjEtMC4yMi0wLjIyLTAuMjJoLTEuMzNjLTAuMTIsMC0wLjIyLDAuMS0wLjIyLDAuMjJ2MTAuMjFjMCwwLjEyLDAuMSwwLjIyLDAuMjIsMC4yMmgxLjMzYzAuMTIsMCwwLjIyLTAuMSwwLjIyLTAuMjJ2LTMuNzhjMC42OCwwLjcxLDEuNjIsMS4xMiwyLjYxLDEuMTJjMi4wNywwLDMuNzUtMS43OCwzLjc1LTMuOTlTNTEuOTgsNi4wNCw0OS45MSw2LjA0eiBNNDkuNiwxMi40MmMtMS4yNiwwLTIuMjgtMS4wNi0yLjMtMi4zNlY5Ljk5YzAuMDItMS4zMSwxLjA0LTIuMzcsMi4yOS0yLjM3YzEuMjYsMCwyLjMsMS4wNywyLjMsMi4zOVM1MC44NiwxMi40MSw0OS42LDEyLjQyTDQ5LjYsMTIuNDJ6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTQ5LjYsNy42M2MtMS4yNiwwLTIuMjgsMS4wNi0yLjMsMi4zNnYwLjA2YzAuMDIsMS4zMSwxLjA0LDIuMzYsMi4zLDIuMzZzMi4zLTEuMDcsMi4zLTIuMzlTNTAuODYsNy42Myw0OS42LDcuNjN6IE00OS42LDExLjIzYy0wLjYsMC0xLjA5LTAuNTMtMS4xMS0xLjE5VjEwQzQ4LjUsOS4zNCw0OSw4LjgxLDQ5LjYsOC44MWMwLjYsMCwxLjExLDAuNTUsMS4xMSwxLjIxUzUwLjIxLDExLjIzLDQ5LjYsMTEuMjN6Ii8+PHBhdGggY2xhc3M9InN0MCIgZD0iTTM0LjM2LDEzLjU5YzAsMC4xMi0wLjEsMC4yMi0wLjIyLDAuMjJoLTEuMzRjLTAuMTIsMC0wLjIyLTAuMS0wLjIyLTAuMjJWOS4yNGMwLTAuOTMtMC43LTEuNjMtMS41NC0xLjYzYy0wLjc2LDAtMS4zOSwwLjY3LTEuNTEsMS41NGwwLjAxLDQuNDRjMCwwLjEyLTAuMSwwLjIyLTAuMjIsMC4yMmgtMS4zNGMtMC4xMiwwLTAuMjItMC4xLTAuMjItMC4yMlY5LjI0YzAtMC45My0wLjctMS42My0xLjU0LTEuNjNjLTAuODEsMC0xLjQ3LDAuNzUtMS41MiwxLjcxdjQuMjdjMCwwLjEyLTAuMSwwLjIyLTAuMjIsMC4yMmgtMS4zM2MtMC4xMiwwLTAuMjItMC4xLTAuMjItMC4yMlY2LjQ0YzAuMDEtMC4xMiwwLjEtMC4yMSwwLjIyLTAuMjFoMS4zM2MwLjEyLDAsMC4yMSwwLjEsMC4yMiwwLjIxdjAuNjNjMC40OC0wLjY1LDEuMjQtMS4wNCwyLjA2LTEuMDVoMC4wM2MxLjA0LDAsMS45OSwwLjU3LDIuNDgsMS40OGMwLjQzLTAuOSwxLjMzLTEuNDgsMi4zMi0xLjQ5YzEuNTQsMCwyLjc5LDEuMTksMi43NiwyLjY1TDM0LjM2LDEzLjU5eiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik04MC4zMiwxMi45N2wtMC4wNy0wLjEyTDc4LjM4LDEwbDEuODUtMi44MWMwLjQyLTAuNjQsMC4yNS0xLjQ5LTAuMzktMS45MmMtMC4wMS0wLjAxLTAuMDItMC4wMS0wLjAzLTAuMDJjLTAuMjItMC4xNC0wLjQ4LTAuMjEtMC43NC0wLjIxaC0xLjUzYy0wLjUzLDAtMS4wMywwLjI4LTEuMywwLjc0bC0wLjMyLDAuNTNsLTAuMzItMC41M2MtMC4yOC0wLjQ2LTAuNzctMC43NC0xLjMxLTAuNzRoLTEuNTNjLTAuNTcsMC0xLjA4LDAuMzUtMS4yOSwwLjg4Yy0yLjA5LTEuNTgtNS4wMy0xLjQtNi45MSwwLjQzYy0wLjMzLDAuMzItMC42MiwwLjY5LTAuODUsMS4wOWMtMC44NS0xLjU1LTIuNDUtMi42LTQuMjgtMi42Yy0wLjQ4LDAtMC45NiwwLjA3LTEuNDEsMC4yMlYzLjM3YzAtMC43OC0wLjYzLTEuNDEtMS40LTEuNDFoLTEuMzNjLTAuNzcsMC0xLjQsMC42My0xLjQsMS40djMuNTdjLTAuOS0xLjMtMi4zOC0yLjA4LTMuOTctMi4wOWMtMC43LDAtMS4zOSwwLjE1LTIuMDIsMC40NWMtMC4yMy0wLjE2LTAuNTEtMC4yNS0wLjgtMC4yNWgtMS4zM2MtMC40MywwLTAuODMsMC4yLTEuMSwwLjUzYy0wLjAyLTAuMDMtMC4wNC0wLjA1LTAuMDctMC4wOGMtMC4yNy0wLjI5LTAuNjUtMC40NS0xLjA0LTAuNDVoLTEuMzJjLTAuMjksMC0wLjU3LDAuMDktMC44LDAuMjVDNDAuOCw1LDQwLjEyLDQuODUsMzkuNDIsNC44NWMtMS43NCwwLTMuMjcsMC45NS00LjE2LDIuMzhjLTAuMTktMC40NC0wLjQ2LTAuODUtMC43OS0xLjE5Yy0wLjc2LTAuNzctMS44LTEuMTktMi44OC0xLjE5aC0wLjAxYy0wLjg1LDAuMDEtMS42NywwLjMxLTIuMzQsMC44NGMtMC43LTAuNTQtMS41Ni0wLjg0LTIuNDUtMC44NGgtMC4wM2MtMC4yOCwwLTAuNTUsMC4wMy0wLjgyLDAuMWMtMC4yNywwLjA2LTAuNTMsMC4xNS0wLjc4LDAuMjdjLTAuMi0wLjExLTAuNDMtMC4xNy0wLjY3LTAuMTdoLTEuMzNjLTAuNzgsMC0xLjQsMC42My0xLjQsMS40djcuMTRjMCwwLjc4LDAuNjMsMS40LDEuNCwxLjRoMS4zM2MwLjc4LDAsMS40MS0wLjYzLDEuNDEtMS40MWMwLDAsMCwwLDAsMFY5LjM1YzAuMDMtMC4zNCwwLjIyLTAuNTYsMC4zNC0wLjU2YzAuMTcsMCwwLjM2LDAuMTcsMC4zNiwwLjQ1djQuMzVjMCwwLjc4LDAuNjMsMS40LDEuNCwxLjRoMS4zNGMwLjc4LDAsMS40LTAuNjMsMS40LTEuNGwtMC4wMS00LjM1YzAuMDYtMC4zLDAuMjQtMC40NSwwLjMzLTAuNDVjMC4xNywwLDAuMzYsMC4xNywwLjM2LDAuNDV2NC4zNWMwLDAuNzgsMC42MywxLjQsMS40LDEuNGgxLjM0YzAuNzgsMCwxLjQtMC42MywxLjQtMS40di0wLjM2YzAuOTEsMS4yMywyLjM0LDEuOTYsMy44NywxLjk2YzAuNywwLDEuMzktMC4xNSwyLjAyLTAuNDVjMC4yMywwLjE2LDAuNTEsMC4yNSwwLjgsMC4yNWgxLjMyYzAuMjksMCwwLjU3LTAuMDksMC44LTAuMjV2MS45MWMwLDAuNzgsMC42MywxLjQsMS40LDEuNGgxLjMzYzAuNzgsMCwxLjQtMC42MywxLjQtMS40di0xLjY5YzAuNDYsMC4xNCwwLjk0LDAuMjIsMS40MiwwLjIxYzEuNjIsMCwzLjA3LTAuODMsMy45Ny0yLjF2MC41YzAsMC43OCwwLjYzLDEuNCwxLjQsMS40aDEuMzNjMC4yOSwwLDAuNTctMC4wOSwwLjgtMC4yNWMwLjYzLDAuMywxLjMyLDAuNDUsMi4wMiwwLjQ1YzEuODMsMCwzLjQzLTEuMDUsNC4yOC0yLjZjMS40NywyLjUyLDQuNzEsMy4zNiw3LjIyLDEuODljMC4xNy0wLjEsMC4zNC0wLjIxLDAuNS0wLjM0YzAuMjEsMC41MiwwLjcyLDAuODcsMS4yOSwwLjg2aDEuNTNjMC41MywwLDEuMDMtMC4yOCwxLjMtMC43NGwwLjM1LTAuNThsMC4zNSwwLjU4YzAuMjgsMC40NiwwLjc3LDAuNzQsMS4zMSwwLjc0aDEuNTJjMC43NywwLDEuMzktMC42MywxLjM4LTEuMzlDODAuNDcsMTMuMzgsODAuNDIsMTMuMTcsODAuMzIsMTIuOTdMODAuMzIsMTIuOTd6IE0zNC4xNSwxMy44MWgtMS4zNGMtMC4xMiwwLTAuMjItMC4xLTAuMjItMC4yMlY5LjI0YzAtMC45My0wLjctMS42My0xLjU0LTEuNjNjLTAuNzYsMC0xLjM5LDAuNjctMS41MSwxLjU0bDAuMDEsNC40NGMwLDAuMTItMC4xLDAuMjItMC4yMiwwLjIyaC0xLjM0Yy0wLjEyLDAtMC4yMi0wLjEtMC4yMi0wLjIyVjkuMjRjMC0wLjkzLTAuNy0xLjYzLTEuNTQtMS42M2MtMC44MSwwLTEuNDcsMC43NS0xLjUyLDEuNzF2NC4yN2MwLDAuMTItMC4xLDAuMjItMC4yMiwwLjIyaC0xLjMzYy0wLjEyLDAtMC4yMi0wLjEtMC4yMi0wLjIyVjYuNDRjMC4wMS0wLjEyLDAuMS0wLjIxLDAuMjItMC4yMWgxLjMzYzAuMTIsMCwwLjIxLDAuMSwwLjIyLDAuMjF2MC42M2MwLjQ4LTAuNjUsMS4yNC0xLjA0LDIuMDYtMS4wNWgwLjAzYzEuMDQsMCwxLjk5LDAuNTcsMi40OCwxLjQ4YzAuNDMtMC45LDEuMzMtMS40OCwyLjMyLTEuNDljMS41NCwwLDIuNzksMS4xOSwyLjc2LDIuNjVsMC4wMSw0LjkxQzM0LjM3LDEzLjcsMzQuMjcsMTMuOCwzNC4xNSwxMy44MUMzNC4xNSwxMy44MSwzNC4xNSwxMy44MSwzNC4xNSwxMy44MXogTTQzLjc4LDEzLjU5YzAsMC4xMi0wLjEsMC4yMi0wLjIyLDAuMjJoLTEuMzNjLTAuMTIsMC0wLjIyLTAuMS0wLjIyLTAuMjJ2LTAuNzFDNDEuMzQsMTMuNiw0MC40LDE0LDM5LjQyLDE0Yy0yLjA3LDAtMy43NS0xLjc4LTMuNzUtMy45OXMxLjY5LTMuOTksMy43NS0zLjk5YzAuOTgsMCwxLjkyLDAuNDEsMi42LDEuMTJ2LTAuN2MwLTAuMTIsMC4xLTAuMjIsMC4yMi0wLjIyaDEuMzNjMC4xMS0wLjAxLDAuMjEsMC4wOCwwLjIyLDAuMmMwLDAuMDEsMCwwLjAxLDAsMC4wMlYxMy41OXogTTQ5LjkxLDE0Yy0wLjk4LDAtMS45Mi0wLjQxLTIuNi0xLjEydjMuNzhjMCwwLjEyLTAuMSwwLjIyLTAuMjIsMC4yMmgtMS4zM2MtMC4xMiwwLTAuMjItMC4xLTAuMjItMC4yMlY2LjQ1YzAtMC4xMiwwLjEtMC4yMSwwLjIyLTAuMjFoMS4zM2MwLjEyLDAsMC4yMiwwLjEsMC4yMiwwLjIydjAuN2MwLjY4LTAuNzIsMS42Mi0xLjEyLDIuNi0xLjEyYzIuMDcsMCwzLjc1LDEuNzcsMy43NSwzLjk4UzUxLjk4LDE0LDQ5LjkxLDE0eiBNNjMuMDksMTAuODdDNjIuNzIsMTIuNjUsNjEuMjIsMTQsNTkuNDMsMTRjLTAuOTgsMC0xLjkyLTAuNDEtMi42LTEuMTJ2MC43YzAsMC4xMi0wLjEsMC4yMi0wLjIyLDAuMjJoLTEuMzNjLTAuMTIsMC0wLjIyLTAuMS0wLjIyLTAuMjJWMy4zN2MwLTAuMTIsMC4xLTAuMjIsMC4yMi0wLjIyaDEuMzNjMC4xMiwwLDAuMjIsMC4xLDAuMjIsMC4yMnYzLjc4YzAuNjgtMC43MSwxLjYyLTEuMTIsMi42LTEuMTFjMS43OSwwLDMuMjksMS4zMywzLjY2LDMuMTJDNjMuMjEsOS43Myw2My4yMSwxMC4zMSw2My4wOSwxMC44N0w2My4wOSwxMC44N0w2My4wOSwxMC44N3ogTTY4LjI2LDE0LjAxYy0xLjksMC4wMS0zLjU1LTEuMjktMy45Ny0zLjE0Yy0wLjEyLTAuNTYtMC4xMi0xLjEzLDAtMS42OWMwLjQyLTEuODUsMi4wNy0zLjE1LDMuOTctMy4xNGMyLjI1LDAsNC4wNiwxLjc4LDQuMDYsMy45OVM3MC41LDE0LjAxLDY4LjI2LDE0LjAxTDY4LjI2LDE0LjAxeiBNNzkuMDksMTMuODFoLTEuNTNjLTAuMTIsMC0wLjIzLTAuMDYtMC4yOS0wLjE2bC0xLjM3LTIuMjhsLTEuMzcsMi4yOGMtMC4wNiwwLjEtMC4xNywwLjE2LTAuMjksMC4xNmgtMS41M2MtMC4wNCwwLTAuMDgtMC4wMS0wLjExLTAuMDNjLTAuMDktMC4wNi0wLjEyLTAuMTgtMC4wNi0wLjI3YzAsMCwwLDAsMCwwbDIuMzEtMy41bC0yLjI4LTMuNDdjLTAuMDItMC4wMy0wLjAzLTAuMDctMC4wMy0wLjExYzAtMC4xMSwwLjA5LTAuMiwwLjItMC4yaDEuNTNjMC4xMiwwLDAuMjMsMC4wNiwwLjI5LDAuMTZsMS4zNCwyLjI1bDEuMzQtMi4yNWMwLjA2LTAuMSwwLjE3LTAuMTYsMC4yOS0wLjE2aDEuNTNjMC4wNCwwLDAuMDgsMC4wMSwwLjExLDAuMDNjMC4wOSwwLjA2LDAuMTIsMC4xOCwwLjA2LDAuMjdjMCwwLDAsMCwwLDBMNzYuOTYsMTBsMi4zMSwzLjVjMC4wMiwwLjAzLDAuMDMsMC4wNywwLjAzLDAuMTFDNzkuMjksMTMuNzIsNzkuMiwxMy44MSw3OS4wOSwxMy44MUM3OS4wOSwxMy44MSw3OS4wOSwxMy44MSw3OS4wOSwxMy44MUw3OS4wOSwxMy44MXoiLz48cGF0aCBjbGFzcz0ic3QwIiBkPSJNMTAsMS4yMWMtNC44NywwLTguODEsMy45NS04LjgxLDguODFzMy45NSw4LjgxLDguODEsOC44MXM4LjgxLTMuOTUsOC44MS04LjgxQzE4LjgxLDUuMTUsMTQuODcsMS4yMSwxMCwxLjIxeiBNMTQuMTgsMTIuMTljLTEuODQsMS44NC00LjU1LDIuMi02LjM4LDIuMmMtMC42NywwLTEuMzQtMC4wNS0yLTAuMTVjMCwwLTAuOTctNS4zNywyLjA0LTguMzljMC43OS0wLjc5LDEuODYtMS4yMiwyLjk4LTEuMjJjMS4yMSwwLDIuMzcsMC40OSwzLjIzLDEuMzVDMTUuOCw3LjczLDE1Ljg1LDEwLjUsMTQuMTgsMTIuMTl6Ii8+PHBhdGggY2xhc3M9InN0MSIgZD0iTTEwLDAuMDJjLTUuNTIsMC0xMCw0LjQ4LTEwLDEwczQuNDgsMTAsMTAsMTBzMTAtNC40OCwxMC0xMEMxOS45OSw0LjUsMTUuNTIsMC4wMiwxMCwwLjAyeiBNMTAsMTguODNjLTQuODcsMC04LjgxLTMuOTUtOC44MS04LjgxUzUuMTMsMS4yLDEwLDEuMnM4LjgxLDMuOTUsOC44MSw4LjgxQzE4LjgxLDE0Ljg5LDE0Ljg3LDE4LjgzLDEwLDE4LjgzeiIvPjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0xNC4wNCw1Ljk4Yy0xLjc1LTEuNzUtNC41My0xLjgxLTYuMi0wLjE0QzQuODMsOC44Niw1LjgsMTQuMjMsNS44LDE0LjIzczUuMzcsMC45Nyw4LjM5LTIuMDRDMTUuODUsMTAuNSwxNS44LDcuNzMsMTQuMDQsNS45OHogTTExLjg4LDkuODdsLTAuODcsMS43OGwtMC44Ni0xLjc4TDguMzgsOS4wMWwxLjc3LTAuODZsMC44Ni0xLjc4bDAuODcsMS43OGwxLjc3LDAuODZMMTEuODgsOS44N3oiLz48cG9seWdvbiBjbGFzcz0ic3QwIiBwb2ludHM9IjEzLjY1LDkuMDEgMTEuODgsOS44NyAxMS4wMSwxMS42NSAxMC4xNSw5Ljg3IDguMzgsOS4wMSAxMC4xNSw4LjE1IDExLjAxLDYuMzcgMTEuODgsOC4xNSAiLz48L2c+PC9zdmc+"},{"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","endDate":"2016-01-01T00:00:00.000Z","startDate":"2013-01-01T00:00:00.000Z","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","description":"Six Inch resolution aerial imagery for the State of Maryland"},{"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","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","description":"Maryland State Highway Administration road features and additional Maryland focused landmarks"},{"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","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]]],"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","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABLCAMAAAAf8MQEAAAAAXNSR0IArs4c6QAAAt9QTFRF////q6ytVFplAAAB0owMmWYJRS4EZWx3o6OjYmNl7JoE/agGdE0GBgUA9aQOzIkMKhwCFA0BJBQBNBUAdHV15OXpUlVYGhECkWEJ5ZkOsXYKbkoH/64Qu30LgVYImpqbSTEEa0gG8qIOVTkFEgwBHhQCqnEKMSEE/80So20Kck0HCQYB/7IOMzM0uru+Q0tYRCQA/8ER/9oT/+EUlGMJflUI3ZQN/7kQ/60PaUYGZUMG/7EQ/8oSJhkCil0IOiYDMB8CfH1+yYYM4pcOiFsI2ZIN1Y4N/8URIRYCi4uLa3B5NSQD/74RzooM7qAO/7YQ6+vsiloD+6gP/aoP6p0OrnQLnWkKm2kJWz0FUjYFMSED/9QTjV4JdHZ69ff77J4ODAkBX0AGAAEL+fr7S1BVBQIAtXkLhVkIPikExIMMTjUEFhYXysrLxcXF+qcPwYEM1pENHSIqPSkDLR4Dck0I/qoQRzAEe1MH/+gVWzQAg4SFJCQlelIIDgkBYUEGQiwESElLLSADSi0B/9ESDAIArrS9v4ALTDIEDAwMxsvVklsAHRMBjmAJP0JHAAETdEUAhVcISVRlxoUMd1AI/7sOz9HW1IoChFkHomwK/+UUYj4D96UQZjYAGiQ4OURXg4eMk5mm/6wJwH8M3uHmp3AK/90UNDtJLhQAFxABGQ0Bg1gIglUEJjNJl14FsnMBlmUJ0YcA2drbi5WmFQIAi1MAa2trbHaHW1tck5KS8fL0fEoAOxwAJCw7/7YFUiwAgU0AJQwA6ZcCJy9BDRcrsLCx/8oU2t3j7/H2ChEfu73DAAAA1NXXAAAGWmJtEx42qWoAVDkEzIQAa0YEo2QAAw4lfIGNhY2bdnyIm2QCp6y2eoWXLTA5w34AjZKbRE1hdn+RrHEFxoAAu8DGY26BAQocnZ+kvHkB5JQB/8QOhIqVORcATCYA24wA+6YK8JsCJQYAn6Wu0YsMnai8hY+hU2B4tSvHUAAACMpJREFUWMO1mP9TFPcZx2nfd9do7xutySG3dznuzuOOQ8PCwd65C2eFY69h6ya7CMuXBDRzcNDksOJhUwkYz5IYLFaKDco41qqNEztmnMwk1aaNbZN0MtpYG5O06ZdfajWTpJl2pn9An4WxxS9HhZl+fgBm9/P6fJ7P87yf5/ksBQX/j/E50DAY9Z/4wuLQe+8jxlFYVOwE44LZvRK4fxE0UAJ4jb5VAVtpMIRwuQNYfdf4AxVsFRtBdU00hmJeqEVdHOvwlbvFMTciBpRI+Bo20EEgVzcAd0U/9HAgpMhqzcZwK6CF29pLw52wqc0mPPLoXdD6zqu0Lo5d3yKDQRws6oH1XZuAzY/dheWmysyACSFRllaVJlsAPlMOxB1xxPA/PLDmG/BstUr127IZUzIqbkHNkAN1omzXTdqeRiG+tQC9A0/CJBfpcwetoVR9R6Kp0/dUWuiKAz79aWv+/XfO+jsZ634asK30AKSWGIaJ4HZhDo/kENv9UJ5TN40lakK9ydFamvgMsToPsAPgurdRDPQlWlBU+Owd+T3PiUILbWGvNgHjsPSjv2+EoLJKcP4e3RB91O4FvnMHej84toxeGyabBmwDGN+O70HzFfP0yMbCC4SAUYDWmdp9u34O4PtsDI5Jrvr5Mne1PIyw3eEaD/T1kT1sJQ4msRFwYogM6ANuM39iX/AQDgXZ5JxgOZu/xj+JtK21jk7ct7EqiRkfRsIRwNMP5+Fb6B8cFYubpawv1uCtslVSlsHLS05vO1iWLDY3lg/C20+OYIF2IHOL+ccg8TKbjZaJuaJqOHs6arR6JSqFGFg3TQNlW8rjsJrQDwm9FoycmIv+ih3ACh3/0QucxCckZkCKztoeEiSecEkoMWKMnG7LJuAdRRoyRANkfdKNzNRNxxTsibWIqYzqCoTpYXuQEeowkPG3wwRXW5VpAwKmMFxuFAWRQjc7TdufrmRnrdj8XE4TONYFWZ4k9iXydkDowTQnMZ0mlPKdnMeKuMmPlSrSHTRjYwA49phZrMQZ3Qq2R5YVhn1KDFJ4kNAVMoi1ckYN1rGFEbfEdgv2dE0EouQARy9FoOKBFXAU60X02NEOcw3NVQV6czCTHG94CbBwIqdGpZFOuFGbA59ubx4eFYm14ZEClEntN05e8MoJN+rlDLmKzErANxwv1fOjbEyWZlAMirVs92IwGlo/QMapqVcL8MWDNGHvLH52ohOeRjnDFgPFlXDSU8/W0XEqM8nK7RYh7Ca8uhnJDm+jx5jE6Ln9FKkAUvaD53T8CaDzRE8Hh0ZPMAq+3oxefqMJRoajpG335ygBrblxnAxuiCD94m7fdjxesAbdghdJHV/2c8jBcc0yXtUiaJCmqK4OdoqbMCC6KfMwSllirQFacj1j8KeQntRt3nnoYN/c2Ze9PtrB+4GwVeCc9TwH11DEmFMQiDbDjG46ETZQs1rZ0S7BCL/mmqXO/+JLc5p79s1YM47XFrfqxUhkfWVubHAIAd2xiZawNQuxT49kLob29iJKWnLRbMG+94nH9V+OSbcBdm0wRXNKmnPF6ouUGV3f1PGUrKsgJIdR18UgPBLTO0aVpr01L18KzU4NTc7C7tI2ItLTQoikYTXPxvU4EOwZPlkNC6uhpQso7EXQq/36psrOhtHkKBn0wYO3d+qaonlvXEDWAj/6EqK+zo7XUEa1IDXW6xAaNl38zXxcgik+UtpmxKqKX94DE2ewUkK/E49SW4NdFB06f2a2DDcLZs1VFrv0zs34KLzr0hFYfovVGFYZxoz7cBprSRHoEeM6eXbN/fcgIAvlI/EILuO/3WoZHTUONY3Y8+lEEGAURYnYZYx4U0X4Lorm6tcOPUbANjzdNIKjeGsezrqTiAyhtgpolBElfEuTEKqxj44QN2rpJdXPXg/owvK7cX2td6/Mv8XkfjgUqd1KSUJvZnFV1mSqkW6kZutmrpky8Kbe/948178/xaiiw4zCetP2QjtkJZORIj0Ry0mEbaU011pt6V7obnBJUrkQbgyOZaVgnZX+Mpav6ySbPP9J7TzdbYrhRa3Jjlg1ySzV0BKZJnUHOlnomyvU32Ilnrfz4h9gisVYTSkqu1BtmN2rl0qHik4KhLvDI5QrM9xC2/+exyRrRS8LbWiY6G7VYxwMIkR4WWWTOKOoDB7Mi/8BDZDkLXpLHtyme8EWccOZ8AVyJPtck0ixmLk0sdCVxs7yzRjWW2wf07+3z0ZZ7YGLcEZO8KQERXz5lfz4xGmJb4wX+Xyo9ett3I2v6yHrgka9S9VxaaHtJ96lLicaSTU9VYZG24k/oWD16r+8vAsBSZkb5c0LOO8ClgciHMcxYhqXL5/CH+cer97K6xpmIryiqsG/5udfO+8KScqMKrXiytWrf7ux6jVRt5zr4fSfFxdw3ubGEZuiKswUblGUDgbKyQge+aVTsCc446SdGEH74GZFkd9ln6GcVtl1eAFclHyMzPNad2rzvAVwSlLUzFopS0tfX8B5+1nOx/cG3M8EPzo0b9oeXCeTtGyUlJMfP4Bz/EqXjeMMgotjH56fzuD6tspRNRpVy/F+Pse9LnBBF8sFj7O8N7j8zHzv5VrAz6iGAT748Yd58Cv7xOo6p1RnGJaCYJ+c/+rwiTaQ+6ZbZSEv/m0IljdlH0JO/fr451uu+BGKmllWrl/M/w3xCfYJWuq0Gdd+9cYt6VQoU+wMvPJpfs8f+fyDmz/efceylGI4ync+OlPx48V/TuKnnKpEmSwF7tzEEvCfZenkdQlS3WdYNP0e5BlFifbLC8om7zg7UcHyKlPPqNHs3/GPRfOP4vQ/ZTWqMusZ4csfLv7wB64Osnrf8qjiUvCCf73AKiov+fjMYr/k53x/jVNVmTUW18SxFPwzWcnKnDIsn1oSvlzqoc+FrNzF7l4K/hF9PNazHNtbWbEU/Px1tLjlkYSx45Ol/R+lQpROYoDjtKXhn0qyBQPeNiwNPxeUUFupYYn4q37/ha8eOfKTs7e9+TeLgDxdoqv76wAAAABJRU5ErkJggg==","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","endDate":"2015-05-03T00:00:00.000Z","startDate":"2015-03-29T00:00:00.000Z","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)","description":"Digital orthophotography of New Jersey, Near Infrared, 1 foot resolution"},{"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","endDate":"2015-05-03T00:00:00.000Z","startDate":"2015-03-29T00:00:00.000Z","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)","description":"Digital orthophotography of New Jersey, Natural Color, 1 foot resolution"},{"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","icon":"http://nls.tileserver.com/nls70-nq8.png"},{"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","icon":"http://nls.tileserver.com/nls70-nq8.png"},{"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","icon":"http://nls.tileserver.com/nls70-nq8.png"},{"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","icon":"http://nls.tileserver.com/nls70-nq8.png"},{"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","icon":"http://nls.tileserver.com/nls70-nq8.png"},{"id":"NLSC-EMAP5","name":"NLSC General Map with Contour line","type":"tms","template":"http://wmts.nlsc.gov.tw/wmts/EMAP5_OPENDATA/default/EPSG:3857/{zoom}/{y}/{x}","startDate":"2015-01-01T00:00:00.000Z","scaleExtent":[0,15],"polygon":[[[120.4570579,26.3970586],[120.44256,26.3708009],[120.44713,26.3531513],[120.4673009,26.3405831],[120.4978723,26.3340866],[120.5141036,26.3401594],[120.5341168,26.3641649],[120.5297045,26.3842128],[120.4956661,26.4015754],[120.4570579,26.3970586]],[[119.9007221,25.9858609],[119.8960071,25.9648902],[119.9131301,25.9470399],[119.9503542,25.9278478],[119.9905563,25.9260623],[120.0198392,25.9363284],[120.0277804,25.9557423],[120.0275322,25.9845224],[119.9989937,26.0010288],[119.9404278,26.0028131],[119.9007221,25.9858609]],[[122.089,24.5485],[121.709,23.4541],[121.717,22.698],[121.818,21.95],[121.803,21.8735],[121.759,21.8087],[121.694,21.7653],[120.861,21.5631],[120.815,21.5576],[120.739,21.5728],[120.661,21.6296],[120.202,22.1809],[119.27,23.0542],[119.153,23.2049],[119.128,23.2485],[119.103,23.4],[119.118,23.4765],[119.137,23.512],[119.361,23.8885],[119.406,23.9407],[120.968,25.2284],[121.408,25.4687],[121.989,25.8147],[122.065,25.8299],[122.141,25.8147],[122.216,25.7663],[122.26,25.7015],[122.297,25.48],[122.196,24.9696],[122.089,24.5485]],[[116.6855033,20.8547596],[116.6309071,20.8149565],[116.5941695,20.7600846],[116.5797214,20.6967501],[116.5893056,20.6325865],[116.621766,20.5753367],[116.6731874,20.5319171],[116.7373678,20.5075783],[116.8065659,20.5052653],[116.8724354,20.5252581],[116.9270316,20.5651373],[116.9637692,20.6200797],[116.9782173,20.6834462],[116.9686331,20.7475883],[116.9361727,20.8047732],[116.8847512,20.8481147],[116.8205709,20.872399],[116.7513728,20.8747063],[116.6855033,20.8547596]],[[118.2261504,24.4563345],[118.2936439,24.4538527],[118.2851467,24.4751026],[118.3097372,24.4916821],[118.3767709,24.4729348],[118.4100947,24.5332285],[118.4479031,24.5284069],[118.4746394,24.4599272],[118.512992,24.4315479],[118.5065839,24.4202318],[118.4811625,24.4332439],[118.4610567,24.4089192],[118.426145,24.3970385],[118.3970055,24.4284184],[118.3765564,24.4258395],[118.3397565,24.3814628],[118.3031926,24.3705764],[118.2574234,24.4139213],[118.1381276,24.3724838],[118.1617342,24.4022433],[118.2094226,24.4139604],[118.1895784,24.4352201],[118.2176338,24.430205],[118.2261504,24.4563345]],[[120.2234496,26.30045],[120.2550843,26.3100412],[120.269888,26.3368716],[120.2591889,26.3652192],[120.2292544,26.3784823],[120.1976197,26.3688968],[120.182816,26.3420738],[120.1935151,26.3137205],[120.2234496,26.30045]],[[119.4374461,25.0047541],[119.4342024,24.9886249],[119.4541901,24.9722553],[119.4827444,24.9718376],[119.4898402,24.9937882],[119.4715877,25.0069239],[119.4374461,25.0047541]],[[119.8869914,26.180381],[119.893227,26.1203128],[119.9285109,26.1080224],[119.9779388,26.1223611],[120.0366775,26.151728],[120.1098054,26.2134921],[120.119269,26.2713663],[120.0629175,26.3172592],[119.9923706,26.3164881],[119.9467732,26.2898799],[119.9020362,26.2439761],[119.8869914,26.180381]]],"terms_url":"http://maps.nlsc.gov.tw/","terms_text":"© National Land Surveying and Mapping Center, Taiwan OGDL 1.0","description":"The emap from Taiwan National Land Surveying and Mapping Center","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAAxJJREFUOI3tlF9oW2UYxn9f4nKW2ixfjJGYMnuctRUZ5mhEpjdJEEaHtmsZaKHq0qt6ZdtZL3Zhk3ilIKS9Ui806UStE7Edjln8kwzEwaB6IshsmJIqK1ttZ7Qlzel2eryQhqZrsDC8EHyuvu993+/53j+8D/yPfxtip4GqH1X1owLkdHI3RSwbkbFu1yAPdx4t3hpSS6YLAM05i/vCqcmzZwpj9T6pIZYOZNArNADhsQj3RVNjtyS1DcKtiHlPIb96PTn67nJiq8++cRgJicTpQ7Yz0oHc7cQZeakzPbTyqr9iKXUr0lfbqOx7LHJgbXrux5/X9M0+G0C8SySeeWTPQPSLxu4jn1vd4tE7m4euDNclrCEvt6E+25/e6H+VuKen57vEe1b8I29b8cKyo6j6Uece6I/VK387jC70crgjMFBDPDEx8aA5aOPkG+f7FhcX9YhGZLIUBSD7VAtSsZOKNpGKNgFU710tbiJ7G0lFm9DucCL2R7uCXjTpQFZbMV6wMu+EbWnpQOIJVKcvFTuDIR+az4nmc1Zt6h4HuV9XGHjIx1D2EvrCKtLnUgE+Pig+kQ6kDeDFc9YQwJdP2rLuBlfzRjklw7yh7JJh0vfZL6Tb70IqdqRSnT/5JfQTBcZfDom4HaBiUjn5k/Xh0VYRe85ztZ11QX53K4ZQyPxwFcO0yP+2Ste9bi6XrxPbfxuvnV9g6uIfPK/dTskwURbOFfPTM2PSIeTT99Bzw4KMhERi5ICIl667OOHuYNzdQV5p/ccBxi89kUmm5vveDou06kLddvNSibasbvZGXvj9fYJGgbldAaYaI+SVVoq7ApxtCNXEH7ZyhL8+Nho00YJeoT3+6Xp0W2KtBU07NpzNlHulem2ecHmGzpUcmlGg+dp83aynitbkK99ayfwSel2tiLUTo3M4lSn3ys12ub5MsFL4O4GGWZq/fyszfvrPsfwSNZtnpw70i+jMfjPdf//MfXf7UYtrASqWQkUoeNzLtHumS0buzePJD4zjV1a5vPX9jmRT9aNGNCKbZXMn0vnfwl+e9BTflqrxKAAAAABJRU5ErkJggg=="},{"id":"MAPNIK","name":"OpenStreetMap (Standard)","type":"tms","template":"https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png","scaleExtent":[0,19],"terms_url":"https://www.openstreetmap.org/","terms_text":"© OpenStreetMap contributors, CC-BY-SA","default":true,"description":"The default OpenStreetMap layer.","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAGb0lEQVR4Xq3MS2xcVx3H8e855z7m3vH1jMdjO43zshIrtpM0SZ3WFEcRVFFKoRWPBYtAHwgWCFUsQN100QeCsqAhCESrirRASdWWIkoUqgKFJm3UZ5o2oW2akrR5uXbi2ON4PPfOfZ17iERW2bCAz1/f3V8/cfDC02UEj4OxKHjdFMUfmUzOlAeXZFZuuVIKN8zi1dPh7Hcn5091G2EOB5b//NplA28/9tAT4bq111jD64ZKHR2VQWPEbULI0aHqZz7NZeLNmSeVMOJu4AfGgNEGLsR/95YuetcRzprcFJvaaVxrpm2mmqfp8FxKSYk8ck+0pt1nykFp0A/k9Tnt/lq3T2dHEOmi2DxSu+EdAAFwcPqp640xe42h26Qa2hqnXsFVHs04pNFuYgvbtOWCmD3aMj2VNaLi1+jwyxgpCKOQRCdMN6ZMd5Bmw1cPfG+5O/7LeX0ECyBppx9Zrn0c6BbNHJNr4qhFYWtsJCWpSFUm3ntxips2bxe+p1BKIJQECpRbkCQ2wu0XzbnIeemvhzYCVNR6JMDm5bdNF9qcwhiKbpvMg2KujZDmUgX1jgqT719gy+iX6QxsPM9F2YqclHbRRpUEXmCRZTGFlZGKxSMbR6+uA0gu863OzLc7cVUZN6jgKI8kicl0ykzjAiW5lGrVAWUwokApSa3UTY/XR2B3UlDgVy1sB8od7tgt2++4AcACOHL+uRW2bW8QQiCxcUoS6XssyBbnF6Y5+8kci8vjlJwqjnQwWpDlgtRYZDpHmxJzWUyk26gOYXxK0g+8G4bXX/snC0DZcmVh9EoQ5DpDSIVJYmIiGvkCurAQpkLU9kkTEEJeCjxbURSCZgTkfVjOApoM6Qtc3109Nj7uWO9M70EbPQT4YMhNjrWQEdHmTPs8SgfUisUgDLoAgcGyEjJtEaeaVlKQ5gVSGYwBhETaEmVJcemQaZ44aRpvyLIEnedGoNHNkNTTeI5DT2kRljeJziVhnKNlE1GaJFfnuRi3SXMDxmA7IUqCI20qdifkxfED+/dlanzb1cYL3BFhsTXPU4Ep0FGKUVALegCb1oLN7FlNpd5HIUNQLYxIsO0EKcByWljuAmXbp7fcIwgVb7xyaNeep3YfUnt272PLjaP1em/lZqmEk4cJQoMKfBxVIcwjlAp47okX6ap3XaoP221CIREyx7La2E6O7/h0eTXK+Bw+8uHrP7znvocXLe6flwCHXj06kab5hJAS6dhQFOgiJ2qXsKLVuHqAgdVD7HrwXibPTKJzFyMMAgECHGXTJTqxE4t3T5xMD7y29+mFRjgpLSUlYJ793T9ORWF0Lk1StCzQNqTTAle30flbzJ/bx6n3Xsa2Fb9/5Eccfu19wnlNFBniWJA3JecbDfa/8y5nJg7bW7ZeuyYKZwyF0QIAkC988Ogzfof6SppapHGZqgNTExPsfngfgaXpqyWk9QF6lwWk7YJlK1fQaTysqk8sE6LwIq4OEMql1DH3/O03PnBHUCk3JMCeA7/q6u1a0ltiNZ1eL719cPrcWR752d+Yn2lx/HSDY40qY2Pb2PapjYxv3YBX1syZ88weP3bp90Omw3PMOxNUe9FTn9gn5uemQqfk5BbAisHBlVo7g7PFx9TdgDMnZvjtzheI51qkWY5xYWxTLxXfJ5IVevIZ6gMDxCYnPjWDXZ0nSiOkEmYqO5l8cGT6FSD6+NhRJMCF1sWV88VkX6f3n/FHd+xl9uwsrTDEOIbPfWEj120eorw0JEzLhGWfop3ixxKrP0CTIQSAEVmhw5/f94uXAANg3b/r+1YrnV1T86ucPDzBrp3PcvHcHGmaUekL+OKtm9m0ailOUEe4FrXyWaKFblM4HmUvElNzF4jTxFiOhRRSJO34JHCOy6RU0i60uepfx07nO+593FycapAkCbX+Kl+/cxvXfXYIU3GjN/Yf2vPPg2/9JVxoNYNqQ+hcilznlKWDcpSwlCWiZrtx/O3Tf+AKClj88I9v/9aD99/aHBkaLlYNDTXuvPubH/3kN3e9vP3bn78HGAP6gSXA6K3fufnOXz+/888vHH3i9O4XH3j1roe+8dDo1pGvAeuAClfa/+aTQH35Yztuenz7l4aPLB9c81O/3H3L5VHFlUACZaAH6AQc/pv1o9cEiwbWbRlev+mrazeOblg3usnj/6nWV2fVyFp71fCa0sDgkOKyq5av4H/xb0Ky8po5hQEuAAAAAElFTkSuQmCC"},{"id":"OpenStreetMap-turistautak","name":"OpenStreetMap (turistautak)","type":"tms","template":"http://{switch:h,i,j}.tile.openstreetmap.hu/turistautak/{zoom}/{x}/{y}.png","scaleExtent":[0,18],"polygon":[[[16.1139147,46.8691038],[16.1789749,46.90662],[16.2000429,46.9415079],[16.2217547,46.9355441],[16.2462784,46.9463851],[16.2553226,46.9642125],[16.2764694,46.9626082],[16.290583,47.0139849],[16.3016199,46.9992329],[16.3414618,46.9965225],[16.3505162,47.0106313],[16.3734016,46.9985929],[16.412765,47.00475],[16.4332705,46.9927417],[16.4478119,47.003893],[16.479997,46.9941169],[16.5121988,47.0011695],[16.4635584,47.0322699],[16.4478586,47.0227481],[16.439123,47.029663],[16.445673,47.038872],[16.520323,47.056103],[16.473213,47.0736169],[16.4637199,47.09392],[16.500798,47.110058],[16.500035,47.123295],[16.5295349,47.1287419],[16.5171609,47.1496938],[16.454951,47.1425878],[16.4648728,47.1683349],[16.4555643,47.1875584],[16.4305559,47.1847022],[16.4195013,47.1949147],[16.4189215,47.2107114],[16.4371293,47.2097043],[16.4426335,47.2337117],[16.4313127,47.2527554],[16.4671512,47.2531652],[16.4892319,47.2798885],[16.4646338,47.3338455],[16.4337002,47.3528101],[16.458513,47.3670496],[16.4454619,47.4070195],[16.4831657,47.4093628],[16.4963821,47.3892659],[16.5170941,47.4100218],[16.5749054,47.4054243],[16.5807291,47.4191699],[16.661847,47.455595],[16.6706419,47.47422],[16.6523395,47.500342],[16.6895619,47.510161],[16.7147797,47.540199],[16.663545,47.567733],[16.673199,47.6049544],[16.6595343,47.6061018],[16.652758,47.622852],[16.6314207,47.6283176],[16.5739108,47.619667],[16.5147382,47.6461964],[16.4967504,47.6393149],[16.425464,47.6621679],[16.4437449,47.674205],[16.4480507,47.6964725],[16.4746984,47.6811576],[16.4872245,47.6979767],[16.5521729,47.7225519],[16.5363779,47.736785],[16.5479799,47.751544],[16.6095193,47.7603722],[16.6344148,47.7590843],[16.65729,47.7414879],[16.7209405,47.7353565],[16.7534062,47.6828165],[16.8301587,47.681058],[16.8394284,47.7045139],[16.8668943,47.7211462],[16.876679,47.6876452],[17.0937421,47.7077706],[17.0706562,47.7285366],[17.0516019,47.7938499],[17.0749479,47.8084997],[17.047139,47.8285635],[17.0519452,47.8377691],[17.0105513,47.8581765],[17.0163878,47.8673325],[17.0857537,47.8746239],[17.113171,47.9271605],[17.0917133,47.9342916],[17.1183782,47.9601083],[17.094657,47.9708775],[17.2010289,48.019992],[17.241769,48.0224651],[17.257955,47.998655],[17.334651,47.993125],[17.4029929,47.947849],[17.4539199,47.8852579],[17.5267369,47.865509],[17.5675779,47.8151289],[17.608402,47.8218859],[17.7085789,47.756678],[17.7798739,47.739487],[17.8660959,47.74575],[17.9001292,47.7392633],[17.946867,47.744668],[17.9708709,47.7578392],[18.0044103,47.7463402],[18.0380583,47.7576812],[18.2958774,47.7314616],[18.4540681,47.7651226],[18.4931553,47.7527552],[18.5590761,47.7659963],[18.6460866,47.7590921],[18.7260691,47.7890411],[18.7411784,47.8138245],[18.7920013,47.8230869],[18.8485417,47.8167221],[18.855876,47.826077],[18.828014,47.834291],[18.8135749,47.85555],[18.76353,47.8716049],[18.756858,47.896838],[18.776746,47.955092],[18.7552499,47.9763469],[18.8157429,47.993442],[18.819998,48.039676],[18.833268,48.048239],[18.8749364,48.0470707],[18.886674,48.058682],[18.9089819,48.051139],[18.9439039,48.058865],[18.9816099,48.0536009],[19.0148639,48.078179],[19.0585249,48.0573529],[19.0843619,48.072781],[19.107402,48.065596],[19.1352889,48.074146],[19.2413679,48.0536529],[19.2557819,48.0715559],[19.3031119,48.088711],[19.3865969,48.091914],[19.400018,48.082304],[19.454053,48.101436],[19.467354,48.083933],[19.4944199,48.109906],[19.492377,48.1396639],[19.5128219,48.154663],[19.504518,48.173443],[19.528967,48.190358],[19.526044,48.20313],[19.577502,48.2160149],[19.6308263,48.2500725],[19.6445239,48.2391719],[19.669857,48.239212],[19.691219,48.203894],[19.721125,48.201473],[19.74618,48.2165119],[19.7871629,48.19253],[19.7987329,48.19482],[19.8052829,48.183733],[19.782415,48.165039],[19.794812,48.153529],[19.821331,48.169081],[19.8452819,48.162742],[19.8551729,48.178431],[19.8601309,48.169409],[19.898745,48.1663119],[19.9145359,48.146863],[19.898298,48.1249019],[19.937383,48.131118],[19.9743939,48.1660049],[19.988706,48.1621679],[20.029038,48.1776849],[20.049449,48.1671999],[20.0729859,48.179606],[20.0700369,48.1917019],[20.1340909,48.225182],[20.1331879,48.253982],[20.206162,48.250979],[20.2038299,48.261906],[20.228466,48.262779],[20.2349469,48.279933],[20.286858,48.26164],[20.3257109,48.272794],[20.3374649,48.301667],[20.3656579,48.316606],[20.384077,48.3511809],[20.4098349,48.365857],[20.402532,48.382565],[20.4205349,48.403858],[20.416228,48.418536],[20.507929,48.489363],[20.5065069,48.534415],[20.537471,48.527878],[20.5464939,48.544292],[20.586595,48.535759],[20.6538739,48.561413],[20.836359,48.58284],[20.8378,48.57421],[20.8504359,48.5816329],[20.8453301,48.5665046],[20.8681549,48.551818],[20.922323,48.559453],[20.9346349,48.538341],[20.955882,48.533963],[20.9561979,48.521666],[20.9815849,48.5177669],[21.0151139,48.532313],[21.0663209,48.525894],[21.1174479,48.4910549],[21.1608749,48.521499],[21.179634,48.518232],[21.221061,48.537497],[21.305488,48.5222489],[21.313377,48.550841],[21.326875,48.554129],[21.319384,48.561201],[21.4154499,48.558951],[21.4226649,48.578821],[21.4406099,48.585104],[21.514091,48.551065],[21.5420199,48.508395],[21.6139329,48.509416],[21.6201879,48.469826],[21.663549,48.417961],[21.6645609,48.392164],[21.7017409,48.380695],[21.711871,48.357617],[21.8174139,48.332787],[21.8352029,48.3346409],[21.837213,48.363253],[21.8842979,48.356047],[21.8848429,48.367539],[21.897883,48.36256],[21.8997959,48.3702229],[21.9281859,48.3615969],[21.9268059,48.370899],[21.949198,48.378728],[21.994463,48.377323],[22.0213259,48.392749],[22.0546049,48.377528],[22.0764859,48.387241],[22.086743,48.371564],[22.1359089,48.380519],[22.131056,48.3912329],[22.152768,48.3962409],[22.1561913,48.4093076],[22.2125722,48.4256468],[22.2371405,48.4100396],[22.2654858,48.4098675],[22.2398761,48.3870055],[22.2675722,48.3611612],[22.3178106,48.3545437],[22.3132861,48.3250712],[22.3372944,48.3079113],[22.3384267,48.2792074],[22.3847547,48.2339632],[22.4006407,48.249198],[22.4328384,48.2525166],[22.456386,48.2423109],[22.4899029,48.2534237],[22.4972201,48.2395546],[22.5161491,48.237965],[22.5311088,48.2094282],[22.5711442,48.1961428],[22.5616362,48.1816066],[22.5982449,48.144756],[22.5902763,48.1073414],[22.6754492,48.091997],[22.7347192,48.119848],[22.7576242,48.1200599],[22.7703914,48.1090162],[22.772319,48.1218742],[22.8027688,48.1221112],[22.8025285,48.1070813],[22.8254256,48.1175119],[22.8364365,48.080249],[22.8611284,48.0750312],[22.8677955,48.0524256],[22.8820424,48.0548053],[22.8659692,48.0113165],[22.835562,47.9905988],[22.8407599,47.9813636],[22.8725729,47.9752683],[22.8697274,47.9659593],[22.8915652,47.9672446],[22.897435,47.9540629],[22.8473299,47.9077579],[22.7928135,47.8908586],[22.7586924,47.8941446],[22.77775,47.8422508],[22.7136344,47.8360928],[22.6801938,47.7877527],[22.6111171,47.7717455],[22.5490018,47.7722246],[22.4812121,47.8108886],[22.4513078,47.803389],[22.4313319,47.7398119],[22.3566167,47.7486206],[22.3177714,47.7660887],[22.3176236,47.7433657],[22.2851369,47.7292757],[22.264325,47.7310675],[22.2589955,47.6979057],[22.2306796,47.693196],[22.1796501,47.5916115],[22.1289245,47.5978984],[22.0942787,47.5583628],[22.0782587,47.5621299],[22.0534529,47.5474795],[22.0712176,47.5380742],[22.0617872,47.5288029],[22.0451278,47.5398919],[22.0367222,47.5326653],[22.0071886,47.48362],[22.0327909,47.4508372],[22.0238835,47.3908631],[22.0119849,47.3758016],[21.9627373,47.381053],[21.9382461,47.3725317],[21.8777922,47.2857763],[21.8872845,47.2730473],[21.8534909,47.2397622],[21.8580662,47.1873597],[21.8124804,47.1667511],[21.7924092,47.1059751],[21.7268258,47.0983882],[21.6976037,47.057915],[21.6504151,47.0408303],[21.6888701,47.0019977],[21.6678744,46.9712337],[21.6814917,46.9652089],[21.6381964,46.9330487],[21.5984455,46.9274708],[21.6142857,46.8867275],[21.6016694,46.8668202],[21.520328,46.8373749],[21.5186086,46.8000703],[21.4831761,46.7650246],[21.5263389,46.7393249],[21.529369,46.7209721],[21.4923253,46.6859652],[21.4728438,46.6959075],[21.4299047,46.693937],[21.4309553,46.6781367],[21.4546661,46.660863],[21.4162375,46.6426231],[21.4097959,46.6218052],[21.3657038,46.6379501],[21.3300499,46.6318155],[21.3139733,46.617666],[21.3012351,46.5908672],[21.3207905,46.5828562],[21.2743045,46.5407362],[21.2600254,46.5021583],[21.2744188,46.4767333],[21.2964506,46.4762973],[21.3174343,46.4507288],[21.2895176,46.4154784],[21.2963256,46.4069601],[21.2250116,46.4136899],[21.2064214,46.4033825],[21.1992563,46.3479034],[21.1762269,46.3357664],[21.180497,46.3044494],[21.1155437,46.3018529],[21.1030549,46.2624637],[21.0708792,46.2539014],[21.0660827,46.2429394],[21.0366237,46.2480392],[21.0246723,46.2665329],[20.960817,46.2623039],[20.9465849,46.2793024],[20.9250701,46.2766191],[20.9218133,46.2618129],[20.8732713,46.2877555],[20.7756538,46.2759602],[20.7490474,46.2508489],[20.7618619,46.204563],[20.727401,46.2077485],[20.7341052,46.1939355],[20.7140487,46.1660531],[20.6843592,46.1447802],[20.6549178,46.1497739],[20.6394471,46.1267602],[20.5450486,46.1790935],[20.5014839,46.190334],[20.4949436,46.1709908],[20.4592293,46.1428837],[20.3975133,46.1574709],[20.3685325,46.1528554],[20.3557074,46.1696256],[20.2968136,46.1521542],[20.2549024,46.1158522],[20.2484757,46.1300956],[20.2330132,46.1241668],[20.1817362,46.1601137],[20.1364966,46.1449476],[20.1009667,46.1772756],[20.0636156,46.1437275],[20.0346142,46.1458888],[20.0158072,46.1768354],[19.9354075,46.1764243],[19.8533469,46.1500005],[19.8179747,46.1281652],[19.7585403,46.1479754],[19.6982054,46.1879317],[19.6827672,46.1800388],[19.661508,46.1904394],[19.6317396,46.1692993],[19.5676482,46.179106],[19.5604013,46.1665762],[19.5026585,46.1424492],[19.5271208,46.1210269],[19.4645033,46.0953827],[19.4665828,46.0820437],[19.4160037,46.0460453],[19.3803957,46.0358749],[19.3640923,46.0522965],[19.2819012,46.0148048],[19.2965348,45.9881173],[19.2856472,45.9968981],[19.1479857,45.9963445],[19.1338422,46.0370993],[19.104873,46.0401673],[19.0660427,46.0001999],[19.0796791,45.9636376],[19.0059803,45.9590674],[19.0092745,45.9236559],[18.9061334,45.9353801],[18.8794572,45.9166827],[18.8647137,45.9208493],[18.8685629,45.9113361],[18.8276792,45.9051714],[18.8220041,45.9145893],[18.8075092,45.9036055],[18.809247,45.8796189],[18.7956242,45.8784488],[18.7048857,45.9181883],[18.6700246,45.9108439],[18.6596602,45.9168934],[18.6651348,45.899279],[18.6412808,45.8890396],[18.6550179,45.8742393],[18.6277704,45.8733782],[18.6148449,45.8531438],[18.6236656,45.8398531],[18.5732391,45.8137578],[18.5749849,45.8004344],[18.559716,45.8037961],[18.5223504,45.7826858],[18.4906706,45.7947167],[18.4821905,45.7655032],[18.4562828,45.7695229],[18.4450763,45.7605195],[18.446853,45.737128],[18.40763,45.7397119],[18.3918949,45.7616983],[18.3642257,45.7729364],[18.3394214,45.7471605],[18.2968157,45.7612196],[18.2440473,45.7612305],[18.2307311,45.7790328],[18.1908702,45.7878759],[18.1681939,45.7762712],[18.1246514,45.7896277],[18.1068067,45.7708256],[18.0818922,45.7645205],[17.9958808,45.7957311],[17.9302095,45.7863301],[17.9066757,45.7925692],[17.8653145,45.7670064],[17.8262748,45.8099957],[17.8089784,45.8040989],[17.7809054,45.8174884],[17.7603399,45.811923],[17.7408624,45.8295975],[17.6632915,45.8381849],[17.6276211,45.8979446],[17.5700676,45.9358204],[17.4378254,45.9503823],[17.4258964,45.9272681],[17.4108059,45.9399665],[17.392149,45.9302149],[17.3828713,45.9475733],[17.3476208,45.9423413],[17.3438769,45.9605329],[17.3537711,45.9525011],[17.3905375,45.9581914],[17.387423,45.9661823],[17.3583539,45.9642737],[17.3754852,45.9686921],[17.3751895,45.9881054],[17.3635685,45.9915442],[17.3567202,45.9735836],[17.3339583,45.9960781],[17.3319847,45.9728948],[17.3129974,45.9665347],[17.323647,45.9887776],[17.2987653,45.9838652],[17.3041996,46.0021128],[17.2579726,46.0110256],[17.29632,46.0285169],[17.2541514,46.030005],[17.270955,46.0567055],[17.2324767,46.0592034],[17.2525145,46.0664725],[17.2313144,46.0790345],[17.2019916,46.0765488],[17.2331299,46.0989644],[17.2104017,46.1001693],[17.2129734,46.113855],[17.175927,46.1084583],[17.1743424,46.1287608],[17.1865197,46.1332308],[17.1810983,46.1505485],[17.1562307,46.1585819],[17.1592857,46.1696818],[17.1261012,46.1684495],[17.1227409,46.1789791],[17.0752482,46.1889531],[17.0661614,46.2022984],[16.9735401,46.2251982],[16.973954,46.2431113],[16.9504085,46.2415285],[16.8862356,46.2814598],[16.8713682,46.3252767],[16.8802109,46.3356966],[16.8615374,46.3452401],[16.8656232,46.3556489],[16.8521959,46.3517189],[16.8498589,46.3626245],[16.8352859,46.3638195],[16.8376499,46.3748032],[16.8261732,46.3670994],[16.7933444,46.387385],[16.7592072,46.3776563],[16.7298672,46.40149],[16.7182119,46.3898704],[16.6772872,46.4494536],[16.6631785,46.4486958],[16.6663732,46.4582995],[16.6187915,46.4619875],[16.604468,46.4760773],[16.5235997,46.5053761],[16.5325768,46.5314027],[16.5176728,46.5363516],[16.5084107,46.5652692],[16.4829969,46.5660383],[16.4834008,46.5786011],[16.4455713,46.610952],[16.4248583,46.6131645],[16.385941,46.6442485],[16.3915424,46.6637257],[16.4198454,46.6584771],[16.4286335,46.6939737],[16.3689211,46.7040082],[16.3798266,46.7153869],[16.3710856,46.7222945],[16.3570587,46.7142387],[16.3185954,46.7541449],[16.3305417,46.7752119],[16.3121626,46.7780033],[16.3127666,46.797314],[16.3406373,46.8051851],[16.3508404,46.8300552],[16.3403309,46.8468762],[16.3015007,46.8595142],[16.2913867,46.8728341],[16.2332296,46.8766702],[16.1560866,46.8537074],[16.126571,46.8569079],[16.1139147,46.8691038]]],"terms_url":"https://www.openstreetmap.org/","terms_text":"© OpenStreetMap contributors"},{"id":"osm-gps","name":"OpenStreetMap GPS traces","type":"tms","template":"https://{switch:a,b,c}.gps-tile.openstreetmap.org/lines/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"terms_url":"https://www.openstreetmap.org/copyright","terms_text":"© OpenStreetMap contributors","terms_html":"<span style='display: inline-block; padding: 0 8px; background-color: rgba(0,0,0,0.5);'><span style='color: #eee;'>GPS Direction:</span> <span style='font-size: 15px; padding-left: 2px; font-weight: bold;'> <span style='color: #0ee;'>&larr;</span> <span style='color: #96f;'>&darr;</span> <span style='color: #6e0;'>&uarr;</span> <span style='color: #f63;'>&rarr;</span> </span></span> © <a href='https://www.openstreetmap.org/copyright'>OpenStreetMap contributors</a>.","description":"Public GPS traces uploaded to OpenStreetMap.","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAGb0lEQVR4Xq3MS2xcVx3H8e855z7m3vH1jMdjO43zshIrtpM0SZ3WFEcRVFFKoRWPBYtAHwgWCFUsQN100QeCsqAhCESrirRASdWWIkoUqgKFJm3UZ5o2oW2akrR5uXbi2ON4PPfOfZ17iERW2bCAz1/f3V8/cfDC02UEj4OxKHjdFMUfmUzOlAeXZFZuuVIKN8zi1dPh7Hcn5091G2EOB5b//NplA28/9tAT4bq111jD64ZKHR2VQWPEbULI0aHqZz7NZeLNmSeVMOJu4AfGgNEGLsR/95YuetcRzprcFJvaaVxrpm2mmqfp8FxKSYk8ck+0pt1nykFp0A/k9Tnt/lq3T2dHEOmi2DxSu+EdAAFwcPqp640xe42h26Qa2hqnXsFVHs04pNFuYgvbtOWCmD3aMj2VNaLi1+jwyxgpCKOQRCdMN6ZMd5Bmw1cPfG+5O/7LeX0ECyBppx9Zrn0c6BbNHJNr4qhFYWtsJCWpSFUm3ntxips2bxe+p1BKIJQECpRbkCQ2wu0XzbnIeemvhzYCVNR6JMDm5bdNF9qcwhiKbpvMg2KujZDmUgX1jgqT719gy+iX6QxsPM9F2YqclHbRRpUEXmCRZTGFlZGKxSMbR6+uA0gu863OzLc7cVUZN6jgKI8kicl0ykzjAiW5lGrVAWUwokApSa3UTY/XR2B3UlDgVy1sB8od7tgt2++4AcACOHL+uRW2bW8QQiCxcUoS6XssyBbnF6Y5+8kci8vjlJwqjnQwWpDlgtRYZDpHmxJzWUyk26gOYXxK0g+8G4bXX/snC0DZcmVh9EoQ5DpDSIVJYmIiGvkCurAQpkLU9kkTEEJeCjxbURSCZgTkfVjOApoM6Qtc3109Nj7uWO9M70EbPQT4YMhNjrWQEdHmTPs8SgfUisUgDLoAgcGyEjJtEaeaVlKQ5gVSGYwBhETaEmVJcemQaZ44aRpvyLIEnedGoNHNkNTTeI5DT2kRljeJziVhnKNlE1GaJFfnuRi3SXMDxmA7IUqCI20qdifkxfED+/dlanzb1cYL3BFhsTXPU4Ep0FGKUVALegCb1oLN7FlNpd5HIUNQLYxIsO0EKcByWljuAmXbp7fcIwgVb7xyaNeep3YfUnt272PLjaP1em/lZqmEk4cJQoMKfBxVIcwjlAp47okX6ap3XaoP221CIREyx7La2E6O7/h0eTXK+Bw+8uHrP7znvocXLe6flwCHXj06kab5hJAS6dhQFOgiJ2qXsKLVuHqAgdVD7HrwXibPTKJzFyMMAgECHGXTJTqxE4t3T5xMD7y29+mFRjgpLSUlYJ793T9ORWF0Lk1StCzQNqTTAle30flbzJ/bx6n3Xsa2Fb9/5Eccfu19wnlNFBniWJA3JecbDfa/8y5nJg7bW7ZeuyYKZwyF0QIAkC988Ogzfof6SppapHGZqgNTExPsfngfgaXpqyWk9QF6lwWk7YJlK1fQaTysqk8sE6LwIq4OEMql1DH3/O03PnBHUCk3JMCeA7/q6u1a0ltiNZ1eL719cPrcWR752d+Yn2lx/HSDY40qY2Pb2PapjYxv3YBX1syZ88weP3bp90Omw3PMOxNUe9FTn9gn5uemQqfk5BbAisHBlVo7g7PFx9TdgDMnZvjtzheI51qkWY5xYWxTLxXfJ5IVevIZ6gMDxCYnPjWDXZ0nSiOkEmYqO5l8cGT6FSD6+NhRJMCF1sWV88VkX6f3n/FHd+xl9uwsrTDEOIbPfWEj120eorw0JEzLhGWfop3ixxKrP0CTIQSAEVmhw5/f94uXAANg3b/r+1YrnV1T86ucPDzBrp3PcvHcHGmaUekL+OKtm9m0ailOUEe4FrXyWaKFblM4HmUvElNzF4jTxFiOhRRSJO34JHCOy6RU0i60uepfx07nO+593FycapAkCbX+Kl+/cxvXfXYIU3GjN/Yf2vPPg2/9JVxoNYNqQ+hcilznlKWDcpSwlCWiZrtx/O3Tf+AKClj88I9v/9aD99/aHBkaLlYNDTXuvPubH/3kN3e9vP3bn78HGAP6gSXA6K3fufnOXz+/888vHH3i9O4XH3j1roe+8dDo1pGvAeuAClfa/+aTQH35Yztuenz7l4aPLB9c81O/3H3L5VHFlUACZaAH6AQc/pv1o9cEiwbWbRlev+mrazeOblg3usnj/6nWV2fVyFp71fCa0sDgkOKyq5av4H/xb0Ky8po5hQEuAAAAAElFTkSuQmCC","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","endDate":"2010-07-02T00:00:00.000Z","startDate":"2010-06-24T00:00:00.000Z","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","icon":"https://www.geoportail.lu/static/img/lion.png"},{"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","endDate":"2013-07-20T00:00:00.000Z","startDate":"2013-07-19T00:00:00.000Z","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","icon":"https://www.geoportail.lu/static/img/lion.png"},{"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","endDate":"2016-08-16T00:00:00.000Z","startDate":"2013-08-30T00:00:00.000Z","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,"icon":"https://www.geoportail.lu/static/img/lion.png"},{"id":"OS-historic-25k-OSM_Limited","name":"OS 1:25k historic (OSM)","type":"tms","template":"http://ooc.openstreetmap.org/os1/{zoom}/{x}/{y}.jpg","scaleExtent":[6,17],"polygon":[[[-6.4585407,49.9044128],[-6.3872009,49.9841116],[-6.2296827,49.9896159],[-6.2171269,49.8680087],[-6.4551164,49.8591793],[-6.4585407,49.9044128]],[[-1.4495137,60.8634056],[-0.7167114,60.8545122],[-0.7349744,60.4359756],[-0.6938826,60.4168218],[-0.7258429,60.3942735],[-0.7395401,60.0484714],[-0.9267357,60.0461918],[-0.9381501,59.8266157],[-1.4586452,59.831205],[-1.4455187,60.0535999],[-1.463211,60.0535999],[-1.4643524,60.0630002],[-1.5716475,60.0638546],[-1.5693646,60.1790005],[-1.643558,60.1807033],[-1.643558,60.1892162],[-1.8216221,60.1894999],[-1.8204807,60.3615507],[-1.8415973,60.3697345],[-1.8216221,60.3832755],[-1.8179852,60.5934321],[-1.453168,60.5934321],[-1.4495137,60.8634056]],[[-4.9089213,54.4242078],[-4.282598,54.4429861],[-4.2535417,54.029769],[-4.8766366,54.0221831],[-4.9089213,54.4242078]],[[-5.8667408,59.1444603],[-5.7759966,59.1470945],[-5.7720016,59.1014052],[-5.8621751,59.0990605],[-5.8667408,59.1444603]],[[-1.7065887,59.5703599],[-1.5579165,59.5693481],[-1.5564897,59.4965695],[-1.7054472,59.4975834],[-1.7065887,59.5703599]],[[-7.6865827,58.2940975],[-7.5330594,58.3006957],[-7.5256401,58.2646905],[-7.6797341,58.2577853],[-7.6865827,58.2940975]],[[-4.5338281,59.0359871],[-4.481322,59.0371616],[-4.4796099,59.0186583],[-4.5332574,59.0180707],[-4.5338281,59.0359871]],[[-8.6710698,57.8769896],[-8.4673234,57.8897332],[-8.4467775,57.7907],[-8.6510947,57.7779213],[-8.6710698,57.8769896]],[[-5.2395519,50.3530581],[-5.7920073,50.3384899],[-5.760047,49.9317027],[-4.6551363,49.9581461],[-4.677965,50.2860073],[-4.244219,50.2801723],[-4.2487848,50.2042525],[-3.3812929,50.2042525],[-3.4223846,50.5188201],[-3.1164796,50.5246258],[-3.1210453,50.6579592],[-2.6736357,50.6619495],[-2.5953453,50.6394325],[-2.5905026,50.5728419],[-2.4791203,50.5733545],[-2.4758919,50.5066704],[-2.3967943,50.5056438],[-2.401637,50.5723293],[-1.0400296,50.5718167],[-1.0335726,50.7059289],[-0.549302,50.7038843],[-0.5460736,50.7886618],[-0.0924734,50.7856002],[-0.0876307,50.7181949],[0.4789659,50.7120623],[0.487037,50.8182467],[0.9761503,50.8049868],[0.9922927,51.0126311],[1.4491213,51.0004424],[1.4781775,51.4090372],[1.0229632,51.4271576],[1.035877,51.7640881],[1.6105448,51.7500992],[1.646058,52.1560003],[1.7267698,52.1540195],[1.749369,52.4481811],[1.7870672,52.4811624],[1.759102,52.522505],[1.7933451,52.9602749],[0.3798147,52.9958468],[0.3895238,53.2511239],[0.3478614,53.2511239],[0.3238912,53.282186],[0.3461492,53.6538501],[0.128487,53.6575466],[0.116582,53.6674703],[0.1350586,54.0655731],[-0.0609831,54.065908],[-0.0414249,54.4709448],[-0.5662701,54.4771794],[-0.5592078,54.6565127],[-1.1665638,54.6623485],[-1.1637389,54.842611],[-1.3316194,54.843909],[-1.3257065,55.2470842],[-1.529453,55.2487108],[-1.524178,55.6540122],[-1.7638798,55.6540122],[-1.7733693,55.9719116],[-2.1607858,55.9682981],[-2.1543289,56.0621387],[-2.4578051,56.0585337],[-2.4190635,56.641717],[-2.0962164,56.641717],[-2.0833025,57.0021322],[-1.9283359,57.0126802],[-1.9180966,57.3590895],[-1.7502161,57.3625721],[-1.7695869,57.7608634],[-3.6937554,57.7574187],[-3.7066693,57.9806386],[-3.5969013,57.9772149],[-3.6033582,58.1207277],[-3.0222335,58.1309566],[-3.0286905,58.5410788],[-2.8478961,58.530968],[-2.86081,58.8430508],[-2.679624,58.8414991],[-2.6841897,58.885175],[-2.6339665,58.9052239],[-2.679624,58.9335083],[-2.6887555,59.0229231],[-2.3668703,59.0229231],[-2.3702946,59.2652861],[-2.3429001,59.2821989],[-2.3714361,59.2996861],[-2.3737189,59.3707083],[-2.3429001,59.385825],[-2.3725775,59.400354],[-2.3714361,59.4259098],[-3.0734196,59.4230067],[-3.0711368,59.3433649],[-3.103097,59.3311405],[-3.0745611,59.3136695],[-3.0722782,59.232603],[-3.3850319,59.1484167],[-3.3747589,58.9352753],[-3.5653789,58.9323303],[-3.554829,58.69759],[-5.2808579,58.6667732],[-5.2534159,58.3514125],[-5.5068508,58.3437887],[-5.4761804,58.0323557],[-5.8974958,58.0212436],[-5.8522972,57.6171758],[-6.1396311,57.6137174],[-6.1541592,57.7423183],[-6.2913692,57.7380102],[-6.3365678,58.1398784],[-6.1121891,58.1466944],[-6.1473778,58.5106285],[-6.2934817,58.5416182],[-6.8413713,58.2977321],[-7.0057382,58.2929331],[-7.1016189,58.2064403],[-7.2573132,58.1793148],[-7.2531092,58.1004928],[-7.4070698,58.0905566],[-7.391347,57.7911354],[-7.790991,57.7733151],[-7.7624215,57.5444165],[-7.698501,57.1453194],[-7.7943817,57.1304547],[-7.716764,56.7368628],[-7.0122067,56.7654359],[-6.979922,56.5453858],[-7.0638622,56.5453858],[-7.0444914,56.3562587],[-6.500676,56.3812917],[-6.4491433,55.9793649],[-6.563287,55.9691456],[-6.5393742,55.7030135],[-6.5595521,55.6907321],[-6.5345315,55.6761713],[-6.5216176,55.5704434],[-5.8912587,55.5923416],[-5.8560127,55.2320733],[-5.2293639,55.2515958],[-5.1837064,54.6254139],[-3.6655956,54.6518373],[-3.6496155,54.4320023],[-3.5400375,54.4306744],[-3.530906,54.0290181],[-3.0697656,54.030359],[-3.0675737,53.8221388],[-3.0804876,53.7739911],[-3.0619239,53.7477488],[-3.0611168,53.6737049],[-3.2144691,53.6708361],[-3.2057699,53.4226163],[-3.2799632,53.355224],[-3.2896655,53.3608441],[-3.3327547,53.364931],[-3.3761293,53.3540318],[-4.0888976,53.3433102],[-4.0945474,53.4612036],[-4.697412,53.4448624],[-4.6882805,53.3318598],[-4.7202407,53.2895771],[-4.6837148,53.2486184],[-4.6768661,53.1542644],[-4.8480816,53.1446807],[-4.8178336,52.7440299],[-4.2545751,52.7558939],[-4.228876,52.254876],[-4.2607571,52.2536408],[-4.2724603,52.2432637],[-4.8136263,52.230095],[-4.8079191,52.1138892],[-5.3889104,52.0991668],[-5.3717888,51.9129667],[-5.4208706,51.9101502],[-5.414022,51.8453218],[-5.3683645,51.8474373],[-5.3466772,51.5595332],[-4.773676,51.5758518],[-4.7656859,51.4885146],[-4.1915432,51.4970427],[-4.1869775,51.4344663],[-3.6151177,51.4444274],[-3.6105519,51.3746543],[-3.1494115,51.3789292],[-3.1494115,51.2919281],[-4.3038735,51.2745907],[-4.2861169,51.0508721],[-4.8543277,51.0366633],[-4.8372201,50.7212787],[-5.2618345,50.7082694],[-5.2395519,50.3530581]],[[-2.1502671,60.171318],[-2.0030218,60.1696146],[-2.0013096,60.0997023],[-2.148555,60.1011247],[-2.1502671,60.171318]],[[-6.2086011,59.1163488],[-6.1229934,59.1166418],[-6.121852,59.0714985],[-6.2097426,59.0714985],[-6.2086011,59.1163488]],[[-4.4159559,59.0889036],[-4.4212022,59.0770848],[-4.3971904,59.0779143],[-4.3913388,59.0897328],[-4.4159559,59.0889036]]]},{"id":"OS-New_Popular_Edition-historic","name":"OS New Popular Edition historic","type":"tms","template":"http://ooc.openstreetmap.org/npe/{zoom}/{x}/{y}.png","polygon":[[[-5.8,49.8],[-5.8,55.8],[1.9,55.8],[1.9,49.8],[-5.8,49.8]]]},{"id":"OS-OpenData_Locator","name":"OS OpenData Locator","type":"tms","template":"http://tiles.itoworld.com/os_locator/{zoom}/{x}/{y}.png","polygon":[[[-9,49.8],[-9,61.1],[1.9,61.1],[1.9,49.8],[-9,49.8]]],"overlay":true},{"id":"OS-OpenData_StreetView","name":"OS OpenData StreetView","type":"tms","template":"http://os.openstreetmap.org/sv/{zoom}/{x}/{y}.png","scaleExtent":[1,18],"polygon":[[[-5.8292886,50.0229734],[-5.8292886,50.254819],[-5.373356,50.254819],[-5.373356,50.3530588],[-5.1756021,50.3530588],[-5.1756021,50.5925406],[-4.9970743,50.5925406],[-4.9970743,50.6935617],[-4.7965738,50.6935617],[-4.7965738,50.7822112],[-4.6949503,50.7822112],[-4.6949503,50.9607371],[-4.6043131,50.9607371],[-4.6043131,51.0692066],[-4.3792215,51.0692066],[-4.3792215,51.2521782],[-3.9039346,51.2521782],[-3.9039346,51.2916998],[-3.7171671,51.2916998],[-3.7171671,51.2453014],[-3.1486246,51.2453014],[-3.1486246,51.362067],[-3.7446329,51.362067],[-3.7446329,51.4340386],[-3.8297769,51.4340386],[-3.8297769,51.5298246],[-4.0852091,51.5298246],[-4.0852091,51.4939284],[-4.3792215,51.4939284],[-4.3792215,51.5427168],[-5.1444195,51.5427168],[-5.1444195,51.6296003],[-5.7387103,51.6296003],[-5.7387103,51.774037],[-5.5095393,51.774037],[-5.5095393,51.9802596],[-5.198799,51.9802596],[-5.198799,52.0973358],[-4.8880588,52.0973358],[-4.8880588,52.1831557],[-4.4957492,52.1831557],[-4.4957492,52.2925739],[-4.3015365,52.2925739],[-4.3015365,52.3685318],[-4.1811246,52.3685318],[-4.1811246,52.7933685],[-4.4413696,52.7933685],[-4.4413696,52.7369614],[-4.8569847,52.7369614],[-4.8569847,52.9317255],[-4.7288044,52.9317255],[-4.7288044,53.5038599],[-4.1578191,53.5038599],[-4.1578191,53.4113498],[-3.3110518,53.4113498],[-3.3110518,53.5038599],[-3.2333667,53.5038599],[-3.2333667,54.0159169],[-3.3926211,54.0159169],[-3.3926211,54.1980953],[-3.559644,54.1980953],[-3.559644,54.433732],[-3.7188984,54.433732],[-3.7188984,54.721897],[-4.3015365,54.721897],[-4.3015365,54.6140739],[-5.0473132,54.6140739],[-5.0473132,54.7532915],[-5.2298731,54.7532915],[-5.2298731,55.2190799],[-5.6532567,55.2190799],[-5.6532567,55.250088],[-5.8979647,55.250088],[-5.8979647,55.4822462],[-6.5933212,55.4822462],[-6.5933212,56.3013441],[-7.1727691,56.3013441],[-7.1727691,56.5601822],[-6.8171722,56.5601822],[-6.8171722,56.6991713],[-6.5315276,56.6991713],[-6.5315276,56.9066964],[-6.811679,56.9066964],[-6.811679,57.3716613],[-6.8721038,57.3716613],[-6.8721038,57.5518893],[-7.0973235,57.5518893],[-7.0973235,57.2411085],[-7.1742278,57.2411085],[-7.1742278,56.9066964],[-7.3719817,56.9066964],[-7.3719817,56.8075885],[-7.5202972,56.8075885],[-7.5202972,56.7142479],[-7.8306806,56.7142479],[-7.8306806,56.8994605],[-7.6494061,56.8994605],[-7.6494061,57.4739617],[-7.8306806,57.4739617],[-7.8306806,57.7915584],[-7.4736249,57.7915584],[-7.4736249,58.086063],[-7.1879804,58.086063],[-7.1879804,58.367197],[-6.8034589,58.367197],[-6.8034589,58.4155786],[-6.638664,58.4155786],[-6.638664,58.4673277],[-6.5178143,58.4673277],[-6.5178143,58.5625632],[-6.0536224,58.5625632],[-6.0536224,58.1568843],[-6.1470062,58.1568843],[-6.1470062,58.1105865],[-6.2799798,58.1105865],[-6.2799798,57.7122664],[-6.1591302,57.7122664],[-6.1591302,57.6667563],[-5.9339104,57.6667563],[-5.9339104,57.8892524],[-5.80643,57.8892524],[-5.80643,57.9621767],[-5.6141692,57.9621767],[-5.6141692,58.0911236],[-5.490819,58.0911236],[-5.490819,58.3733281],[-5.3199118,58.3733281],[-5.3199118,58.75015],[-3.5719977,58.75015],[-3.5719977,59.2091788],[-3.1944501,59.2091788],[-3.1944501,59.4759216],[-2.243583,59.4759216],[-2.243583,59.1388749],[-2.4611012,59.1388749],[-2.4611012,58.8185938],[-2.7407675,58.8185938],[-2.7407675,58.5804743],[-2.9116746,58.5804743],[-2.9116746,58.1157523],[-3.4865441,58.1157523],[-3.4865441,57.740386],[-1.7153245,57.740386],[-1.7153245,57.2225558],[-1.9794538,57.2225558],[-1.9794538,56.8760742],[-2.1658979,56.8760742],[-2.1658979,56.6333186],[-2.3601106,56.6333186],[-2.3601106,56.0477521],[-1.9794538,56.0477521],[-1.9794538,55.8650949],[-1.4745008,55.8650949],[-1.4745008,55.2499926],[-1.3221997,55.2499926],[-1.3221997,54.8221737],[-1.0550014,54.8221737],[-1.0550014,54.6746628],[-0.6618765,54.6746628],[-0.6618765,54.5527463],[-0.3247617,54.5527463],[-0.3247617,54.2865195],[0.0092841,54.2865195],[0.0092841,53.7938518],[0.2081962,53.7938518],[0.2081962,53.5217726],[0.4163548,53.5217726],[0.4163548,53.0298851],[1.4273388,53.0298851],[1.4273388,52.92021],[1.8333912,52.92021],[1.8333912,52.042488],[1.5235504,52.042488],[1.5235504,51.8261335],[1.2697049,51.8261335],[1.2697049,51.6967453],[1.116651,51.6967453],[1.116651,51.440346],[1.5235504,51.440346],[1.5235504,51.3331831],[1.4507565,51.3331831],[1.4507565,51.0207553],[1.0699883,51.0207553],[1.0699883,50.9008416],[0.7788126,50.9008416],[0.7788126,50.729843],[-0.7255952,50.729843],[-0.7255952,50.7038437],[-1.0074383,50.7038437],[-1.0074383,50.5736307],[-2.3625252,50.5736307],[-2.3625252,50.4846421],[-2.4987805,50.4846421],[-2.4987805,50.5736307],[-3.4096378,50.5736307],[-3.4096378,50.2057837],[-3.6922446,50.2057837],[-3.6922446,50.1347737],[-5.005468,50.1347737],[-5.005468,49.9474456],[-5.2839506,49.9474456],[-5.2839506,50.0229734],[-5.8292886,50.0229734]],[[-6.4580707,49.8673563],[-6.4580707,49.9499935],[-6.3978807,49.9499935],[-6.3978807,50.0053797],[-6.1799606,50.0053797],[-6.1799606,49.9168614],[-6.2540201,49.9168614],[-6.2540201,49.8673563],[-6.4580707,49.8673563]],[[-5.8343165,49.932156],[-5.8343165,49.9754641],[-5.7683254,49.9754641],[-5.7683254,49.932156],[-5.8343165,49.932156]],[[-1.9483797,60.6885737],[-1.9483797,60.3058841],[-1.7543149,60.3058841],[-1.7543149,60.1284428],[-1.5754914,60.1284428],[-1.5754914,59.797917],[-1.0316959,59.797917],[-1.0316959,60.0354518],[-0.6626918,60.0354518],[-0.6626918,60.9103862],[-1.1034395,60.9103862],[-1.1034395,60.8040022],[-1.3506319,60.8040022],[-1.3506319,60.6885737],[-1.9483797,60.6885737]],[[-2.203381,60.1968568],[-2.203381,60.0929443],[-1.9864011,60.0929443],[-1.9864011,60.1968568],[-2.203381,60.1968568]],[[-1.7543149,59.5698289],[-1.7543149,59.4639383],[-1.5373349,59.4639383],[-1.5373349,59.5698289],[-1.7543149,59.5698289]],[[-4.5585981,59.1370518],[-4.5585981,58.9569099],[-4.2867004,58.9569099],[-4.2867004,59.1370518],[-4.5585981,59.1370518]],[[-6.2787732,59.2025744],[-6.2787732,59.0227769],[-5.6650612,59.0227769],[-5.6650612,59.2025744],[-6.2787732,59.2025744]],[[-8.7163482,57.9440556],[-8.7163482,57.7305936],[-8.3592926,57.7305936],[-8.3592926,57.9440556],[-8.7163482,57.9440556]],[[-7.6077005,50.4021026],[-7.6077005,50.2688657],[-7.3907205,50.2688657],[-7.3907205,50.4021026],[-7.6077005,50.4021026]],[[-7.7304303,58.3579902],[-7.7304303,58.248313],[-7.5134503,58.248313],[-7.5134503,58.3579902],[-7.7304303,58.3579902]]]},{"id":"OS-Scottish_Popular-historic","name":"OS Scottish Popular historic","type":"tms","template":"http://ooc.openstreetmap.org/npescotland/tiles/{zoom}/{x}/{y}.jpg","scaleExtent":[6,15],"polygon":[[[-7.8,54.5],[-7.8,61.1],[-1.1,61.1],[-1.1,54.5],[-7.8,54.5]]]},{"id":"Pangasinan_Bulacan_HiRes","name":"Pangasinán/Bulacan (Philippines HiRes)","type":"tms","template":"http://gravitystorm.dev.openstreetmap.org/imagery/philippines/{zoom}/{x}/{y}.png","scaleExtent":[12,19],"polygon":[[[120.336593,15.985768],[120.445995,15.984],[120.446134,15.974459],[120.476464,15.974592],[120.594247,15.946832],[120.598064,16.090795],[120.596537,16.197999],[120.368537,16.218527],[120.347576,16.042308],[120.336593,15.985768]],[[120.8268,15.3658],[121.2684,15.2602],[121.2699,14.7025],[120.695,14.8423],[120.8268,15.3658]]]},{"id":"Actueel_ortho25_WMTS","name":"PDOK Luchtfoto Beeldmateriaal 25cm","type":"tms","template":"http://geodata.nationaalgeoregister.nl/luchtfoto/wmts?FORMAT=image/jpeg&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=2016_ortho25&STYLE=&FORMAT=image/jpeg&tileMatrixSet=OGC:1.0:GoogleMapsCompatible&tileMatrix={zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,18],"polygon":[[[3.1437689,51.3598403],[3.1575018,51.2411346],[3.3387762,51.1154412],[3.9128119,51.0585083],[4.6571356,51.2806657],[4.8933416,51.2634825],[5.1789862,51.1257851],[5.3849798,51.1309561],[5.5442816,51.056782],[5.4206854,50.8595581],[5.4673773,50.7032633],[5.6568914,50.6192567],[6.1485296,50.6214349],[6.3023382,50.8578243],[6.2995916,50.9543819],[6.2638861,51.0183545],[6.3723761,51.0925902],[6.4012152,51.2011393],[6.3737494,51.2510206],[6.4451605,51.3158713],[6.4204413,51.5496009],[6.343537,51.6792182],[6.796723,51.7642909],[7.046662,51.9102418],[7.0713812,52.0455856],[7.2718817,52.1704147],[7.3075872,52.3855111],[7.2059637,52.5319494],[7.282868,52.614576],[7.2993475,52.7785318],[7.4421698,52.9782705],[7.43393,53.2831352],[7.0439154,53.5515877],[6.7829901,53.6363531],[6.2391668,53.5401639],[5.6871039,53.5124077],[5.173493,53.4388477],[4.8164373,53.2338445],[4.6516424,53.0658312],[4.5417791,52.4859784],[4.3220526,52.1956753],[4.08104,52.0136897],[4.0219885,52.0162253],[3.9368445,51.9637937],[3.9519507,51.8807927],[3.844834,51.8494157],[3.6237341,51.7075226],[3.6553198,51.6606936],[3.6333471,51.6274583],[3.5468298,51.622343],[3.3957678,51.5609145],[3.3820349,51.5173524],[3.4987646,51.4326715],[3.3298498,51.3855587],[3.1437689,51.3598403]]],"terms_url":"http://www.nationaalgeoregister.nl/geonetwork/srv/dut/catalog.search#/search?facet.q=license%2FCC-BY&isChild=%27false%27&resultType=details&any_OR_title_OR_keyword=luchtfoto&fast=index&_content_type=json&from=1&to=20&sortBy=relevance","terms_text":"Kadaster / Beeldmateriaal.nl, CC BY 4.0","best":true,"description":"Landsdekkende dataset 25cm resolutie kleuren luchtfotos van de meest recente jaargang.","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGYAAABpCAMAAAD/V6aFAAABQVBMVEVHcEzFxcUIjtE3quLGxsYMlNMxseXFxcXFxcXGxsY3qeC82+c4qeA4quEcod3FxcXGxsbGxsbKysrHx8cGkdLGxsYPl9fExMTGxsbGxsbGxsYGjtDGxsYLlNXFxcXKysrGxsY3qeDFxcXGxsbFxcXGxsY3qeHGxsbIyMjGxsbGxsbFxcXFxcXFxcXGxsYBi883quHExMTGxsbGxsYgpdkYntoeqtXGxsYko93FxcXFxcUio97GxsYDjdAcn9rGxsbGxsbGxsYQmdjGxsYCjdAAis0IktM1qODGxsbHx8fGxsY3quHFxcUco93GxsbGxsbFxcUmotw3q+E4quE3quE3quACjtEKl9XGxsbFxcUZoNkBi883qeHGxsYAis44quEAic0AiM08rOIcnNk6q+IspN4Mk9QFj9EXmdclodzGxsbX17u1AAAAXnRSTlMA7d4ItK8KTHw//QHerC31nSgFHsszjQ5Bw23d6qMYFFmUZtVH78rkCTn4uIZUdvqAFKxPDUAEozao2iLQ5V39lLF/y+z+wd1he76y+hGNgC1uQO7BUNR6mYRR96TdoavfmwAABLhJREFUeF7s08Fqg0AQBuApCC0IBBtCYpBVbMQmNoF4CfGykV5aKKbXAn2B//0foOLspQF0xhQokO80/2l2WH66xnNx18vz6S+c0K+ha8TukQn62RWNFxzfeY2J0K96pLH2zSSf81hjwIHGevsG7nncYkhC45gDgNKdlWOA/Uo7MemsnwBkAYcGQtmcVJINWi8cZhZCR1JZWrSiKacSUkvSeEBnx2llIWQ/Vbegk8UcQ0i9asqTgJ05biF2Jrn1BJ2J0R6DKmzJGmSq371eWOgsSKK8+M4COrmoOimckHPwAR2PBPbRRQUaKKU0zK/hRHy72UDHTmmYqT1nx2tnhadz8ulfuLn5YazseRMEwjhuJDCIOhkXw8DiagchJkQGInZoHKxWk7Y5nkO09ft/gTb3Sjg4nt/4T7jf5XnhIlcR8SRzbUxaeO/XBFQCGxasd7QToLeyMBglvZZ4AUSw9VjyCcTCvTI1Z0TNciIAlydziwZ+ihZe+jUZVUekPNlbNPS3LEwQrXHVoblozdZas7KqmmU7rXstjm7N7sCSaW7TPO//yM4vOYiaJV9EADOfJUcgVoDK/ix9/NaQ5gQEQOzQh+hPOECTgdJkLPBnfRoQqzPa4DUBJZLImAD76ow9vEZP7yrhzVr11kxM2gTr0HfXgxa1t12jVucDr5mqu8MlZkkKLZbHrYao2eg7DEOkSh8Ke55c2zTPskZRI0VOgNYEMulqukl1SlAWb6s1884/GjyKDt4GKDY5UVxZEl9MjXhjTKojTjOnIKGpfNPAQNTMBLegzn4xVPBPDrNhk8XwddzOGbeg/trT+DxyPAOni/ivXfNbbRSIwvgpLCQiYIyIRmAT1hS1RCEJICmCgjdtKKmXe+ML+P4PsCmzG6Y96zczFO/yu3WGzxnPmTl/JCV37gTFXKb4m6e9zk2JQPWBp5cirfMHY1YoJOi+5MqOkHFrY5kXoLL8WsV4c4XMk6lK7QKZiI326QPPMZWJwafx+UtnojL8aCqzAFZWDYyjeJIYbdgVUIkuB04hvllsoJL4bueO79kclOFbA5mSEHkN5hwMZI4ECP9vs2fx9F1fxfGQX47YUiyc+UVfprWBSjIw5OLTVl/mAlT6QYYfA12NDDhZSLhIZRThAOuHAfBKOviJss5rx98ubGfwTQ+gZ2PSFdriY7EShrMDiyn12hmQx71wK3i1qLCjQUWmKqc6P9UyVmhhwrUYmI0NDH0C3LnjzTTZCicPjnhYh+NLNZbofyiim4IYZi2fnU733hm5ACrT0A5fbSti6AQryWm++9HXUhCRPquXzDnABWwCupJ20VlcBsq4Y0YM5aRyTzfC07+uUlcrD3KOpR01hGexI/ZI1/Nhk+cWjbBsoYqMbYm77TjWSkcpU24cnKYJCDMNl7NKaZR3YO8oA+T0Hu6EcnbqLi3D8YmDTyg2Qz3raUYQ7/NynLZtFzYpKT7vW50TgAdSDWkye5Z9bEMq1rKxvfmkS9DcwsEqIzUROC4BNrmXjxOyjn8FpEHagn9PMEEXht2S9NiyvGwaSmYAEyD9N3Zumma6BdkbyXH2NB2nm8xvmpB9L1WOJiRzWHI+CRHLbafh0l+p1Hb2B2WwRgDiX0fTAAAAAElFTkSuQmCC"},{"id":"PNOA-Spain-TMS","name":"PNOA Spain","type":"tms","template":"http://www.ign.es/wmts/pnoa-ma?request=GetTile&service=WMTS&VERSION=1.0.0&Layer=OI.OrthoimageCoverage&Style=default&Format=image/png&TileMatrixSet=GoogleMapsCompatible&TileMatrix={zoom}&TileRow={y}&TileCol={x}","polygon":[[[-17.8846298,28.4460601],[-17.8939535,28.5225529],[-18.0212548,28.7481927],[-18.0224091,28.8038375],[-17.9424017,28.8726124],[-17.8911792,28.8737099],[-17.8903302,28.8515102],[-17.7675902,28.8537764],[-17.7669837,28.8312183],[-17.7412714,28.8319975],[-17.7394926,28.7642235],[-17.7139824,28.7649677],[-17.7129312,28.7303731],[-17.7574427,28.6931782],[-17.7570788,28.6741254],[-17.7457913,28.6743524],[-17.7457266,28.6165627],[-17.7519687,28.5833675],[-17.7622536,28.5591958],[-17.7833086,28.541667],[-17.7831575,28.4936643],[-17.808611,28.4925024],[-17.8060072,28.4468974],[-17.8846298,28.4460601]],[[-18.1661033,27.7851643],[-18.163494,27.6949247],[-18.0889827,27.6963366],[-18.0873398,27.6738724],[-18.0364092,27.6753701],[-18.0350079,27.6302571],[-17.9589987,27.6323976],[-17.8603269,27.7926025],[-17.8630328,27.8368793],[-17.8884015,27.8364947],[-17.8891263,27.8590536],[-17.9906491,27.8567467],[-18.0386803,27.7655831],[-18.1146412,27.7637873],[-18.1154627,27.7863613],[-18.1661033,27.7851643]],[[-17.36038,28.0639801],[-17.3629657,28.1757247],[-17.3375583,28.1763688],[-17.3384577,28.2213012],[-17.1857883,28.2238767],[-17.0820788,28.1351849],[-17.0808422,28.0679977],[-17.1315446,28.0668073],[-17.1563337,28.0214628],[-17.2321063,28.0203711],[-17.2319938,27.9980388],[-17.2576823,27.9978403],[-17.257851,28.0199741],[-17.3086658,28.0192298],[-17.36038,28.0639801]],[[-16.9278171,28.3275779],[-16.9286591,28.3721879],[-16.8776666,28.3729288],[-16.8780707,28.3954191],[-16.5214259,28.4226146],[-16.4457117,28.491135],[-16.4462506,28.535972],[-16.4205859,28.5362679],[-16.4209227,28.5588419],[-16.3443329,28.5597589],[-16.3446023,28.5822095],[-16.1912541,28.5837179],[-16.1916246,28.6068435],[-16.1279344,28.6078193],[-16.1277997,28.5921762],[-16.0995079,28.5925015],[-16.0993395,28.5163822],[-16.1648148,28.5161158],[-16.1647474,28.4938583],[-16.2385755,28.4484704],[-16.2653516,28.4476116],[-16.2658569,28.4030038],[-16.3167484,28.4017594],[-16.3163105,28.380189],[-16.3420763,28.3795075],[-16.3408301,28.2892963],[-16.415837,28.1976134],[-16.415096,28.1311312],[-16.5153297,28.0164796],[-16.6168433,28.01532],[-16.6168096,27.9930469],[-16.7184243,27.9919168],[-16.7190979,28.0371426],[-16.7446952,28.0367859],[-16.7453351,28.0818146],[-16.7706967,28.0816065],[-16.8223966,28.1259036],[-16.8231712,28.1708652],[-16.8487012,28.1707464],[-16.8502842,28.260791],[-16.8756457,28.2605537],[-16.8760836,28.2832162],[-16.9015125,28.2827713],[-16.9023882,28.3279337],[-16.9278171,28.3275779]],[[-15.8537427,27.9008901],[-15.8542032,27.9901812],[-15.828953,27.9906555],[-15.8291065,28.035578],[-15.7782992,28.0363232],[-15.7532793,28.0814298],[-15.7278756,28.0815652],[-15.7282593,28.1718567],[-15.4989741,28.1728039],[-15.4987438,28.1504075],[-15.4497785,28.1507459],[-15.4501622,28.1961425],[-15.3972827,28.1961425],[-15.3964385,28.0383554],[-15.3710348,28.0380167],[-15.3706511,28.0153212],[-15.3457847,28.0153212],[-15.3454777,27.9254406],[-15.3708046,27.9252372],[-15.3705743,27.8352137],[-15.395978,27.8347387],[-15.4209979,27.7879673],[-15.4718052,27.7893932],[-15.471882,27.7666454],[-15.522766,27.7667813],[-15.5477092,27.7216112],[-15.6236132,27.7213395],[-15.6241504,27.741991],[-15.7007451,27.7433495],[-15.801669,27.8110501],[-15.8537427,27.9008901]],[[-14.5215621,28.0467778],[-14.5224358,28.1184131],[-14.4157526,28.1156076],[-14.2168794,28.2278805],[-14.2153651,28.33903],[-14.1641672,28.4528287],[-14.1115132,28.4747955],[-14.0335806,28.7226671],[-13.9565217,28.7449351],[-13.9561722,28.7665857],[-13.8290221,28.7664325],[-13.8289639,28.7879765],[-13.8000741,28.7879255],[-13.8012972,28.7189894],[-13.827566,28.719347],[-13.8278572,28.6517968],[-13.8025786,28.651899],[-13.8033941,28.5384172],[-13.8288474,28.5384684],[-13.8315061,28.3970177],[-13.9158189,28.2241438],[-13.9856445,28.2235696],[-14.0369588,28.1795787],[-14.1387139,28.1799894],[-14.1386556,28.1579103],[-14.2153651,28.1578076],[-14.2147244,28.1118888],[-14.2913173,28.0452356],[-14.3319673,28.0368713],[-14.4457846,28.0469834],[-14.4466583,28.0657961],[-14.4962835,28.0682631],[-14.495934,28.0458525],[-14.5215621,28.0467778]],[[-13.800662,28.8456579],[-13.8009273,28.8231121],[-13.775688,28.8230539],[-13.69729,28.8898184],[-13.69729,28.9127744],[-13.6072498,28.9117991],[-13.4388551,29.0002417],[-13.4374559,29.1351289],[-13.4117005,29.1349931],[-13.4105556,29.2229789],[-13.4592801,29.255586],[-13.4597392,29.2942023],[-13.5091254,29.2945638],[-13.5100581,29.3163453],[-13.5635382,29.3172941],[-13.5640564,29.2713764],[-13.5389228,29.2711956],[-13.5389747,29.2500375],[-13.5661293,29.2501279],[-13.5665956,29.2030039],[-13.5156549,29.2022349],[-13.5156549,29.1820579],[-13.5398038,29.1827819],[-13.5408921,29.137528],[-13.65782,29.1368528],[-13.713222,29.0935079],[-13.7663353,29.0934533],[-13.8502463,29.0165937],[-13.8518224,28.983425],[-13.8524443,28.914861],[-13.9013122,28.89245],[-13.9024005,28.8469779],[-13.800662,28.8456579]],[[1.6479916,38.9990693],[1.7321668,38.9993635],[1.7314703,39.0441733],[1.6489512,39.0431944],[1.6481552,39.1276358],[1.3948608,39.1265691],[1.3954412,39.0864199],[1.2281145,39.0852615],[1.2291095,39.0028958],[1.1448657,39.0018003],[1.1452803,38.8319988],[1.3113632,38.8331615],[1.3121924,38.7906483],[1.3946949,38.7916178],[1.3951924,38.7529597],[1.3112803,38.7519251],[1.3125919,38.6238804],[1.6489036,38.6251112],[1.6480745,38.7111504],[1.58456,38.7101152],[1.5811604,38.7005387],[1.5491544,38.7002798],[1.5197188,38.7092094],[1.50355,38.7253185],[1.4813282,38.9155064],[1.5518906,38.9254411],[1.5667328,38.9566554],[1.6487378,38.9583318],[1.6479916,38.9990693]],[[2.5450749,39.4166673],[2.43933,39.4161122],[2.438714,39.4846853],[2.439022,39.4993424],[2.3122308,39.4993424],[2.3119228,39.5417911],[2.2290722,39.5409994],[2.2283536,39.6260571],[2.3460076,39.6270851],[2.9270445,39.9601558],[3.1456647,39.9600498],[3.1460753,40.0019797],[3.2313899,40.0019797],[3.2312872,39.8329231],[3.1482313,39.8331596],[3.1484366,39.7935717],[3.4814817,39.7931773],[3.4803472,39.5959027],[3.3150618,39.4784606],[3.3146179,39.3785504],[3.0830178,39.2499355],[2.9798608,39.2501482],[2.9790395,39.3334971],[2.7287424,39.3334177],[2.7288451,39.4581361],[2.6456865,39.4577397],[2.6453785,39.4996593],[2.5452802,39.4994216],[2.5450749,39.4166673]],[[3.8120402,40.0434431],[3.729082,40.0437979],[3.7286185,39.9584155],[3.8126633,39.9576011],[3.8122771,39.9164393],[3.9608975,39.9159813],[4.1938142,39.791308],[4.3150279,39.7905799],[4.3159934,39.8329294],[4.3987393,39.8320396],[4.3973664,39.9185834],[4.3158003,39.9193274],[4.3161865,40.0433985],[4.2318959,40.0443594],[4.2324752,40.0847793],[4.1491501,40.086109],[4.1490623,40.1255157],[4.0627981,40.1272166],[4.0624217,40.0849941],[3.8128687,40.085294],[3.8120402,40.0434431]],[[-8.8910646,41.8228891],[-9.1092038,42.5751065],[-9.0365469,42.730656],[-9.0883419,42.7269569],[-9.1466113,42.7750272],[-9.2185488,42.9016271],[-9.2760988,42.8605106],[-9.3099094,42.9311297],[-9.2789763,42.9821991],[-9.3099094,43.0600377],[-9.2523594,43.1041725],[-9.2314975,43.1703151],[-9.1473307,43.210176],[-9.06748,43.1991644],[-9.0336694,43.2426748],[-8.99842,43.2447709],[-8.9998588,43.2955793],[-8.9372732,43.3055265],[-8.92936,43.326986],[-8.8638969,43.3290792],[-8.8761263,43.3740655],[-8.8221732,43.3735426],[-8.785485,43.3191358],[-8.7063538,43.305003],[-8.6099575,43.3296025],[-8.5509688,43.3233227],[-8.5243519,43.3364048],[-8.5250713,43.3646525],[-8.45745,43.3918416],[-8.3610538,43.4111803],[-8.3603344,43.4634161],[-8.3344369,43.5797394],[-8.2776063,43.5708796],[-8.0646713,43.7239184],[-7.9992081,43.7233986],[-7.9171994,43.7826357],[-7.8560525,43.7914643],[-7.83591,43.7374337],[-7.6628443,43.809819],[-7.3188932,43.6782695],[-7.1997467,43.5830817],[-6.2488228,43.6075032],[-6.1229322,43.5790105],[-5.8520425,43.6798953],[-5.6036334,43.5708672],[-5.2855347,43.5619084],[-5.1787525,43.4991591],[-4.9089869,43.4836655],[-4.6156167,43.4192021],[-4.1839917,43.4249168],[-3.8029478,43.5195394],[-3.7400025,43.4869277],[-3.5612827,43.5423572],[-3.1083013,43.3816347],[-2.9385737,43.4624573],[-2.7452417,43.4755094],[-2.3046245,43.3170625],[-1.9854018,43.3563045],[-1.8552841,43.3972545],[-1.769802,43.3964383],[-1.7700492,43.3760501],[-1.7100474,43.3756908],[-1.7113451,43.3312527],[-1.7225915,43.3131806],[-1.6890375,43.3129108],[-1.6881106,43.3341294],[-1.6446695,43.3337248],[-1.6449785,43.3133155],[-1.6029903,43.3129528],[-1.6034352,43.2926624],[-1.5635905,43.2921227],[-1.5630468,43.3133844],[-1.4779905,43.3128355],[-1.3667723,43.2761368],[-1.3568809,43.2381533],[-1.3703692,43.1712972],[-1.4423067,43.0833554],[-1.4198262,43.0603647],[-1.3730668,43.051166],[-1.3640746,43.1115893],[-1.3020285,43.135217],[-1.2354864,43.1332484],[-1.2795481,43.0774443],[-1.1923239,43.0649635],[-1.0061856,43.0077821],[-0.942341,42.9748951],[-0.7562028,42.9821318],[-0.7148387,42.9610774],[-0.6968543,42.9031405],[-0.5511809,42.8220693],[-0.5044215,42.8484456],[-0.4288871,42.8200906],[-0.3164848,42.8655842],[-0.1456332,42.810856],[-0.0314324,42.7124874],[0.1861785,42.7540985],[0.3021777,42.7177729],[0.3642238,42.7428729],[0.4487504,42.7144695],[0.6276949,42.7223973],[0.6411832,42.8576747],[0.7149192,42.882718],[0.9675996,42.8181119],[1.108777,42.7989808],[1.1753192,42.7342872],[1.3632559,42.7415521],[1.4113736,42.7093914],[1.4806054,42.7103407],[1.4813006,42.5010664],[1.6443591,42.5020345],[1.6432777,42.5424539],[1.730407,42.5434214],[1.7316429,42.5011803],[2.0638621,42.5016359],[2.0645572,42.4590247],[2.3969309,42.4599364],[2.3976786,42.4178363],[2.4804823,42.4179732],[2.4809767,42.3759441],[2.6447922,42.3762636],[2.6444832,42.4592447],[2.8113266,42.4596094],[2.8112648,42.5010358],[3.063878,42.5008535],[3.063878,42.4591535],[3.2307832,42.4593359],[3.2304935,42.3764363],[3.3141469,42.3760369],[3.3141243,42.3339864],[3.397855,42.3340435],[3.3973912,42.290094],[3.3138923,42.2908368],[3.3139695,42.2070151],[3.1475896,42.2073012],[3.1475896,42.1260612],[3.2305478,42.1260039],[3.2466753,41.9529359],[3.1945206,41.8558943],[3.060537,41.7647419],[2.7835777,41.6371796],[2.26293,41.4271601],[2.1649151,41.2989297],[1.86008,41.2232228],[1.3763003,41.116273],[1.1793714,41.0464585],[1.0858526,41.048493],[0.758537,40.8195599],[0.9114042,40.733761],[0.8781331,40.6751363],[0.6650182,40.5358666],[0.5580112,40.5502166],[0.433919,40.3757589],[0.2675635,40.1919192],[0.1641534,40.0647234],[0.0751307,40.0144671],[0.010387,39.8952188],[-0.0939224,39.8116904],[-0.1847435,39.6311716],[-0.2908513,39.5036254],[-0.2863552,39.333431],[-0.1856427,39.1774612],[-0.2135185,39.1558487],[-0.1110076,38.9722246],[0.0094878,38.8826835],[0.1218901,38.872183],[0.2342925,38.798636],[0.2558737,38.7264162],[0.0958128,38.6133825],[-0.0022021,38.6070586],[-0.0570544,38.5269073],[-0.2719677,38.4762395],[-0.379874,38.3931234],[-0.3834708,38.3381297],[-0.4509122,38.3310763],[-0.5048654,38.2830943],[-0.4823849,38.1948095],[-0.429331,38.1658287],[-0.4545091,38.148859],[-0.5839966,38.1721913],[-0.6136708,38.1198599],[-0.6370505,37.9612228],[-0.6811123,37.9456238],[-0.7323677,37.8810656],[-0.7215771,37.7830562],[-0.688306,37.7340026],[-0.6641461,37.6231485],[-0.7193941,37.5878413],[-0.9196258,37.5375806],[-1.1107098,37.5164093],[-1.3383246,37.5286671],[-1.4408917,37.3903714],[-1.6766966,37.2765189],[-1.8540816,36.9122889],[-2.0683486,36.6929117],[-2.2158766,36.6619233],[-2.3721861,36.7801753],[-2.6812926,36.6591056],[-2.9201476,36.6675585],[-3.09402,36.712625],[-3.4610839,36.6548788],[-3.7280395,36.6929117],[-4.3743529,36.6633322],[-4.6571151,36.4404171],[-4.9188018,36.4531321],[-5.1699508,36.3513541],[-5.2841094,36.1970201],[-5.2680911,36.1241812],[-5.3524784,36.1224654],[-5.3516094,36.0401413],[-5.4365759,36.0388921],[-5.4353207,36.0034384],[-5.6888562,36.0036518],[-5.6899635,36.0405317],[-5.85506,36.0385595],[-5.8566821,36.1242077],[-5.9384817,36.1221487],[-5.9400265,36.1655625],[-5.9983445,36.1645024],[-6.0357297,36.1780957],[-6.0775178,36.2224132],[-6.1506113,36.2864561],[-6.231541,36.3770075],[-6.3358504,36.5310643],[-6.3214629,36.5816265],[-6.404191,36.6234958],[-6.4743301,36.7489673],[-6.4158808,36.7993866],[-6.490516,36.9173818],[-6.6298949,37.0194012],[-6.8744824,37.1083766],[-7.0426363,37.1850699],[-7.2647434,37.1843535],[-7.3753473,37.1535419],[-7.408316,37.1682196],[-7.4202886,37.2118318],[-7.4249231,37.2350505],[-7.4380543,37.2451969],[-7.4459717,37.3326142],[-7.4480958,37.3909382],[-7.4696271,37.4075829],[-7.4647029,37.4530494],[-7.5019723,37.516411],[-7.5191587,37.5229203],[-7.5219588,37.5723727],[-7.4501271,37.6695835],[-7.4249019,37.7599222],[-7.316662,37.839974],[-7.268329,37.988952],[-7.1536786,38.0155235],[-7.1177098,38.0553626],[-7.0142997,38.0243785],[-6.9963153,38.1075633],[-6.9614706,38.201254],[-7.080617,38.1570753],[-7.3402665,38.4402363],[-7.2638329,38.7380741],[-7.0435243,38.8729667],[-7.0615086,38.907962],[-6.9693387,39.0198308],[-7.0008114,39.0887867],[-7.1536786,39.0957658],[-7.1525545,39.1602899],[-7.2447245,39.1968854],[-7.2559647,39.2813308],[-7.3368944,39.3535074],[-7.3279022,39.4559917],[-7.5144901,39.5886496],[-7.5527069,39.6795427],[-7.0502684,39.6752171],[-6.9951913,39.8195433],[-6.9221297,39.8790868],[-6.886161,40.0229854],[-7.0412762,40.1347927],[-7.0176717,40.266146],[-6.8086034,40.3450071],[-6.8681766,40.4451649],[-6.8535643,40.6066433],[-6.837828,40.8757589],[-6.9536024,41.0370445],[-6.8018592,41.0395879],[-6.7681385,41.138706],[-6.6411239,41.2655616],[-6.5624422,41.2630269],[-6.217367,41.5791017],[-6.3162811,41.644652],[-6.5152332,41.6412921],[-6.5871707,41.6883151],[-6.5478299,41.8559743],[-6.6298836,41.9112057],[-7.1334461,41.9404756],[-7.1682909,41.8718791],[-7.4256922,41.7847727],[-7.9539833,41.8459271],[-8.130455,41.7805819],[-8.2518495,41.9078597],[-8.1293309,42.0348842],[-8.2484774,42.1008034],[-8.3676239,42.0557521],[-8.6070409,42.0340493],[-8.8910646,41.8228891]]],"terms_text":"PNOA","best":true},{"id":"Geodatastyrelsen_Denmark","name":"SDFE aerial imagery","type":"tms","template":"http://osmtools.septima.dk/mapproxy/tiles/1.0.0/kortforsyningen_ortoforaar/EPSG3857/{zoom}/{x}/{y}.jpeg","scaleExtent":[0,21],"polygon":[[[8.3743941,54.9551655],[8.3683809,55.4042149],[8.2103997,55.4039795],[8.2087314,55.4937345],[8.0502655,55.4924731],[8.0185123,56.7501399],[8.1819161,56.7509948],[8.1763274,57.0208898],[8.3413329,57.0219872],[8.3392467,57.1119574],[8.5054433,57.1123212],[8.5033923,57.2020499],[9.3316304,57.2027636],[9.3319079,57.2924835],[9.4978864,57.2919578],[9.4988593,57.3820608],[9.6649749,57.3811615],[9.6687295,57.5605591],[9.8351961,57.5596265],[9.8374896,57.6493322],[10.1725726,57.6462818],[10.1754245,57.7367768],[10.5118282,57.7330269],[10.5152095,57.8228945],[10.6834853,57.8207722],[10.6751613,57.6412021],[10.5077045,57.6433097],[10.5039992,57.5535088],[10.671038,57.5514113],[10.6507805,57.1024538],[10.4857673,57.1045138],[10.4786236,56.9249051],[10.3143981,56.9267573],[10.3112341,56.8369269],[10.4750295,56.83509],[10.4649016,56.5656681],[10.9524239,56.5589761],[10.9479249,56.4692243],[11.1099335,56.4664675],[11.1052639,56.376833],[10.9429901,56.3795284],[10.9341235,56.1994768],[10.7719685,56.2020244],[10.7694751,56.1120103],[10.6079695,56.1150259],[10.4466742,56.116717],[10.2865948,56.118675],[10.2831527,56.0281851],[10.4439274,56.0270388],[10.4417713,55.7579243],[10.4334961,55.6693533],[10.743814,55.6646861],[10.743814,55.5712253],[10.8969041,55.5712253],[10.9051793,55.3953852],[11.0613726,55.3812841],[11.0593038,55.1124061],[11.0458567,55.0318621],[11.2030844,55.0247474],[11.2030844,55.117139],[11.0593038,55.1124061],[11.0613726,55.3812841],[11.0789572,55.5712253],[10.8969041,55.5712253],[10.9258671,55.6670198],[10.743814,55.6646861],[10.7562267,55.7579243],[10.4417713,55.7579243],[10.4439274,56.0270388],[10.4466742,56.116717],[10.6079695,56.1150259],[10.6052053,56.0247462],[10.9258671,56.0201215],[10.9197132,55.9309388],[11.0802782,55.92792],[11.0858066,56.0178284],[11.7265047,56.005058],[11.7319981,56.0952142],[12.0540333,56.0871256],[12.0608477,56.1762576],[12.7023469,56.1594405],[12.6611131,55.7114318],[12.9792318,55.7014026],[12.9612912,55.5217294],[12.3268659,55.5412096],[12.3206071,55.4513655],[12.4778226,55.447067],[12.4702432,55.3570479],[12.6269738,55.3523837],[12.6200898,55.2632576],[12.4627339,55.26722],[12.4552949,55.1778223],[12.2987046,55.1822303],[12.2897344,55.0923641],[12.6048608,55.0832904],[12.5872011,54.9036285],[12.2766618,54.9119031],[12.2610181,54.7331602],[12.1070691,54.7378161],[12.0858621,54.4681655],[11.7794953,54.4753579],[11.7837381,54.5654783],[11.1658525,54.5782155],[11.1706443,54.6686508],[10.8617173,54.6733956],[10.8651245,54.7634667],[10.7713646,54.7643888],[10.7707276,54.7372807],[10.7551428,54.7375776],[10.7544039,54.7195666],[10.7389074,54.7197588],[10.7384368,54.7108482],[10.7074486,54.7113045],[10.7041094,54.6756741],[10.5510973,54.6781698],[10.5547184,54.7670245],[10.2423994,54.7705935],[10.2459845,54.8604673],[10.0902268,54.8622134],[10.0873731,54.7723851],[9.1555798,54.7769557],[9.1562752,54.8675369],[8.5321973,54.8663765],[8.531432,54.95516],[8.3743941,54.9551655]],[[11.4577738,56.819554],[11.7849181,56.8127385],[11.7716715,56.6332796],[11.4459621,56.6401087],[11.4577738,56.819554]],[[11.3274736,57.3612962],[11.3161808,57.1818004],[11.1508692,57.1847276],[11.1456628,57.094962],[10.8157703,57.1001693],[10.8290599,57.3695272],[11.3274736,57.3612962]],[[11.5843266,56.2777928],[11.5782882,56.1880397],[11.7392309,56.1845765],[11.7456428,56.2743186],[11.5843266,56.2777928]],[[14.6825922,55.3639405],[14.8395247,55.3565231],[14.8263755,55.2671261],[15.1393406,55.2517359],[15.1532015,55.3410836],[15.309925,55.3330556],[15.295719,55.2437356],[15.1393406,55.2517359],[15.1255631,55.1623802],[15.2815819,55.1544167],[15.2535578,54.9757646],[14.6317464,55.0062496],[14.6825922,55.3639405]]],"terms_url":"http://download.kortforsyningen.dk/content/vilkaar-og-betingelser","terms_text":"Geodatastyrelsen og Danske Kommuner","best":true,"icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAABGlBMVEX///+y4OQAAAAKCgrL6ezI6exHs8AdorE/sL0FBQX+/v78/v4RERH5/PzS7fC64+chpLLt+Pm95Og+Pj4mprQYGBgAkaLM6u3D5+oAlabc8fMVn671+/wAjp/Y7/EmJiY4ODg4rbsgICBgYGBLtcHk5OT29vYyMjJqamoNnKtISEhYu8aamppMTEzy+vpycnLg8/S/5emjo6NSUlJfvsgsLCzs7Oxsw81NtsKsrKyu3uPo9vd+ytODzdXk9PaEhISBgYFVVVWe193P7O95yNGPj4/x8fGk2uB7e3vd3d3Hx8cuqbfW1tZnwctRuMOxsbG7u7vQ0NB2dnYAl6dzxs+14eWW1NtRUVGZ1dxwxc6r3eKx3+ON0NiR0tk4C4avAAAG00lEQVR4XtzY5Y4qSxQF4JVqV9zdXcfd3Y/Lve//GrcDdTPQyjDnNMl8PyBAUnuxa1c3Ae8S3l9fP/+KFVG24rm4IZfraFiBRCqX+jyRiscD8F1yUp5K5Xbhs36K1qcJ4ofwVzVuChCFr4a0/swmJOCn/dxnk/g6/FSKmwOkovBTMGUJ0FLgI8EmgAYfRa0BMvBTxzIDcRF+2s1ZjuE3+KplDvBZw58la5rbklfzLUjlDuAim8Ub7ekJlmXP8n04qc7fjEpwFF4v3d2Vtk/fEKJ/xrETHKfDiThJQOvfwUmilBGCBiETXHhKQkmWTUwZETQ4OMjFUxPx3BacfGsFo1Qw87hw/cQrllPgQD5v5eLxXOvBubmnreiMxRIoHK1PcTpcpNMynOUz0TmZf+AtzSXmsFwfy3oUonOCQe+1ZLr/r7g8lpTORE0yP+Clz5kDsAkZy/lhCSDw8HLIJUxYTsNyHoSoSfDOc62hJcDyQ9ARombB0FsCUFz2jwUIRvvwELLpgILlbNlsgedaWesQ6ljSlXUIH+FJtxzDIZYUEoLmY3gFTyFTC1hWwbIeMuYRgDc5z81PwB6Wppla0PqKRZxx7Ez9NN5Bb80maJ1jMTrHsrT93CHe5UwQopSQOcCiQmfclN7HO2XXhYwgBIVMRkzgDbKHw/xwT8MfsHe6zvOdgzw+posCVmsgYbU+MVitJsFqvXSxMkexQrkJ3BpPG1iFcXutdwHct9e+V7AyzxWs1oBgta4ZrNRLhBljhS7IRoREsDI3ZADckmv4bKfSUNWNyhhjBoZKEbefIjG13Lu4hA+eGMJE1tYiDJEaMRia5RiRCmvf2zFCfDiUR6TwTAewwkhHwIvKFHcwUTshDSxNUWR4e5mduVqEFNtSbAcU0CUDLEDLmmuFdC45SnJpBR6+q3XMOJbU4tzGn0h1eEiedx63O1u7M7X6XCA8EQjn4S7WxCy5wpg79ARXXEfk+WqV58Xqb1B7RvnRVDiQhLNuQ2We3K+E9bJaHtzA0Y8SX92eqor7tP0BWt49gVyLkUJFevb4RdRo9Ai5gIOrEi0/k0Ax6s8K6LBVV9VbbBKPAFpsALlHdmBrSOtT1dJvAHpgNO+rAjvH5B64JEeuAeQa6QJolGFrnd+eU+UB0Aa8CuRhZ6MNQ6Po3oExuZk83sNGurRtIo6wFxiZhEf2O3A97UPNNUCkAEONjGHjVDQH4A8wtAYIKLC6ZI5hqElNtwD30/nblGwDfOHNAaod5MPWAFlY1WMDGFAhdZcAJ6oGw4391aBjDVBdOADaZUxbUHEO8EIP4LW06TmDNIDtFsDODj2BTVJzDFCIYULtwc6+NcA6+tYASdgqTFugqUWnAGM6e8fkFnaurEP4LxC2HMM0bD2RI1qmax+gzkyjbZIebGXpdehVSQfSAfMOyLAXoc0vMpu2AXpk+n6Dfm51zpsa8AjDKDxffwgHdWmDfsOIXYAx7dAx6cJBVjRdinUYtPmbkQ5Hz/QnV5dcWANsMg16EtpwlKA3Q1r/F801+j9COBzIw0WTfrk2ubcEKDKXMFyqMbhI8CJNUOXFX6DkfDgQNgQCyRBcRabzXY+VzQEG9A7YkG7gpr8virxBFB+GeKUd6mwike7DQ72sTta/ldrzf9HskCYMWKM5XIR2z3/+/HI1xFLqtemEX9boazrwm9NnhX78gR2XN1wVIgr+qqONoqtGW8bHdh0ruCoXZfxV3d6Jq7WKjI+tSRhXUlnBX7XTHLi7/q89u1txFIbiAH6EzZV0xd6shNJHKM1VIFoBd6BXuYshn+//GluWma5qN1od4sD09wDJnyTnHEF45OXl5eXp/nw6IkIQPsAn2BX+8nZxWf7E9oUx7MYwlMJaieZUa005b+Yuhg2zyV+WsRzWqbgW76iYt9jR2OSOmXUJ3qj4h9ITTMuNTTos28FynosuWsG0liU9rIDFzlz08T1MqY1NeixbXguSij5dwRTEkgGDYaGd0GKAlzAhux/A+jsouRjiCMLSdhxgDwsdHwQgXz0APAhAYl4BEDYK8DPqI8SjMlzRC9WCMkztIADLPrMRkTmjyA4PYLlmQSuGopvAmt+BsY1Y0zAUSlj1h9EBZib4GMeh/U/GeXnj3TUQ4XIfx5rrA8yDrWH2hpmkhv85OqneSRcolPbjg4Q2MFuKSXtTnCGwv+pwvwLFiNSlqnyWw1PS8K/c3EvV5UqIy0jVI68QVe7VgK8hJjQOkEFMTCq16R1cxwGa9FsFMFtfAfGjAC3EVI6rAMOmr1A2EFfpVI/DEBnqDyMC0f3ojuMCNlArJ6VSUjqJYRs1MUpd92dY4Q9//EnbIq9ZogAAAABJRU5ErkJggg=="},{"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","startDate":"2017-03-01T00:00:00.000Z","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-Orthofoto-2014-2015","name":"South Tyrol Orthofoto 2014/2015","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_2015_EPSG3857&STYLE=default&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX=GoogleMapsCompatible%3A{zoom}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg","endDate":"2015-11-01T00:00:00.000Z","startDate":"2014-07-01T00:00:00.000Z","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 4.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","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","description":"Topographical basemap of South Tyrol"},{"id":"Bern-bern2016-tms","name":"Stadt Bern 10cm (2016)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/bern2016/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,21],"polygon":[[[7.2943145,46.9237564],[7.2982665,46.9274715],[7.3061586,46.9309487],[7.3043338,46.9362344],[7.3068603,46.9403709],[7.3246431,46.9432765],[7.3284525,46.946409],[7.3414051,46.9460797],[7.3438454,46.9473713],[7.3434554,46.9487937],[7.3513567,46.9485481],[7.3505628,46.950213],[7.3530901,46.9519266],[7.3582028,46.9511773],[7.3685031,46.9566244],[7.3715097,46.9607339],[7.37503,46.959835],[7.3785111,46.9614686],[7.3806232,46.9654741],[7.3832097,46.9663014],[7.3937998,46.9669268],[7.4000528,46.9691779],[7.4082922,46.9686857],[7.4281713,46.9738041],[7.4327053,46.972689],[7.4353602,46.9684345],[7.4378522,46.9684302],[7.4412474,46.9767865],[7.4456893,46.9747939],[7.4483835,46.9756393],[7.4477006,46.9790125],[7.4440468,46.9780682],[7.4412738,46.9798224],[7.4506732,46.9901527],[7.4522112,46.9896803],[7.454649,46.9778182],[7.4680382,46.9758258],[7.4707923,46.969998],[7.4701907,46.9674116],[7.4781618,46.9711823],[7.4845237,46.9701571],[7.4861275,46.9679018],[7.4857945,46.9646828],[7.4784708,46.9629043],[7.4802865,46.9606768],[7.4789304,46.9587841],[7.4797786,46.9566019],[7.4770135,46.9544586],[7.4840504,46.9499938],[7.4833925,46.9451977],[7.4955563,46.9396169],[7.4935119,46.9376594],[7.4908036,46.9387617],[7.4894997,46.9368667],[7.4766667,46.9369496],[7.4781093,46.9362489],[7.4746986,46.9339187],[7.4753537,46.9329898],[7.4691047,46.9292427],[7.4707683,46.9255044],[7.4585674,46.934836],[7.4476373,46.9304297],[7.435418,46.9349668],[7.4338022,46.9331237],[7.4376403,46.9307415],[7.4146941,46.9368183],[7.413844,46.9315682],[7.4070798,46.9303824],[7.408065,46.9256296],[7.4021268,46.9241992],[7.4014835,46.9211927],[7.3875736,46.9304506],[7.3823129,46.927282],[7.3800187,46.9298929],[7.3808694,46.9324085],[7.3748669,46.9314306],[7.3748901,46.9327104],[7.368066,46.9323929],[7.3683058,46.930426],[7.3604074,46.9285884],[7.3605592,46.9272018],[7.338783,46.9245357],[7.3393683,46.9196675],[7.3274574,46.9190326],[7.3269178,46.9235974],[7.324374,46.9251891],[7.3082264,46.9222857],[7.2943145,46.9237564]]],"terms_text":"Orthophoto 2016, Vermessungsamt Stadt Bern ","best":true},{"id":"Uster-2008","name":"Stadt Uster Orthophoto 2008 10cm","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/uster/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","polygon":[[[8.6,47.31],[8.6,47.39],[8.77,47.39],[8.77,47.31],[8.6,47.31]]],"terms_text":"Stadt Uster Vermessung Orthophoto 2008"},{"id":"Zuerich-zh_luftbild2011-tms","name":"Stadt Zürich Luftbild 2011","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/zh_luftbild2011/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","polygon":[[[8.4441,47.3141],[8.4441,47.4411],[8.6284,47.4411],[8.6284,47.3141],[8.4441,47.3141]]],"terms_text":"Stadt Zürich Luftbild 2011"},{"id":"Zuerich-city_map","name":"Stadtplan Zürich","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/zh_stadtplan/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","polygon":[[[8.4482,47.321],[8.4482,47.4339],[8.6248,47.4339],[8.6248,47.321],[8.4482,47.321]]],"terms_text":"Stadt Zürich Open Government Data"},{"id":"stamen-terrain-background","name":"Stamen Terrain","type":"tms","template":"http://{switch:a,b,c,d}.tile.stamen.com/terrain-background/{zoom}/{x}/{y}.jpg","scaleExtent":[4,18],"terms_url":"http://maps.stamen.com/#terrain","terms_text":"Map tiles by Stamen Design, under CC BY 3.0"},{"id":"Stevns_Denmark","name":"Stevns","type":"tms","template":"http://{switch:a,b,c}.tile.openstreetmap.dk/stevns/2009/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[12.0913942,55.3491574],[12.0943104,55.3842256],[12.1573875,55.3833103],[12.1587287,55.4013326],[12.1903468,55.400558],[12.1931411,55.4364665],[12.2564251,55.4347995],[12.2547073,55.4168882],[12.3822489,55.4134349],[12.3795942,55.3954143],[12.4109213,55.3946958],[12.409403,55.3766417],[12.4407807,55.375779],[12.4394142,55.3578314],[12.4707413,55.3569971],[12.4629475,55.2672214],[12.4315633,55.2681491],[12.430045,55.2502103],[12.3672011,55.2519673],[12.3656858,55.2340267],[12.2714604,55.2366031],[12.2744467,55.272476],[12.2115654,55.2741475],[12.2130078,55.2920322],[12.1815665,55.2928638],[12.183141,55.3107091],[12.2144897,55.3100981],[12.2159927,55.3279764],[12.1214458,55.3303379],[12.1229489,55.3483291],[12.0913942,55.3491574]]],"terms_text":"Stevns Kommune"},{"id":"Surrey-Air_Survey","name":"Surrey Air Survey","type":"tms","template":"http://gravitystorm.dev.openstreetmap.org/surrey/{zoom}/{x}/{y}.png","endDate":"2009-01-01T00:00:00.000Z","startDate":"2007-01-01T00:00:00.000Z","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}","startDate":"2012-01-01T00:00:00.000Z","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","endDate":"2010-07-20T00:00:00.000Z","startDate":"2013-07-19T00:00:00.000Z","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","icon":"https://www.geoportail.lu/static/img/lion.png"},{"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}","endDate":"2011-01-01T00:00:00.000Z","startDate":"2008-01-01T00:00:00.000Z","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}","endDate":"2013-01-01T00:00:00.000Z","startDate":"2013-01-01T00:00:00.000Z","scaleExtent":[0,22],"polygon":[[[0.427093505859375,47.26199018174824],[0.427093505859375,47.50096732311069],[0.814361572265625,47.50096732311069],[0.814361572265625,47.26199018174824],[0.427093505859375,47.26199018174824]]],"terms_url":"http://wiki.openstreetmap.org/wiki/Tours/Orthophoto","terms_text":"Orthophoto Tour(s)plus 2013"},{"id":"US_Forest_Service_roads","name":"U.S. Forest Service roads","type":"tms","template":"https://osm.cycle.travel/forest/{zoom}/{x}/{y}.png","scaleExtent":[0,19],"polygon":[[[-124.7617886,48.4130148],[-124.6059492,45.90245],[-124.9934269,40.0557614],[-122.5369737,36.8566086],[-119.9775867,33.0064099],[-117.675935,32.4630223],[-114.8612307,32.4799891],[-111.0089311,31.336015],[-108.1992687,31.3260016],[-108.1871123,31.7755116],[-106.5307225,31.7820947],[-106.4842052,31.7464455],[-106.429317,31.7520583],[-106.2868855,31.5613291],[-106.205248,31.446704],[-105.0205259,30.5360988],[-104.5881916,29.6997856],[-103.2518856,28.8908685],[-102.7173632,29.3920567],[-102.1513983,29.7475702],[-101.2552871,29.4810523],[-100.0062436,28.0082173],[-99.2351068,26.4475962],[-98.0109067,25.9928035],[-97.435024,25.8266009],[-96.9555259,25.9821589],[-96.8061741,27.7978168],[-95.5563349,28.5876066],[-93.7405308,29.4742093],[-90.9028456,28.8564513],[-88.0156706,28.9944338],[-88.0162494,30.0038862],[-86.0277506,30.0047454],[-84.0187909,28.9961781],[-81.9971976,25.9826768],[-81.9966618,25.0134917],[-84.0165592,25.0125783],[-84.0160068,24.0052745],[-80.0199985,24.007096],[-79.8901116,26.8550713],[-80.0245309,32.0161282],[-75.4147385,35.0531894],[-74.0211163,39.5727927],[-72.002019,40.9912464],[-69.8797398,40.9920457],[-69.8489304,43.2619916],[-66.9452845,44.7104937],[-67.7596632,47.0990024],[-69.2505131,47.5122328],[-70.4614886,46.2176574],[-71.412273,45.254878],[-72.0222508,45.0059846],[-75.0798841,44.9802854],[-76.9023061,43.8024568],[-78.7623935,43.6249578],[-79.15798,43.4462589],[-79.0060087,42.8005317],[-82.662475,41.6889458],[-82.1761642,43.588535],[-83.2813977,46.138853],[-87.5064535,48.0142702],[-88.3492194,48.2963271],[-89.4353148,47.9837822],[-93.9981078,49.0067142],[-95.1105379,49.412004],[-96.0131199,49.0060547],[-123.3228926,49.0042878],[-123.2275233,48.1849927],[-124.7617886,48.4130148]],[[-160.5787616,22.5062947],[-160.5782192,21.4984647],[-158.7470604,21.2439843],[-157.5083185,20.995803],[-155.9961942,18.7790194],[-154.6217803,18.7586966],[-154.6890176,19.8805722],[-156.2927622,21.2225888],[-157.5047384,21.9984962],[-159.0093692,22.5070181],[-160.5787616,22.5062947]],[[-167.1571546,68.721974],[-164.8553982,67.0255078],[-168.002195,66.0017503],[-169.0087448,66.001546],[-169.0075381,64.9987675],[-172.5143281,63.8767267],[-173.8197023,59.74014],[-162.5018149,58.0005815],[-160.0159024,58.0012389],[-160.0149725,57.000035],[-160.5054788,56.9999017],[-165.8092575,54.824847],[-178.000097,52.2446469],[-177.9992996,51.2554252],[-171.4689067,51.8215329],[-162.40251,53.956664],[-159.0075717,55.002502],[-158.0190709,55.0027849],[-151.9963213,55.9991902],[-151.500341,57.9987853],[-151.5012894,58.9919816],[-138.5159989,58.9953194],[-138.5150471,57.9986434],[-133.9948193,54.0031685],[-130.0044418,54.0043387],[-130.0070826,57.0000507],[-131.975877,56.9995156],[-135.1229873,59.756601],[-138.0071813,59.991805],[-139.1715881,60.4127229],[-140.9874011,61.0118551],[-140.9683975,69.9535069],[-156.176891,71.5633329],[-160.413634,70.7397728],[-163.0218273,69.9707435],[-164.9717003,68.994689],[-167.1571546,68.721974]]]},{"id":"Zuerich-zh_uebersichtsplan-tms","name":"Übersichtsplan Zürich","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/zh_uebersichtsplan/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[0,21],"polygon":[[[8.4482,47.321],[8.4482,47.4339],[8.6248,47.4339],[8.6248,47.321],[8.4482,47.321]]],"terms_text":"Stadt Zürich Open Government Data"},{"id":"USGS-Large_Scale","name":"USGS Large Scale Imagery","type":"tms","template":"http://{switch:a,b,c}.tile.openstreetmap.us/usgs_large_scale/{zoom}/{x}/{y}.jpg","scaleExtent":[12,20],"polygon":[[[-123.2549305,48.7529029],[-123.2549305,48.5592263],[-123.192224,48.5592263],[-123.192224,48.4348366],[-122.9419646,48.4348366],[-122.9419646,48.3720812],[-122.8806229,48.3720812],[-122.8806229,48.3094763],[-122.8167566,48.3094763],[-122.8167566,48.1904587],[-123.0041133,48.1904587],[-123.0041133,48.1275918],[-123.058416,48.1275918],[-123.058416,48.190514],[-123.254113,48.190514],[-123.254113,48.1274982],[-123.3706593,48.1274982],[-123.3706593,48.1908403],[-124.0582632,48.1908403],[-124.0582632,48.253442],[-124.1815163,48.253442],[-124.1815163,48.3164666],[-124.4319117,48.3164666],[-124.4319117,48.3782613],[-124.5564618,48.3782613],[-124.5564618,48.4408305],[-124.7555107,48.4408305],[-124.7555107,48.1914986],[-124.8185282,48.1914986],[-124.8185282,48.1228381],[-124.7552951,48.1228381],[-124.7552951,47.5535253],[-124.3812108,47.5535253],[-124.3812108,47.1218696],[-124.1928897,47.1218696],[-124.1928897,43.7569431],[-124.4443382,43.7569431],[-124.4443382,43.1425556],[-124.6398855,43.1425556],[-124.6398855,42.6194503],[-124.4438525,42.6194503],[-124.4438525,39.8080662],[-123.8815685,39.8080662],[-123.8815685,39.1102825],[-123.75805,39.1102825],[-123.75805,38.4968799],[-123.2702803,38.4968799],[-123.2702803,37.9331905],[-122.8148084,37.9331905],[-122.8148084,37.8019606],[-122.5664316,37.8019606],[-122.5664316,36.9319611],[-121.8784026,36.9319611],[-121.8784026,36.6897596],[-122.0034748,36.6897596],[-122.0034748,36.4341056],[-121.9414159,36.4341056],[-121.9414159,35.9297636],[-121.5040977,35.9297636],[-121.5040977,35.8100273],[-121.3790276,35.8100273],[-121.3790276,35.4239164],[-120.9426515,35.4239164],[-120.9426515,35.1849683],[-120.8171978,35.1849683],[-120.8171978,35.1219894],[-120.6918447,35.1219894],[-120.6918447,34.4966794],[-120.5045898,34.4966794],[-120.5045898,34.4339651],[-120.0078775,34.4339651],[-120.0078775,34.3682626],[-119.5283517,34.3682626],[-119.5283517,34.0576434],[-119.0060985,34.0576434],[-119.0060985,33.9975267],[-118.5046259,33.9975267],[-118.5046259,33.8694631],[-118.4413209,33.8694631],[-118.4413209,33.6865253],[-118.066912,33.6865253],[-118.066912,33.3063832],[-117.5030045,33.3063832],[-117.5030045,33.0500337],[-117.3188195,33.0500337],[-117.3188195,32.6205888],[-117.1917023,32.6205888],[-117.1917023,32.4974566],[-116.746496,32.4974566],[-116.746496,32.5609161],[-115.9970138,32.5609161],[-115.9970138,32.6264942],[-114.8808125,32.6264942],[-114.8808125,32.4340796],[-114.6294474,32.4340796],[-114.6294474,32.3731636],[-114.4447437,32.3731636],[-114.4447437,32.3075418],[-114.2557628,32.3075418],[-114.2557628,32.2444561],[-114.0680274,32.2444561],[-114.0680274,32.1829113],[-113.8166499,32.1829113],[-113.8166499,32.1207622],[-113.6307421,32.1207622],[-113.6307421,32.0565099],[-113.4417495,32.0565099],[-113.4417495,31.9984372],[-113.2546027,31.9984372],[-113.2546027,31.9325434],[-113.068072,31.9325434],[-113.068072,31.8718062],[-112.8161105,31.8718062],[-112.8161105,31.8104171],[-112.6308756,31.8104171],[-112.6308756,31.7464723],[-112.4418918,31.7464723],[-112.4418918,31.6856001],[-112.257192,31.6856001],[-112.257192,31.6210352],[-112.0033787,31.6210352],[-112.0033787,31.559584],[-111.815619,31.559584],[-111.815619,31.4970238],[-111.6278586,31.4970238],[-111.6278586,31.4339867],[-111.4418978,31.4339867],[-111.4418978,31.3733859],[-111.2559708,31.3733859],[-111.2559708,31.3113225],[-108.1845822,31.3113225],[-108.1845822,31.7459502],[-106.5065055,31.7459502],[-106.5065055,31.6842308],[-106.3797265,31.6842308],[-106.3797265,31.621752],[-106.317434,31.621752],[-106.317434,31.4968167],[-106.2551769,31.4968167],[-106.2551769,31.4344889],[-106.1924698,31.4344889],[-106.1924698,31.3721296],[-106.0039212,31.3721296],[-106.0039212,31.309328],[-105.9416582,31.309328],[-105.9416582,31.2457547],[-105.8798174,31.2457547],[-105.8798174,31.1836194],[-105.8162349,31.1836194],[-105.8162349,31.1207155],[-105.6921198,31.1207155],[-105.6921198,31.0584835],[-105.6302881,31.0584835],[-105.6302881,30.9328271],[-105.5044418,30.9328271],[-105.5044418,30.8715864],[-105.4412973,30.8715864],[-105.4412973,30.808463],[-105.3781497,30.808463],[-105.3781497,30.7471828],[-105.1904658,30.7471828],[-105.1904658,30.6843231],[-105.1286244,30.6843231],[-105.1286244,30.6199737],[-105.0036504,30.6199737],[-105.0036504,30.5589058],[-104.9417962,30.5589058],[-104.9417962,30.4963236],[-104.8782018,30.4963236],[-104.8782018,30.3098261],[-104.8155257,30.3098261],[-104.8155257,30.2478305],[-104.7536079,30.2478305],[-104.7536079,29.9353916],[-104.690949,29.9353916],[-104.690949,29.8090156],[-104.6291301,29.8090156],[-104.6291301,29.6843577],[-104.5659869,29.6843577],[-104.5659869,29.6223459],[-104.5037188,29.6223459],[-104.5037188,29.5595436],[-104.4410072,29.5595436],[-104.4410072,29.4974832],[-104.2537551,29.4974832],[-104.2537551,29.3716718],[-104.1291984,29.3716718],[-104.1291984,29.3091621],[-104.0688737,29.3091621],[-104.0688737,29.2467276],[-103.8187309,29.2467276],[-103.8187309,29.1843076],[-103.755736,29.1843076],[-103.755736,29.1223174],[-103.5667542,29.1223174],[-103.5667542,29.0598119],[-103.5049819,29.0598119],[-103.5049819,28.9967506],[-103.3165753,28.9967506],[-103.3165753,28.9346923],[-103.0597572,28.9346923],[-103.0597572,29.0592965],[-102.9979694,29.0592965],[-102.9979694,29.1212855],[-102.9331397,29.1212855],[-102.9331397,29.1848575],[-102.8095989,29.1848575],[-102.8095989,29.2526154],[-102.8701345,29.2526154],[-102.8701345,29.308096],[-102.8096681,29.308096],[-102.8096681,29.3715484],[-102.7475655,29.3715484],[-102.7475655,29.5581899],[-102.684554,29.5581899],[-102.684554,29.6847655],[-102.4967764,29.6847655],[-102.4967764,29.7457694],[-102.3086647,29.7457694],[-102.3086647,29.8086627],[-102.1909323,29.8086627],[-102.1909323,29.7460097],[-101.5049914,29.7460097],[-101.5049914,29.6846777],[-101.3805796,29.6846777],[-101.3805796,29.5594459],[-101.3175057,29.5594459],[-101.3175057,29.4958934],[-101.1910075,29.4958934],[-101.1910075,29.4326115],[-101.067501,29.4326115],[-101.067501,29.308808],[-100.9418897,29.308808],[-100.9418897,29.2456231],[-100.8167271,29.2456231],[-100.8167271,29.1190449],[-100.7522672,29.1190449],[-100.7522672,29.0578214],[-100.6925358,29.0578214],[-100.6925358,28.8720431],[-100.6290158,28.8720431],[-100.6290158,28.8095363],[-100.5679901,28.8095363],[-100.5679901,28.622554],[-100.5040411,28.622554],[-100.5040411,28.5583804],[-100.4421832,28.5583804],[-100.4421832,28.4968266],[-100.379434,28.4968266],[-100.379434,28.3092865],[-100.3171942,28.3092865],[-100.3171942,28.1835681],[-100.254483,28.1835681],[-100.254483,28.1213885],[-100.1282282,28.1213885],[-100.1282282,28.059215],[-100.0659537,28.059215],[-100.0659537,27.9966087],[-100.0023855,27.9966087],[-100.0023855,27.9332152],[-99.9426497,27.9332152],[-99.9426497,27.7454658],[-99.816851,27.7454658],[-99.816851,27.6834301],[-99.7541346,27.6834301],[-99.7541346,27.6221543],[-99.6291629,27.6221543],[-99.6291629,27.5588977],[-99.5672838,27.5588977],[-99.5672838,27.4353752],[-99.5041798,27.4353752],[-99.5041798,27.3774021],[-99.5671796,27.3774021],[-99.5671796,27.2463726],[-99.504975,27.2463726],[-99.504975,26.9965649],[-99.4427427,26.9965649],[-99.4427427,26.872803],[-99.3800633,26.872803],[-99.3800633,26.8068179],[-99.3190684,26.8068179],[-99.3190684,26.7473614],[-99.2537541,26.7473614],[-99.2537541,26.6210068],[-99.1910617,26.6210068],[-99.1910617,26.4956737],[-99.1300639,26.4956737],[-99.1300639,26.3713808],[-99.0029473,26.3713808],[-99.0029473,26.3093836],[-98.816572,26.3093836],[-98.816572,26.2457762],[-98.6920082,26.2457762],[-98.6920082,26.1837096],[-98.4440896,26.1837096],[-98.4440896,26.1217217],[-98.3823181,26.1217217],[-98.3823181,26.0596488],[-98.2532707,26.0596488],[-98.2532707,25.9986871],[-98.0109084,25.9986871],[-98.0109084,25.9932255],[-97.6932319,25.9932255],[-97.6932319,25.9334103],[-97.6313904,25.9334103],[-97.6313904,25.8695893],[-97.5046779,25.8695893],[-97.5046779,25.8073488],[-97.3083401,25.8073488],[-97.3083401,25.8731159],[-97.2456326,25.8731159],[-97.2456326,25.9353731],[-97.1138939,25.9353731],[-97.1138939,27.6809179],[-97.0571035,27.6809179],[-97.0571035,27.8108242],[-95.5810766,27.8108242],[-95.5810766,28.7468827],[-94.271041,28.7468827],[-94.271041,29.5594076],[-92.5029947,29.5594076],[-92.5029947,29.4974754],[-91.8776216,29.4974754],[-91.8776216,29.3727013],[-91.378418,29.3727013],[-91.378418,29.2468326],[-91.3153953,29.2468326],[-91.3153953,29.1844301],[-91.1294702,29.1844301],[-91.1294702,29.1232559],[-91.0052632,29.1232559],[-91.0052632,28.9968437],[-89.4500159,28.9968437],[-89.4500159,28.8677422],[-88.8104309,28.8677422],[-88.8104309,30.1841864],[-85.8791527,30.1841864],[-85.8791527,29.5455038],[-84.8368083,29.5455038],[-84.8368083,29.6225158],[-84.7482786,29.6225158],[-84.7482786,29.683624],[-84.685894,29.683624],[-84.685894,29.7468386],[-83.6296975,29.7468386],[-83.6296975,29.4324361],[-83.3174937,29.4324361],[-83.3174937,29.0579442],[-82.879659,29.0579442],[-82.879659,27.7453529],[-82.8182822,27.7453529],[-82.8182822,26.9290868],[-82.3796782,26.9290868],[-82.3796782,26.3694183],[-81.8777106,26.3694183],[-81.8777106,25.805971],[-81.5036862,25.805971],[-81.5036862,25.7474753],[-81.4405462,25.7474753],[-81.4405462,25.6851489],[-81.3155883,25.6851489],[-81.3155883,25.5600985],[-81.2538534,25.5600985],[-81.2538534,25.4342361],[-81.1902012,25.4342361],[-81.1902012,25.1234341],[-81.1288133,25.1234341],[-81.1288133,25.0619389],[-81.0649231,25.0619389],[-81.0649231,24.8157807],[-81.6289469,24.8157807],[-81.6289469,24.7538367],[-81.6907173,24.7538367],[-81.6907173,24.6899374],[-81.8173189,24.6899374],[-81.8173189,24.6279161],[-82.1910041,24.6279161],[-82.1910041,24.496294],[-81.6216596,24.496294],[-81.6216596,24.559484],[-81.372006,24.559484],[-81.372006,24.6220687],[-81.0593278,24.6220687],[-81.0593278,24.684826],[-80.9347147,24.684826],[-80.9347147,24.7474828],[-80.7471081,24.7474828],[-80.7471081,24.8100618],[-80.3629898,24.8100618],[-80.3629898,25.1175858],[-80.122344,25.1175858],[-80.122344,25.7472357],[-80.0588458,25.7472357],[-80.0588458,26.3708251],[-79.995837,26.3708251],[-79.995837,26.9398003],[-80.0587265,26.9398003],[-80.0587265,27.1277466],[-80.1226251,27.1277466],[-80.1226251,27.2534279],[-80.1846956,27.2534279],[-80.1846956,27.3781229],[-80.246175,27.3781229],[-80.246175,27.5658729],[-80.3094768,27.5658729],[-80.3094768,27.7530311],[-80.3721485,27.7530311],[-80.3721485,27.8774451],[-80.4351457,27.8774451],[-80.4351457,28.0033366],[-80.4966078,28.0033366],[-80.4966078,28.1277326],[-80.5587159,28.1277326],[-80.5587159,28.3723509],[-80.4966335,28.3723509],[-80.4966335,29.5160326],[-81.1213644,29.5160326],[-81.1213644,31.6846966],[-80.6018723,31.6846966],[-80.6018723,32.2475309],[-79.4921024,32.2475309],[-79.4921024,32.9970261],[-79.1116488,32.9970261],[-79.1116488,33.3729457],[-78.6153621,33.3729457],[-78.6153621,33.8097638],[-77.9316963,33.8097638],[-77.9316963,33.8718243],[-77.8692252,33.8718243],[-77.8692252,34.0552454],[-77.6826392,34.0552454],[-77.6826392,34.2974598],[-77.2453509,34.2974598],[-77.2453509,34.5598585],[-76.4973277,34.5598585],[-76.4973277,34.622796],[-76.4337602,34.622796],[-76.4337602,34.6849285],[-76.373212,34.6849285],[-76.373212,34.7467674],[-76.3059364,34.7467674],[-76.3059364,34.808551],[-76.2468017,34.808551],[-76.2468017,34.8728418],[-76.1825922,34.8728418],[-76.1825922,34.9335332],[-76.120814,34.9335332],[-76.120814,34.9952359],[-75.9979015,34.9952359],[-75.9979015,35.0578182],[-75.870338,35.0578182],[-75.870338,35.1219097],[-75.7462194,35.1219097],[-75.7462194,35.1818911],[-75.4929694,35.1818911],[-75.4929694,35.3082988],[-75.4325662,35.3082988],[-75.4325662,35.7542495],[-75.4969907,35.7542495],[-75.4969907,37.8105602],[-75.3082972,37.8105602],[-75.3082972,37.8720088],[-75.245601,37.8720088],[-75.245601,37.9954849],[-75.1828751,37.9954849],[-75.1828751,38.0585079],[-75.1184793,38.0585079],[-75.1184793,38.2469091],[-75.0592098,38.2469091],[-75.0592098,38.3704316],[-74.9948111,38.3704316],[-74.9948111,38.8718417],[-74.4878252,38.8718417],[-74.4878252,39.3089428],[-74.1766317,39.3089428],[-74.1766317,39.6224653],[-74.0567045,39.6224653],[-74.0567045,39.933178],[-73.9959035,39.933178],[-73.9959035,40.1854852],[-73.9341593,40.1854852],[-73.9341593,40.4959486],[-73.8723024,40.4959486],[-73.8723024,40.5527135],[-71.8074506,40.5527135],[-71.8074506,41.3088005],[-70.882512,41.3088005],[-70.882512,41.184978],[-70.7461947,41.184978],[-70.7461947,41.3091865],[-70.4337553,41.3091865],[-70.4337553,41.4963885],[-69.9334281,41.4963885],[-69.9334281,41.6230802],[-69.869857,41.6230802],[-69.869857,41.8776895],[-69.935791,41.8776895],[-69.935791,42.0032342],[-69.9975823,42.0032342],[-69.9975823,42.0650191],[-70.0606103,42.0650191],[-70.0606103,42.1294348],[-70.5572884,42.1294348],[-70.5572884,43.2487079],[-70.4974097,43.2487079],[-70.4974097,43.3092194],[-70.3704249,43.3092194],[-70.3704249,43.371963],[-70.3085701,43.371963],[-70.3085701,43.4969879],[-70.183921,43.4969879],[-70.183921,43.6223531],[-70.057583,43.6223531],[-70.057583,43.6850173],[-69.7455247,43.6850173],[-69.7455247,43.7476571],[-69.2472845,43.7476571],[-69.2472845,43.8107035],[-69.0560701,43.8107035],[-69.0560701,43.8717247],[-68.9950522,43.8717247],[-68.9950522,43.9982022],[-68.4963672,43.9982022],[-68.4963672,44.0597368],[-68.3081038,44.0597368],[-68.3081038,44.122137],[-68.1851802,44.122137],[-68.1851802,44.3081382],[-67.9956019,44.3081382],[-67.9956019,44.3727489],[-67.8103041,44.3727489],[-67.8103041,44.435178],[-67.4965289,44.435178],[-67.4965289,44.4968776],[-67.37102,44.4968776],[-67.37102,44.5600642],[-67.1848753,44.5600642],[-67.1848753,44.6213345],[-67.1221208,44.6213345],[-67.1221208,44.6867918],[-67.059365,44.6867918],[-67.059365,44.7473657],[-66.9311098,44.7473657],[-66.9311098,44.9406566],[-66.994683,44.9406566],[-66.994683,45.0024514],[-67.0595847,45.0024514],[-67.0595847,45.1273377],[-67.1201974,45.1273377],[-67.1201974,45.1910115],[-67.2469811,45.1910115],[-67.2469811,45.253442],[-67.3177546,45.253442],[-67.3177546,45.1898369],[-67.370749,45.1898369],[-67.370749,45.2534001],[-67.4326888,45.2534001],[-67.4326888,45.3083409],[-67.3708571,45.3083409],[-67.3708571,45.4396986],[-67.4305573,45.4396986],[-67.4305573,45.4950095],[-67.37099,45.4950095],[-67.37099,45.6264543],[-67.6214982,45.6264543],[-67.6214982,45.6896133],[-67.683828,45.6896133],[-67.683828,45.753259],[-67.7462097,45.753259],[-67.7462097,47.1268165],[-67.8700141,47.1268165],[-67.8700141,47.1900278],[-67.9323803,47.1900278],[-67.9323803,47.2539678],[-67.9959387,47.2539678],[-67.9959387,47.3149737],[-68.1206676,47.3149737],[-68.1206676,47.3780823],[-68.4423175,47.3780823],[-68.4423175,47.3166082],[-68.6314305,47.3166082],[-68.6314305,47.2544676],[-68.9978037,47.2544676],[-68.9978037,47.439895],[-69.0607223,47.439895],[-69.0607223,47.5047558],[-69.2538122,47.5047558],[-69.2538122,47.4398084],[-69.3179284,47.4398084],[-69.3179284,47.378601],[-69.4438546,47.378601],[-69.4438546,47.3156274],[-69.5038204,47.3156274],[-69.5038204,47.2525839],[-69.5667838,47.2525839],[-69.5667838,47.1910884],[-69.6303478,47.1910884],[-69.6303478,47.128701],[-69.6933103,47.128701],[-69.6933103,47.0654307],[-69.7557063,47.0654307],[-69.7557063,47.0042751],[-69.8180391,47.0042751],[-69.8180391,46.9415344],[-69.8804023,46.9415344],[-69.8804023,46.8792519],[-69.9421674,46.8792519],[-69.9421674,46.8177399],[-70.0063088,46.8177399],[-70.0063088,46.6920295],[-70.0704265,46.6920295],[-70.0704265,46.4425926],[-70.1945902,46.4425926],[-70.1945902,46.3785887],[-70.2562047,46.3785887],[-70.2562047,46.3152628],[-70.3203651,46.3152628],[-70.3203651,46.0651209],[-70.3814988,46.0651209],[-70.3814988,45.93552],[-70.3201618,45.93552],[-70.3201618,45.879479],[-70.4493131,45.879479],[-70.4493131,45.7538713],[-70.5070021,45.7538713],[-70.5070021,45.6916912],[-70.6316642,45.6916912],[-70.6316642,45.6291619],[-70.7575538,45.6291619],[-70.7575538,45.4414685],[-70.8809878,45.4414685],[-70.8809878,45.3780612],[-71.13328,45.3780612],[-71.13328,45.3151452],[-71.3830282,45.3151452],[-71.3830282,45.253416],[-71.5076448,45.253416],[-71.5076448,45.0655726],[-73.9418929,45.0655726],[-73.9418929,45.0031242],[-74.7469725,45.0031242],[-74.7469725,45.0649003],[-74.8800964,45.0649003],[-74.8800964,45.0029023],[-75.0662455,45.0029023],[-75.0662455,44.9415167],[-75.2539363,44.9415167],[-75.2539363,44.8776043],[-75.3789648,44.8776043],[-75.3789648,44.8153462],[-75.4431283,44.8153462],[-75.4431283,44.7536053],[-75.5666566,44.7536053],[-75.5666566,44.6909879],[-75.6290205,44.6909879],[-75.6290205,44.6284958],[-75.7540484,44.6284958],[-75.7540484,44.566385],[-75.817312,44.566385],[-75.817312,44.5028932],[-75.8799549,44.5028932],[-75.8799549,44.3784946],[-76.1300319,44.3784946],[-76.1300319,44.3159227],[-76.1926961,44.3159227],[-76.1926961,44.2534378],[-76.3182619,44.2534378],[-76.3182619,44.1916726],[-76.3792975,44.1916726],[-76.3792975,44.0653733],[-76.4427584,44.0653733],[-76.4427584,43.9963825],[-76.317027,43.9963825],[-76.317027,43.9414581],[-76.5076611,43.9414581],[-76.5076611,43.8723335],[-76.3829974,43.8723335],[-76.3829974,43.8091872],[-76.2534102,43.8091872],[-76.2534102,43.5665222],[-76.5064833,43.5665222],[-76.5064833,43.5033881],[-76.6331208,43.5033881],[-76.6331208,43.4432252],[-76.6951085,43.4432252],[-76.6951085,43.3786858],[-76.8177798,43.3786858],[-76.8177798,43.318066],[-77.682,43.318066],[-77.682,43.3789376],[-78.0565883,43.3789376],[-78.0565883,43.4396918],[-78.4389748,43.4396918],[-78.4389748,43.3794382],[-78.8803396,43.3794382],[-78.8803396,43.3149724],[-79.1298858,43.3149724],[-79.1298858,43.2429286],[-79.0669615,43.2429286],[-79.0669615,43.1299931],[-79.1298858,43.1299931],[-79.1298858,43.0577305],[-79.071264,43.0577305],[-79.071264,42.9294906],[-78.943264,42.9294906],[-78.943264,42.7542165],[-79.069439,42.7542165],[-79.069439,42.6941622],[-79.133439,42.6941622],[-79.133439,42.6296973],[-79.1947499,42.6296973],[-79.1947499,42.5663538],[-79.3786827,42.5663538],[-79.3786827,42.5033425],[-79.4442961,42.5033425],[-79.4442961,42.4410614],[-79.5679936,42.4410614],[-79.5679936,42.3775264],[-79.6906154,42.3775264],[-79.6906154,42.3171086],[-79.8164642,42.3171086],[-79.8164642,42.2534481],[-80.0052373,42.2534481],[-80.0052373,42.1909188],[-80.1916829,42.1909188],[-80.1916829,42.1272555],[-80.3167992,42.1272555],[-80.3167992,42.0669857],[-80.5063234,42.0669857],[-80.5063234,42.0034331],[-80.6930471,42.0034331],[-80.6930471,41.9415141],[-80.9440403,41.9415141],[-80.9440403,41.8781193],[-81.1942729,41.8781193],[-81.1942729,41.8166455],[-81.3190089,41.8166455],[-81.3190089,41.7545453],[-81.4418435,41.7545453],[-81.4418435,41.690965],[-81.5053523,41.690965],[-81.5053523,41.6301643],[-82.7470081,41.6301643],[-82.7470081,41.7536942],[-82.8839135,41.7536942],[-82.8839135,41.5656075],[-82.9957195,41.5656075],[-82.9957195,41.6270375],[-83.1257796,41.6270375],[-83.1257796,41.6878411],[-83.2474733,41.6878411],[-83.2474733,41.7536942],[-83.3737305,41.7536942],[-83.3737305,41.809276],[-83.3106019,41.809276],[-83.3106019,41.8716064],[-83.2474733,41.8716064],[-83.2474733,41.9361393],[-83.1843447,41.9361393],[-83.1843447,41.9960851],[-83.1207681,41.9960851],[-83.1207681,42.2464812],[-83.0589194,42.2464812],[-83.0589194,42.3089555],[-82.8685328,42.3089555],[-82.8685328,42.3717652],[-82.8072219,42.3717652],[-82.8072219,42.558553],[-82.7553745,42.558553],[-82.7553745,42.4954945],[-82.5599041,42.4954945],[-82.5599041,42.558553],[-82.4967755,42.558553],[-82.4967755,42.6833607],[-82.4328863,42.6833607],[-82.4328863,42.9342196],[-82.3700552,42.9342196],[-82.3700552,43.0648071],[-82.4328863,43.0648071],[-82.4328863,43.1917566],[-82.4947464,43.1917566],[-82.4947464,43.5034627],[-82.557133,43.5034627],[-82.557133,43.8160901],[-82.6197884,43.8160901],[-82.6197884,43.9422098],[-82.6839499,43.9422098],[-82.6839499,44.0022641],[-82.7465346,44.0022641],[-82.7465346,44.0670545],[-82.8708696,44.0670545],[-82.8708696,44.1291935],[-83.008517,44.1291935],[-83.008517,44.0664786],[-83.1336086,44.0664786],[-83.1336086,44.0053949],[-83.2414522,44.0053949],[-83.2414522,44.9962034],[-83.1806112,44.9962034],[-83.1806112,45.067302],[-83.2455172,45.067302],[-83.2455172,45.1287382],[-83.3065878,45.1287382],[-83.3065878,45.2551509],[-83.3706087,45.2551509],[-83.3706087,45.3165923],[-83.4325644,45.3165923],[-83.4325644,45.3792105],[-83.6178415,45.3792105],[-83.6178415,45.4419665],[-83.8084291,45.4419665],[-83.8084291,45.5036189],[-84.0550718,45.5036189],[-84.0550718,45.5647907],[-84.1235181,45.5647907],[-84.1235181,45.6287845],[-84.1807534,45.6287845],[-84.1807534,45.6914688],[-84.3111554,45.6914688],[-84.3111554,45.9337076],[-83.8209974,45.9337076],[-83.8209974,45.8725113],[-83.4968086,45.8725113],[-83.4968086,45.9337076],[-83.4338066,45.9337076],[-83.4338066,46.0016863],[-83.4962697,46.0016863],[-83.4962697,46.0668178],[-83.5599956,46.0668178],[-83.5599956,46.1261576],[-83.9954558,46.1261576],[-83.9954558,46.1931747],[-84.0591816,46.1931747],[-84.0591816,46.3814972],[-84.1152614,46.3814972],[-84.1152614,46.4953584],[-84.0591816,46.4953584],[-84.0591816,46.5682653],[-84.2579545,46.5682653],[-84.2579545,46.5051232],[-84.3071879,46.5051232],[-84.3071879,46.5682653],[-84.4415364,46.5682653],[-84.4415364,46.504525],[-84.9965729,46.504525],[-84.9965729,46.6842882],[-84.9298158,46.6842882],[-84.9298158,46.818077],[-85.3165894,46.818077],[-85.3165894,46.7535825],[-87.5562645,46.7535825],[-87.5562645,47.4407371],[-87.6825361,47.4407371],[-87.6825361,47.5035554],[-88.2560738,47.5035554],[-88.2560738,47.4433716],[-88.4417419,47.4433716],[-88.4417419,47.3789949],[-88.50683,47.3789949],[-88.50683,47.3153881],[-88.6312821,47.3153881],[-88.6312821,47.2539782],[-88.7569636,47.2539782],[-88.7569636,47.1934682],[-88.8838253,47.1934682],[-88.8838253,47.1284735],[-88.9434208,47.1284735],[-88.9434208,47.0662127],[-89.0708726,47.0662127],[-89.0708726,47.0026826],[-89.2565553,47.0026826],[-89.2565553,46.9410806],[-90.3677669,46.9410806],[-90.3677669,47.6844827],[-90.3069978,47.6844827],[-90.3069978,47.7460174],[-89.994859,47.7460174],[-89.994859,47.8082719],[-89.8048615,47.8082719],[-89.8048615,47.8700562],[-89.6797699,47.8700562],[-89.6797699,47.9339637],[-89.4933757,47.9339637],[-89.4933757,47.9957956],[-89.4284697,47.9957956],[-89.4284697,48.0656377],[-89.9932739,48.0656377],[-89.9932739,48.1282966],[-90.7455933,48.1282966],[-90.7455933,48.1893056],[-90.8087291,48.1893056],[-90.8087291,48.2522065],[-91.067763,48.2522065],[-91.067763,48.1916658],[-91.1946247,48.1916658],[-91.1946247,48.1279027],[-91.6814196,48.1279027],[-91.6814196,48.2525994],[-91.9321927,48.2525994],[-91.9321927,48.3142454],[-91.9929683,48.3142454],[-91.9929683,48.3780845],[-92.3189383,48.3780845],[-92.3189383,48.2529081],[-92.3732233,48.2529081],[-92.3732233,48.3153385],[-92.4322288,48.3153385],[-92.4322288,48.4411448],[-92.4977248,48.4411448],[-92.4977248,48.501781],[-92.5679413,48.501781],[-92.5679413,48.439579],[-92.6210462,48.439579],[-92.6210462,48.5650783],[-92.8086835,48.5650783],[-92.8086835,48.6286865],[-92.8086835,48.6267365],[-92.933185,48.6267365],[-92.933185,48.6922145],[-93.0051716,48.6922145],[-93.0051716,48.6282965],[-93.1225924,48.6282965],[-93.1225924,48.6922145],[-93.3190806,48.6922145],[-93.3190806,48.6267365],[-93.5049477,48.6267365],[-93.5049477,48.5635164],[-93.7474601,48.5635164],[-93.7474601,48.6267365],[-93.8135461,48.6267365],[-93.8135461,48.6898775],[-94.2453121,48.6898775],[-94.2453121,48.7554327],[-94.6183171,48.7554327],[-94.6183171,48.941036],[-94.6809018,48.941036],[-94.6809018,49.0029737],[-94.7441532,49.0029737],[-94.7441532,49.2536079],[-94.8084069,49.2536079],[-94.8084069,49.3784134],[-95.1192391,49.3784134],[-95.1192391,49.4425264],[-95.1934341,49.4425264],[-95.1934341,49.0035292],[-96.87069,49.0035292],[-96.87069,49.0656063],[-99.0049312,49.0656063],[-99.0049312,49.0050714],[-109.3699257,49.0050714],[-109.3699257,49.0668231],[-109.5058746,49.0668231],[-109.5058746,49.0050714],[-114.1830014,49.0050714],[-114.1830014,49.0687317],[-114.7578709,49.0687317],[-114.7578709,49.0050714],[-115.433731,49.0050714],[-115.433731,49.0671412],[-116.5062706,49.0671412],[-116.5062706,49.0050714],[-117.3089504,49.0050714],[-117.3089504,49.0659803],[-119.882945,49.0659803],[-119.882945,49.0050714],[-120.1208555,49.0050714],[-120.1208555,49.0678367],[-121.4451636,49.0678367],[-121.4451636,49.0050714],[-121.9311808,49.0050714],[-121.9311808,49.0656099],[-122.817484,49.0656099],[-122.817484,49.0029143],[-122.8795155,49.0029143],[-122.8795155,48.9347018],[-122.8174629,48.9347018],[-122.8174629,48.8101998],[-122.7538859,48.8101998],[-122.7538859,48.7533758],[-122.8712937,48.7533758],[-122.8712937,48.8153948],[-123.0055391,48.8153948],[-123.0055391,48.7529529],[-123.1296926,48.7529529],[-123.1296926,48.6902201],[-123.1838197,48.6902201],[-123.1838197,48.7529029],[-123.2549305,48.7529029]],[[-122.9341743,37.7521547],[-122.9347457,37.6842013],[-123.0679013,37.6849023],[-123.0673747,37.7475251],[-123.1292603,37.7478506],[-123.1286894,37.815685],[-123.0590687,37.8153192],[-123.0595947,37.7528143],[-122.9341743,37.7521547]],[[-71.6299464,41.2540893],[-71.4966465,41.2541393],[-71.4965596,41.122965],[-71.6298594,41.1229149],[-71.6299464,41.2540893]],[[-70.3184265,41.3775196],[-70.3183384,41.2448243],[-70.1906612,41.2448722],[-70.1906239,41.1886019],[-69.9336025,41.1886984],[-69.933729,41.3791941],[-69.9950664,41.3791712],[-69.995109,41.443159],[-70.0707828,41.4431307],[-70.0706972,41.3144915],[-70.2461667,41.3144258],[-70.2462087,41.3775467],[-70.3184265,41.3775196]],[[-68.9403374,43.9404062],[-68.6856948,43.9404977],[-68.6856475,43.8721797],[-68.7465405,43.8721577],[-68.7464976,43.8102529],[-68.8090782,43.8102304],[-68.8090343,43.746728],[-68.8773094,43.7467034],[-68.8773544,43.8117826],[-68.9402483,43.8117599],[-68.9403374,43.9404062]],[[-123.1291466,49.0645144],[-122.9954224,49.0645144],[-122.9954224,48.9343243],[-123.1291466,48.9343243],[-123.1291466,49.0645144]],[[-82.9407144,24.7535913],[-82.8719398,24.7535913],[-82.8719398,24.6905653],[-82.7446233,24.6905653],[-82.7446233,24.6214593],[-82.8088038,24.6214593],[-82.8088038,24.5594908],[-82.9407144,24.5594908],[-82.9407144,24.7535913]]],"icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAA2CAYAAACCwNb3AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAcppVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+UGFpbnQuTkVUIHYzLjMwPC94bXA6Q3JlYXRvclRvb2w+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgofPyfmAABAAElEQVR4AeW9B4AURfY/Xt3TEzdHYMk5I7KICKILhwE8DCe7eieiomRByRmGjKCAIHhgjl+PNUc4UVZEggKSdsmwsMuyOU0O3f3/vJqZZcPMgnfeHf5/BbMz3V3hVdVL9erVa6HNhEciCxS7VtBJKvsDJlWUxCjFa8tdk+6oD/zU1ZOMhyttYXYmK1EhMlbgfnudQWgd161y8+jRnhDZgt6+ZdIkY0nU71N/ijlFyjBneAMNTX/3lSZH8k51u1RR0i3KFHZTvrUy9qy13NWvVbtebkWJ0agq0yusdH9+zv5u0Ym4YgfCw0wHY6Lj93zw5Iw8fz2C2WymjxKo91q/U8xmwGOugufhDUuaFpcV9XJ53T0kSUo+VFooJIaHxSXGxifbnE4lwWASL5cUHRA1YmmEVn/Crsjfx2gjD26f+dzFQJu16wzcv4ZvAWU1AXhUVRWGvrSwvdNj73uxorhNpGTofryiSDIJGm2HpOZ9y1wOKdxoYnar9ezlyuKzbSITbSqTf0mMitvfuVW7febBwyp5mykpEtuxQ2aCUIMOhEaTH/qkQHEOEgShHE801wDg9ZNFELwiY4lhXmFWxbqPVzIgFquGWARoYCJ6zRsz/YS9eLmLqYUCE6SanVDQcZHZFK/S0RQZ0a998p2bhz+zK3XLFk16WppcM2+tK3+bzab9dXqx4lmuoH7G6yc8BHQ8+euXPUq3sNiI/sm33vniX54MVr/AUlNFlp4uY+LFQatn/i2nrDDV7XGnWEQlslRRmFslcFSmEUQmW0DSCtEDkkYjaMIjQP4K00sSixAEZnSzypjwyB/ijNEv7pix8jvKVpv46F49qQY8dzw3+eFiS8UTZV5H3wqmGB3AFpfHwzSihsn4ZjYrANMIzOtVWUSEwACHiH9hBItXsbUMiz5q0Bs3Z8x68U3gG8Etms1mhs81EW31+Xj2/15u8ePJQ0MdLucjFtndzY4JLGcKk71eJogiU1VUSeMjAEhZVpnBIIh6I3IoLAxwxSoahju5kTrjBze37v76xuHjj9M4ABaCqQoeSRZZnKLX6ZnL24CJAo29L+HndZcCsAUAAzKoJgNTLe5wfivPUgdqS14ev2cTvOF2o1b02uwNGQawdhIxcEzxMlmnZS7Fq6/9POS1v02rIKN+CVTmRP0BMK7QFq9f9TJFr2Gq7KlbPzghZhP/0+XUF+c/0Hn248suM1eHMsDE3G7MiwAABUUEshHXlAVZNRjCNRgS0Dv+qEx1uj2YTgFI62Iuqk9kkTkO75A4Z+WQ3gvHfZPcptPYDY88fSGllkQI2jcqj7aIWAmeboDnEuAplQGLB/3i8DBFgzyyCiIBxmvDIjWEWVoUdCqKrLhloKnMLCB2C+ik0F7SO8yl7d1yxrBpf14zd/6Xk5Z8CGRk1RE/KCy4mboltYpZ3WoeN/Orw7tm54tyhMXtBAFgFDAk6LpK40NEIAJ+ozFSQ2oApgMPMbser0Izb0MZG7IC6CaS4J5qObFv8i2Lx5n3zNu4mIgjNRVtod8EC8ZTcDMvuqUyD2c/CrCOPsSKrrdPADb/N6bPrQHsXoFh1pCSImqTEItISuL38Ac4RdOH/tII1voncJYjYAyIO0uU8dqSv01JEWWR1w9YatVN17x+jLEqY9xFQvZqyYeMKk1wj/mjVu68fPrjLE9lhzK73Su4vV5R0CjAP8J9AKZKQF2S9JJTVQQXUNCFqaLfdI+eUz4BhVBEofIlDoey11Yw6LvMX44OXD+vawbUJSKSahDU/AkuCrygcVP7LRy7cmfB6Y+PeiwdSh12r+hRILUFFXjI4ZH97eFbAxgg4RRmg5Sja9As2uDwiETAohe6sNPpzVbtHQ8VZ6cPWDZpM4idIz4RSU0grlz5iCNdNn/9bpOOsx//6ainbPlppyXCYnd60EMZRKFidDSB8aE2MRoamx8eECvzKIpI8ND4YCwlEWJGVETF63B7TtnKxJ/txYtuXTx+16a8/SYiDhAK56KiqoCSiFOAygHSH+OjchkAWAXZi5HHyISUIIFhJlGPAaREncVFrQ/q5GPgyxMo9tu+r1a/jyHVrRMzRjdbTRu2MdNbOa3Abge5qSAMkRaGErQoTO5vSxy7feWADCAXj+w+4ayIyL6UvWfEO2vbE5EQ4gWpVWBmM2+uzYxhG391l00rsNkUjax4UQ1xDvpw6glSNuQtVEhcAcQrSBr0Ldda6f3eljdyyJrZu8+rqoFU2QBSVq8kQBxzvtjS+Lv9Px077i7vU2FzeCTONJgWCE9S6zfBQ51DGXw4zmslUaPKDrd7l62g73tvvfVPah+wUBbQXSCBewV+Xu/fYAHgCYpXlURje8HA+sY32U0wpw5sRZ2qJ/072F9PtVWPfnv9yaNGaVFc6b1o/OwigzLW5XC4RfB+dIS4YNBEtykLvmX6gMNx1SFoZtykjJhcHRiJ+4xiDTt5/uR7lDc9jasRVF31RDih3r746XVnRPdYq9XhAa8lFSWkFYeLs2rw0PxcQazqVft+Q0hLQEqJWR2ub0rO9Rr13OS36AmQ0pfhyl/BDyP7cu/WLT9WXI4CIC6wE60XyB0KYYn7EQw0NvTxDeeVSmv/ghILDsJ0zOlxHbQW9U1Z9sxMypMCY8CVfpCAv84TAQiAsQT0irHGMKlnWMLOlHY9222d9+LnGF0xMJjXeTeqgZelObB5s2fYaytuyLWVLbVUWsHSBHDF0HMBJIdAgaKmyiIYhEbVajRQHkRonRwhqlVe5yfK6Zhbdp/3WJL/+tKSxygDIUEgI36T2iU//PKSBy54LROY3eEFonGJEchT+5sQELCAW3lFgoVggiYlKqqCZTDRVfAEBGfIqpdtDvdhW3HavS/MHoacih8GXigA213PTZ+RLTj7QP11oz19KMLw4wcWBjLDarIKHhLG0A5kiJlQRblE0Yii1upwsNPlhdOe/eSN6AxI2dB6aPB+/c/ukjLrRSdVrSS1l6K8rWIbzPxm6soX9hNEWFQxsznkZPzPgL5Kw+lZmTzHpYL853NVF1mDvNDdSaIETdBPyIwgJphMrLFoLHeJ4gmnwJwGr9zIpnrbX3TbgZIYI6gdwSog8QrVRJPnsLELxbljcPkWkKBK6hJCULn9F08ty3ZZAI8kAJEJ7+okugkVX1Z1oqa9IYpFSYZLxbLnrB4EHmEQOhaqzuhsu4X0GBkaJBkT6iQiEp0gSYXWCnZe0ax87cSJz57s0AFrelriMJYBK+XML9+L2fLj19MrXDbAI0qygppqQRTQr/AE+CFqWmjDWEPJdKlYkc/qYTvQKkrHE15rtBPGDqjaCqmstesg4GA6BCEJHouWxR7OPDwCt1Zf9wTCRRwZDmVFig8Ll9rronZ1btd95Oa/jT5BnRq1aZQ26XKSbE5Pp8s/VjKnu4dvfqHdj2cPDmQON1iqJjRxQGUgztwjIrG8fVKLme2bdP/IPGRIMXV4h6pKmzetGCiez1ybrdrai2ReCWGy53q3W2aXHRW9xr2zoc3GR8efMUP6ZkA4E4H0mDd6WKantAMQ2wOWGxQejp/YTGBaQXNrRMN9PVp0WnRrcv+daZ07WwmeV7Zvb7Dn3C99ThfmLdxrKejqcblBJCwokcCiAQOf4AGDaPRO+ktpKP5a/4ULNSn4kQFt4fDpQ8PKtUoscwIeFfDUIg5k4wnEoej1Ok0PU/zOlo2bzRvcJeXQsN69+R7H6q1bY7cf3fH40aILz+W4HbQmA20HrwmcRayElatMqHwQFfsIhNokkiUqp8/1kgJSA7JY6qCPltvEN5n15eRlq34CgKS7D/lrkmrub/Zt6AUsQfUC/5/u3W+v/1LZpbuLNaThk/SAhTRIIh3aq8hi1/D40sE33d5zyb3Dz1fLJvQHp8X11nFbNqTsPPLz6WPW0nDsitCOSR10AoSwP4leu8Sky2X5t6HcmQw/cVCdHtU93eXlZlsxlEhGHV4Rmy3Jxrivds3f+OddKLeOCvvaU0cOHFiA35/Qp8u8EVuOqRWpqkcmGIMyZEgGsczlZOWSnbj2ayBUhaX6YL9YVDiwFGZrvi4LNbywNGNRpmkhmf6xZ8HGh/egkvfxQaL+q5PvvrsU36v/vHZ2sT3/3FslDrsCI1ZQgqXRYW4vc0ieHpM/fb2pCAEKoSzTfhN2d1RYKtB5iPI6I0vN/ZcStc23m2A4iQsPl26LarL7js59uhFxEAijNm3SHkg6RcThXfPrjugR61bcAAoH+MHVgf8S2GjmGkat1iTLLvdtFtlDa6ughekmdhOUOKhVLWOT5hBxtDA/biCu72+Q97vJpFTjxrTx+S1ik9ZqDUZSF4Lit695US2DmeNs8eVmNDbG2BKukt29fOZNpR5nV5j98TS4moaMqEKR2jJ95Z9vuYsQGnsUZh2pRfhJ1dNuvTho3QS+1zPqnqFPddSGV0Ifk3xlqUTNhA5AiiisyGG/cdimpY3wVGHpTF51eFsYiLkP9AcMTjWDUrXiGAQY6BVNG63JPbB///H0KNVcAx5mVvlYSV8+u+ztFrqwnxnUMN/WSLWK/D99kkWQKwXFcPLsmTaiVhCiI8LDWJTRqDcYjRLp+DDaY59FhewTvFho1ZrSupX+nncg/kCrEKeiIHU0xSm3xbecuXPu+r7rh43JIqlh3mGWuBsIdswnvb2+Z/rnW07+cPEILfBY8ujRQTnUFfiC4uCVx/+1X1fALHDbmnOFiMvwugAAYiIAKRrbHs0aNfyccjzOWriBhJhLv8AHc7jlFt9eUKwx8uNGfPtBqWaBqVkvYQd251miKbwjPfnm4Bd8YByCc+glEYxegCG2ZpGqKzzwag0G1jKu4Wvmu/5S2NmcqktPM7uxzggUUQm2byaud9Gzib0HV0YbIzYzgx5snv7XTT6kZF6HRjWWlFfcHMhx+Kefm5TarTGcJEMxP5IeOokl6iP+uWHgYyUshUnp5hrwMLNgVoA7vI/Nw+K+MWFfHAyAxq9O4p3ARnIxNkTPFeVqxJYxCa8PiG258e5mXV9INias6qgJ/6CjIfJiQ/jTKFBtZOw0wJ6GvTj/ZNSp8ve5QdDjQ7wLi9Bw7W3RTffendy32yfPLnmOWiDCOHDKJzWIWw1dM3fZtuO//LLbXZJ41mUnNypGUoW+r+uETmKfkLqLPn0RD4W4DXFIrA5JItRJWhp94EDTsJiKOwbegVUvYwsWLKjTz/TULXzCW7VsfSFaZ6gAvRHL5WzdP7ZcRPGGaaihKlR63MStGXszmyOuxW4Dt5ZDwsIBVGVNM1HPGic2+YiKduqUGhTp6VkCK/IhocC2x3DvHp+ptDY8PpgE1QmI7R7XjVSWUqGlvJlghHWa1jscPfjtGn+wZlc1ko5l2yy/0IPkdj5CqJEJF60GlnFYPFpxN8QSRkbl/hTBYVHVaK2O9WzV8SZp9+z1L9eubMOOHeGf/rqtTwerdVShtvLBLNkmwRUFLEmEiST4RNau47dck+kSSp7CtDqpoSxYbghLmLdtzpoXd6ISkhqtBg5UzP3TSIdlE7as63X7kgmvHnaWdK2wV3r0hjCtEXtP5b+lwesk78nLeczicQFryD2i/kRbfY3j24dERtTBicZ8d1pph1mPncL1TbASkYcBV5+q187VL1XQFNtt8NPgyUPqzKtb3msDoy2KYlfA7+JVvRzNE0hbjBT1l4Y9dv+B1x6fxNJTU0OCnsJSlAwstVtFJOWcLy30YIqx5Q3vD/ytqpegpiswYbvi1f5QcM4VeJZVVuAppi6AcOpwhECmQHHsi9OtgOdEtcf+n6n4TmftW7TzZlcUsSK53KtIZDEOUrOqeuxeWSorq9BLJAYzs4tE9mYGLXb5BIzv35+sEbSj+M9Rb6+92XQua062UDmk2GmHSijC2hp60whlri0BLr9hwItFkBRpNIpNmWFr1+ZtR30wfm4OVZICuzwGWD2QtpnDdf+auQt2HP3VfMyONZfMPEbRoDqAFxoRmiClIL5Y/P51+kfr8cCRgSboCr7UBhXrDzwUWYndEvvl1+mReG6vnSdwHdh1LrDZ5YjYKKY4XXpy3KudYMORnGDMsaIp6pz/4eG9+9s7ZW9DqHtggcH1fWCgQlt8UcawrP5CSyIu0EzovQ7zArPKzIyVll7OpU6YwsM0vt29uv3FxolUqZfYPbFN+37lhwlrC0g6/0WIL/RO8GIN1zYirttl5MnIMAfN2TkrSyU7p+xwZju8biZEROrDMa5ByANbRbIUGxnGEqIidFImTI1UI9QWcep7mzpl5meHaXUaTaw+qqilLuGSefgT+/D43j+vmzv0QkHeO0edZQb4FcENglwgqOS/lrA5S3tbCqzUUhuN0ZNgjHp69/yXNtPOQDJMt61iBip+T1p15JurO2deOPvmpwWnejJs5EgaiXQSER1VI/SRLNotlnOsCeKL9a9B9x8sVW3M4JKtMYq+tWsoTABnAIoI3suy0/TrmaMDANn7PTfztZbPelcNVJ+aJbBBbbq+ZxO9hyEGHGguCIUAqWUlXK8z7uT7SKijwFYebyfsBcLj75VFUrX6AQtOF8CZk6kH+G1zCtxSMqrlqPXTj9w3J9/pjck5+LzV6w6DixgEGCRILajgOgDlmpliJOPeQC1hBqNY7oF/F19ehaQUDbwzWaFUOYg299Y+8EQ51kA1PHKpPtzjI7/m0w25D/T7y7LOTIgig5RaXZoFGobjI9xOw+Ni476Q0jYt7X+5KO+xtnOHJ+tVsVO54hG14DqwbFX8qjMU9l024ecoKfyDLycu+XDjkR+/e/3Dd77b7yi+UXV7PXzjhtTKkLAHWrzyzRUBAIbdGikcA9CM6bcP7N570rqHxx5DLhFOa0JR1kY1fbRPavRbOnHCP7N+eeECc2NmvF6dRivCIQ6dVaRWkdGsbXiDtU927vViGvsHRiGDS5orrV2HvzBWWHLwdHO/uyt/PLWvCEgZidUC+lRN9fCDTrNKfodFLuzwFufM26+q6T0FwROQFv5svi+fmiW8P3H+SzXu13NBKizt5oczqYeH89N6fI4g7eJFibWIiLOSKTUF/yDh66ndx6CxX0P8a2Z9Gas/C7jkd4lvarPmnYTnLVc2gnJ7SDVohKL3hNcerj/00wzUM+vdkn1kLq9S1fx1cwJh6ZnuT9Iz51Rvr77f0i/ZJ5df0Mk3K9hdhTM9VQKbGlZUWimKuZ1RTHC2jWKlj7SfOfzEt//8buT+RZt79F487h8XvZa0vLJyGdwc2g55btafiIZASVho4D9O2TRmOkfTsPgpe+etfzmLveWXGmUkNUiXVB9at7j1iaLzmw/biwZUum1ctQNBCm7sBxhNRrGLLvJs15btR77+2JQd26hp4kpXLCl057pNosYne59o2dLZc9HYo8xjaa14sLdHDpNBEje5Kqr3nNveYeayKaQp3E9uNVwF9e9+VyumEvGc2x4jhtbHcVQCxwBo4VqU5fN2/i7/vNbJFVUSI6FmUxXhjsysLvtBai+hU2aojNXA8f0kWKnN+mDKwPNUrDexrpFhemK9OnY6fvzyubI8puJQmIA9iBCsmPxVXV52Xq2Y2X3+qIOHFm1OB+1K5hSzAslB+FQjEQFa8trVCwvBOiQpSZZK3A6rip1VLHHsilZnitPpJZOXlUZodBcahkcVV7isF42SvvsFe2nDS56SH/ssHL9+97wND/35hZn5Lpd7YokHqijWAzjAQ6ZhLqQDfJATBawMWPPBWwfre0HRRhtNYpKo294uvuXITyeZswG5iMETMy5jrTHaJwFSVkwcvzc3a/UFwaNDx2F4kDRwV1YVDXbT4U6UHNVk7UvTV81sKwguNipZyzbtJ6K+5smqMVr/44sG+oi9Ea6y+y0uaDb1SGLghuR0ueTtpefu67vw6S3PjJjxWFrTpo5giOD3SbuqND2wGZ1PSefqVK+Yhk22l+fysxN1MArZCDTMLzOCITpNOv86KBV3iV6vnjLqEnLQQumbCSiexJl3pFXcMO/Jg2Cof1Khc+BuHYODPy9QTFQqvR4x2162ZfDKaU9/PX3VBjPWI34JSTK7Cj8y+KG6DH/R0F+kR4pGYmfovU6vM7XWhh3pG9vs2ZQuPTpmLX+rx/dz1t15YNHrT+2a/3LPnOf/0aR1XEIXtOKcuOkF85dTVjzTPizhTzeYYs4nhIdpZQ3cjqHPYQwhJEio0F4VllmgDxCHGGnSa1vrwktuDEscn7X0rTuIOAh4UqkweOAYGd5H317Vsvu8kd8eqix66YLHphPdMihE1Higk5hMBm1yWMLJGxu2uHHbjOcnEXGQmwkrgwfvdUMcVXMQetRrZenYqPFXTRRoBIoXi5HQFELFyKcJ29vyT47C1FWbF2U++eoLf4KG4+Vckk42htorCA0NVrU+xDHpjB3JggUOFxQILtowuZGilrU2RIZC1Ppa+k3PiGlSAb3W8EGEXgeEAlaFSIS/tHdHG9zlXhc7UJn3Um/z6A9mbX8rjtRHFFNRX9B1VYgqq25LDqZGNtaHsWbayAV7zBsWna16xAdKYljNsEzfJtT/jZpPa+jpw7ZsCB+1aUXU5tEzv9+Wn991yRsr/tpEY32yzGnvbmFeg42GGDMaBmNIGCY0wRBxLjLC9O7tbZL/bv7LcBxJZQIAxiBnqOl+C9WdK6eN3Z15ZM1Z1a7HVr8Hbj4i7II43SSL7SJjWfuoRi+Pnbpi0mAQBhEWierNo7lzXQDl/K1e6cB//1dQ3KoJRrUsgyZM0D8//JljtywY8yFTHEMVl0Im0KDuJlQJ7ygdlsLRwV/chS0rsj3b+5jHru/TqtuS54ePLSS1hBAh4xq5NQfMLwTyLGXw5MOGNqFi0OQbXnj3gpmaAmMeNOfvcRN94IAM7nD723n7P55nEYVmIF5iuJxwgrVBzyBJ1AKrRS4yeh4q2Lat/4DlExd8N/PFTWAuJEWwxk2tcqEPVkfte1JnQ/SeyPCoWdtmrNxBD8nsa2gUA3WHU54HxMGwMNQ+vH6i2KTUIjRt1VkzPm08d0qj/Hc1bGjD16v0eeL1F5rm5l+68bylNAq2W2+rqDhvUmzMkXfGzj1LAFID5AZQBIL3D4A6/r2Xmu8/dXTzLxW5d5ZhrQFB5KFVlwdrDZPJKNxgiM7u1qrjqE2PPvvtF9Oe4wiAatQAEvQyjx5ThrPHp1/44O/cq9d/VBJ5rvsU3i9OZesZ69C8zYKi07ahZ9RyrQYjgEMM1cioZjf8RKKVVFE+VVEinjLpJ1hP7XtyyJqZyx59dvmKNB8iCECE3+T+X+ay+4REzeaqrgIAgUszA/uXmHFVXdf4g3N9c1qa+5aF4xYVOYteddnh9EgUUE8FEDOURVIdHs95wZnocAovd5r72JN3rZw5b9v0FVuhfgIJmcbcGQ4oQdYntauW9izeNInfhIhO7TQOHJ1vyCk7zp83rP1403155cUDxywa3T+3olS4ALNsg2MHNL0WjKqINoXtjo+I/eT9cfO2+yvVvDFiSg5+04enbP/3u+PmCeQ/FNdIJ6ePNnOzMj26Z83MUd9m7nvxlGw3wFTn1SFCCYIS0FxoEnRGlhzXbMP8KSun9REErmunpJhZRiYWhiCCOV+81XjfsV83HXCX3lMhO5fzpmLO0SSHYoE8y/X1pxNUS7P0xoipWXesmjolX/C8YLU5vHBO1F6tE9gE1GgkEBPU0CPuUlOmbFuSPWfEiLSXFi3d8vT81/k6JCUFC9WUoAvVK+PgEyFwhvSLqCtP6v7CBhi0AoPBRyB+4VM32+90hzNBMxPhgPhaz3kj0341Vtwpk886HW6qJ3FdDJIY/otKfrlVzteKPa2Vl77pYR71TZQhZtqOmc9hd8PMGKmlCzL4WfZQ1VFPObcpyuqME2a+CB7DXl7+4PS3lq3K8dpb5sOTEvv/IEuYfoG6uR4Hy1UdQEND94YVheNaz3jkwI3N2i77cLz5Y2pk5OZVD2c7Cg98+8yq09UaVbPNbzqzcWMLDu289vy0O3LKC6fvK7pwW7EDm4+QGhKOCUOzwqLIIPUNS8xp3bTF8DefmJaxdeoq7tJ+6nJSldS4dcnEB9L3fPfqKa89FuCzSFjEuF/zH2EfpNqg8J8+dUj8dtrzq29bMrHPLjX/QdnhcsMnTcdtXQHWXbscroHSeEqIICmywysf1ZS3ys8/8doN80c80alhm7n/N272D+aMjGtSu7Bg5LUFaYbf4mAgCzaKoePVI0Fo7ZCZWQ/UoVrw3Td37lyDs5uZ798dXe8YVrb/i1/O6rzNNR4VuyOqtj5JQrWhT3QYEschVTmnsoLl6G2Dmjosg25fOuHNbm1vnL4+bUQRqvcHhPAFafBBceWvBDEjcGpKT+eesVu3f7Pup0vHHz1vh/OGLHi02PsENKBHURuF8C4NdAa3Tqu7iGNblXbVo4nQSD1OluR9NHDZM1+2a9Pur0qlO8dl83zUY8EoS5Sg2WbXas7FR0brC4sKaQvjxkXzRtxazjwdc3G4B34/Xh1UCjc6gnMBmg7RcayhKfr5V2asmUuLcFprkJvJZh/hKrTo+ipj55oTtuJHi5028liwa416k12mg2Z/3ARjBk4ICWzn3HVDsbj8PEuqHFJpteE0G05Q1Yu2vj5jt500H5hbBLnIalOKdK5biy4ey+i9ZPwbKd37TFnx50fKSK0Adwpp0OC+v/UtvfkIKwzno5hJbwiVk86zh1xMX8sM+c/1UGsc/4Gf/JTh8rS0oj8tnX2zq+LCz7kaWzOsKMBEmO5qjfmf4ywahggHanJUm5RjcT+e/2vZ0LQX5y/b8syi5fWYzBkRCK9j+N+X3PfuZ+9vOuCqaICzwrIRZ3dcGHEEsdA2NUWwhobIH2D23ZwQ3XDv3U8MvZwmwMSINPOnbYk/HdjXqMBe8UR5acXrI/9y34jPM/akZJ069tkptXJhCaQCKyghxzjf1o0b1wocbMCJsOTSubUia2g0MhgKDndq1PaZd0ZN/6HtzLVVUiMg1R57ZdmT2zJ+WHPEUxkBdUzWI96RCwEt3NiCbaLXm3IJGNi2ySzzR0sgDuKafPd3r3nTvbctfvrVXTrvk16ckQC3plOG9bDsK72l/ShIHg04midPsUn5gvxE5U9bBz+wes7oTyYv/QxmMOCvr50rpa7tF5kkmUarKbBUuAut5eepVBbcN6pKQxUCN1ZaTXlwZoHKegC9wQFDL6iryvl/kJ9XpaKYUlt1OZj+zOIVuE3qMsfNDEhZ8q74bvSygtQNK2/OKTq/e6+jqKUKtRwqH/yPr96On1AomomKmETek4IlvKTo7LIBSyfe36lt14dfSht5nqtcteKqSbM+fitu/5nDz+/KPfn4ORu5/Ekeg06rcXghNySdlGyIq+zStO2Et0bOfNvfF/b6CL5sIS4ij+17F1ml6PPs6i1bjF9+uyNxDWIv4brfk68+f1tW7pkxFcw5yCZqoitxZsapk5heo9HpoB800Ohko1b/U1xY5GvfTF/1Nvdf8G3wMPNobsVQEOol8suff1z//cXjw3Os5RSSB3suGhGxq3CQQW+41ZhwuXPrlp9tYh8wMzZ2zGj4j5iAuLRW4ESyc95LT93/wsyzZ8oLlx2zlUp04g4UIiGCC+fj9fXPhwiQ97QtBX09izkaOMtzP+23ZMKyH+eun1O9nbr1hK6elAjEWRDOuu2Vq1aNJrcnhrquEEhmKgqnMxxxHGqL1CULDuzLExO8xsT1JY0Gu9RqKxQhAqkBDBmNUrBeSx8/PX+Hqnaas3jsO2c05UMLrdhEhusRtttCBpWoDgLGByYQHOpgGqXYavV+77T1unyo8vi9G+c/+Pm4RV8hL8frQBlp+6+73vmV2Qd5Ky0eHRzRPJD2cFoTm4RHiV0iGnwx4OYBo6b3vyefCsICpUlvlKcyn4WLryM3wcIFWzPLcbnEyWlpJFUuBCp/7ampO/F7J4VsuVSc0+d0fk4UNnLcjQzhUuPwuLJ2DRofWfXw6LOB/HQQ6tTly8RNgf2M3bl6zpD3f9y2+bTqaqg6XF69Ros4UAhvBXWsdUQ06xjd5I3RUyY8PURIslOwL5TjMAXq+6N9A354CkLb6i9oPp2yYvnYd9ftMJ469topT0WnChvWajh1CM5MQRSumqCjE4LpcAZdPldRouaHu2YPWD65+/ezVt9D7eDDibFmRVfwveZ9UCcQy4v16A0RCfFpc99rN+eBRw5hDwuWspqRJ+HcVMps8NaSVSdgDaWK1a4ePADTqnoN2KmEJ2rwlAG8IC+B/ohLhxypd6+c9vhlofiVw+4KCYGvEL0E0SYhRYOXrnkXIfywPBF0Gq/gOe4p0dsvyV8O37hkztvj5i7j6igObFEJKctaZvLCUcQAlcopexDkFYsKfYKla6M2z7w1bvYbW9kL1Z0HuQVqxpa3m2XmZD3icrvuenH+iKRchxXAwUQ873FNpNZ4IiI8Ymuflh2/Nj/wRDY1snRI2iV8VW250kXASY4lM23KELMmg2V4A/FwZ3y7JerggT2vZpZeHHrJSctv0aMXtBqXjHPbBkg1Y3Rej2YdR78yYsqXX05dzhehOCTDiQqZ/9CJ1C10wEseAi8Pm7gXBNN10Mpp888qebNPq07ovbKMdSGc2eDeU4PHBu82XK/BVrSqHdFDvpdzB6csfebrjDkvDiYi4RuLaWm+gldh9tDO4KSlyCYj9tJFIYEKBbNiIZPE1Wevl/ZzrglZqS70Gu6nAAIMgK5DJVov+ImbbZ2+6s2ZH723M/zEnjVnbaX35mNdCkqDFVDEfirWZVdJxGiwwajVCpJ8wVIu7C45v/S+tXNLPnt2ySZS6UhqSVhky3YEFHTKLm3DiEjWJTzhq3v63jZy0m0PkhjVpGAR73MD2UxqqHD3qqkrth3NmHpCtotONyxcZP3wi9IyWthLlrZRrvIhRaXFnsHPT3uvS8sb5q18cFjulPdevivfXlnx3sgZVd6aHP4DzJNxwHeufNn2j+P2Hz847ssdX0/K9FTGMI9X1mKMPThgROuNZmGRrH1kwlsjn3jq6bREBAhIYVLquC2qz3fHzKv7/82fzQe4SgGCIcI3j3tn9btJF86vPucoH5Jjo/Nh/LQnnWa/Kpl4oJoBaXSy0+k6oi0e9Kflk5d9N2v1bLawPxA4gYsNEIB/WRx8BGmaaVnghprsUOA++z9MnLjRPhlxVjz4yDn8vO/B9eb7z5fkrTzqKGvr4dFL+Lhdk7SFMqiBe6ByprhArbRY/566aUlm+ui5PHayZCcvKZwN6KpPqOjQoOmU9AmLXtvOXqwuNThnfnjtopt7zB/x+iHZ1km1Yv0lYi1AthOSjdxNhoYPo4x4rBVOh/qrYtX+Klsfz6soSRu6fuHQTs27Hs7c/dkbty8a34BpNf+AC8HppOg4I4hMLrNaYnCm//Z/7PzqT5dke2yx3Y44DdgSod10FQxBpxe6aSPzOzdpNeb9MXM/+3bGmurw+dQqEO/143Ly+2BPBklF9KvzwjTtxkcnn0Gt9963zjywSenltSfcFZ0RmhQaCc7ngC1x/K2nWTLjgtnoSysq5FOKOCv15cXb08fO+56fB4I6gRMOJLfqT5heLwxhdrfPalilEtQsRZIJxAbrSbUNT0gWEo1XJeaaVdV/RW4kFLIUah77aIL5U+T+9J4XZs44W3pp9gmPLRJ+fDIPrH0NahckLTRYrbdQcUsnLpx5B5vj7chrWmokGSJv0IfvfvCuB//ybG8ejUKE1PA7D/qkBiLNLd1bcHJWtgciTIbfuUarBdVp+cFlrhH4OoKR4T+gClIgEgrn6DmkFphckvC1Z89Xz0Ak3pVsfup5l1dYVuq1shOWQkhthZXhAIsVh16YCxJJ0DgwjIicx3TwKGZNEDmxbUTCG08O/NuzPIxLQGrAJR4iUDZ/9UbDvYcyE7cKwhGuMlw3fln1T+41P0V/MsF2Aojw2UTzdpTtAheKMZfUklUnZWc4XHMowNtVTcKQJPD706o5TguLz7+4CvUkY8eML2midXAf8SKuFlA4GLHxe+BBFAe4POCvH6QTWEHpcWCHifAWwsGrqhyqh/xJiUyqbv0uPwJrIOCsRAzlqykrnpvx7aa/h/34y+JKg3fCaUsZ9tkgTXhc4/qbBJFI4ADu0zpnixFznhqH3C+Kt7boOPnHBS/3JeIgvcvvPOgl58GHNiy6CQh9ZJ+tYFa2rVLVyFxs6UAc9XaTBpPy4DyYTo/gecdLCuT91twX+yG85gHzq1MHt+/doYGsec5jd2RX2KzYDoEQQCER0TjC4F/SQGeUmkv6gt7h8R8MaNejz46560YQcXD4xqXSbj93bhyx6flbv96/98KhoouPUtevHrSBcv0xkx8RZEIE6sH3s9b9/b6eKR1vj2i4tQGiTMLED74U+nRfoNeQJBKcEr3FXluPxzYvuxf3udyINYSDrZGtKpCz5jesRGBeAuYVgbK9tEaulbDBR3ewu5kt2Oz5WK6cZF7PGRUfGKpPJUo6B2EN6g/RQq36fuMlEQcxSFK7nrtjdMWBRa9O7JnU9s52hqhTEtatiLZIx06v2jZUUcnpdLIKr2Pq6t1bjNJrY2f/RLBwCrxMLue+g0p9lk1YvDv35FzspmMIFbdGo4H7Awb3NyZEH8f+oFa9VF4h2yLkpZ3mjtCuTHtyIaqZad7/xaIjew/0PF5woV3bqPi2JoMp+uDFcwd6tOhwqVF82+/XwCrGFyxwCUjBgqO6S/zN5vGL/3n2wNxcyBpJ8ZJ9+o8RtKHa+BVlZdXLaKplrfoZQARSu1Y+ODIXDwYNXTt39LGCi38/4ayEoiSA3YS25BCG4AAWy4HX65niy3/DJY+Ugqg2dh8NEImEwCNAi0PCDO/jqAs3LfqRytd89Bh9V6XUVMmTnu6Om/vUykK5YhpzQJSEiP9VVeZf/QFpi60Cj5ksdBlm8f/GzPkW6+aOt+CIRo7WOu5SZbkKAvDFC6vbA94qtCB4bOJMupY1+Xrnz0MkMpvBzYRczjkn+duLi5KPFWW/ftBa3M1ps9ELnOigAm1b/MuJFonQlcVyq022GGUziETIWvK62dyTnzTbiYp3Hq9W+6nA79TOukH9BgjffHxUzsjwwXf/i/OSzxbmvH7IXdLN5bLDumXQGplG4hQSKPdH+b6dAxpiqup04grWVqld9M6MdPVDWF0e2bRid/7JA9vKBU+j+iIrUq1YGsAM5mVFtoqe606f1k9s29Z1oPjiL6JWNxjnu9HOlaYCUPjuCMyBRfqlcgRg4CnoKoQTSqAcvjnqFLuslZIWR0mrPbiGn799bFApCIRgUOg4BNQ6gnV86npzznfOzOWl2LCGeZdi/gStm/qJMkIRwv5UOiz9xfSsoiri6L/kmYV78k/sP+Io6+a0O0lqgJiuvgBEnVdNBBAAE+FnJJ9V7AtwqOUNKjRwxqgoWMa6Ba0AxyMpvhJO4nuf3vJKy9uXPrNx36XT+4+6Ld1cDic24TUKLO6snP37QRsCKBH4DgpP/TeDDnh9RTIQ+A7Pqcmrf8gIUStxh0QgQpsJg/TvjZ55tH+rzilttOEUdoFiYoXsCp1hg64NhwRP84O7PmtJ1eKkOL0bCqWCF+N3cfANbkEsUdUnURlirPRdK9G9K5+YGICCcx2wEwWvuVbpmpdU5Fo+NUv5rzbDTEvShLYS0ieYVwxo1nF+NNR4jA9FwgiZoKpifBAFWfX2kGit8bfNS7tn5Z5/42d7QXebDS7nElRaQf23pEaw1olIMAmiy2b37NPkPX7nc5Oj/zlj9QMDVky596aFY17D+ZGPEsKj9uBo6fksp4PdGRkTVVZp61rutQ/YdvCH4Rc1Xi2kBkUFR9xYbI5gbZpoDGdt9XFlpCemJA1RM5gvnkCw9q/lHhkayKx8LXmr5yGWdfWEajHdsF7z/QEwibWI6j4EngEkAPm9GnUAkzGXWq0olCgLRw9Cz6DvcuSrgWtn1n/jIiL55Gnzqd6Lxj11TnG9objJgy5Inb4GCBAKuCbZ7I4WuHWiS2xjZ0nZRTCbGlX7cgf+whAFWwA5rnamW4G3dwUe+79rVuB/gREd5GCcVGrlDnH57BtrIg7lZ3+Bl/bE4Kg1SYE6c4Ib8C9XI+OMph3fzVo7EqJDxKfGVIBA6Fplo5j2wwmLFicvHH3zAcVzD/kB4m7QJQNwVCPDYKSJ0PaUbl3y9LifL5zYcAaWDZCMb61BC7n/UIK8hfFWoy2ptLh2qMr9nec9+eH3M18YetO8kbkXZfsbZxi8hUsraFfU/ZOlXEch9UsU7E86ET9Kg/NdoqD14ugu0+lYG0OEvY0xcdrWGS9spAHM8KuJQUEn9KtHvvsWoSJzgHMUl5f+Zo3SAGdnpKBNX7kJZRV7RuRgSvfKnY5bj7jKWuG1TGQjD56gDDSTTCwtuX+DA2zzeUw4hfas0xCIBIPE2J55G97qPPexRVleN+LKIpJ5ED8ljkHQsophPTx2+TwflUK7dT+PhYH8fE8wGDSAugIuPjDdc/z4TwTq49INbR+6kCsdt+b1KhDgz1pXePqgo/HWSayBq7KI38g01yEifzfUlCQzmKeZdUxq8Xz+ecs9l9xWKFLBw/7AmwTzIbGLzkpRPF5e9MQZOqiEN3lh3khqhGrE39a//4VFJIX613vwcpZMV9mDPcwjd/6y+JU3zy17W4h0CevaGcLcsUadsViUNSWykwMk0EsYdVpjpM4gtdSFFSXrY1endElu5ScOAqoO0lSH1IAOh8LBqsKQrOWke1rKTL6yQXXs6tUylpnB270hvmkPFUwJ3Cfo+Pluko6psHCNBHs231OoBFMCG1PcuE+vcKvx0eMcP0OM0MTwSPKgbUNlOnXqFLR+PFLJ2Q6zjoA08lcM71oEstXgplS+eiKmHkhNo+Id0UAYVINRCJ7AYwQVOnyUwdSL5zD7+h489793N1/nhFIp4IAqXoCqIKx9rbHh1yoYOliA1ePlpx3gbhSy0YwFCzjTS+7Z+xDOGkFQQqUMabOjakgLRegddLocHA0rKQVnmkPW/7s/ICLBTGjheerOclb26zZ/REG3xq0HvTt6zjPPvP/KsovFF+9xOO39LtrKowvwuq4GEVHaaJ3xAhag27u167ADgZqtXJmCWY9t2nTVoA2t4hsJ53LLKaYT73zwDgmKBpRr0uop/OU3Ph37KkSS7hu1M+UF8fQLa7ag+AVkBFfAe5FdjspThbknqH2OoDAaYY7hN11XHaLlMuQtK8a7MbIunee21fqhSUGBDHbSZb+gMdI5bh6lBvdqJgKQqsZ5f/h7mjgRNUhqdlxbcKYc0Ef7H9fpB6S6KEPquF3ODrtV1cgPstHaCERZs4Xf5wqijS8HaHyoldq10k0ZDKe5MTI+Cw/9a7La2fg1H0r8eqh7ivvzrZ9CXcqPxsE0eudMnXqxVgbfUtQ4nUmQaNr4CAVqCFr9f+amv0kdPCDcR9zOxPILzgN9Fo5b+OLfRprR4uv+D2+8hP/1/dlFXzgaPApHgzdvR8zVa5ggMOpDfJVIfAkDEGxGcVuwwD3/QllRO2oiA//qTT7kUO5fY47+Je9kJ4prC4wOKqi45QRrw0amiNIR9/3Z+slYM8P+hYBXwBKjCJp8BISYtTDcwr2/LTL9WL9pOIPX0ys6MelnRylhVFDMpeawtmHxiD/buXFzdhDXdHio3exHT4OIbyLswK06ayJflEcBUditjd9/86XmyHPCvHChYPbRGy5/j+QbjFvatBf3HbFpSq2kVeM100GrhkkWBILJbEMv2uHnXkIQbGCIvz+zT8L5IWgIcAIJQhzUDM708mPPyISQo//jxBEVG4rQl+WLeCPREVfpgi6zHzvdc+GYBzft3+9XdfxAwhpBrhHUB4aIkGSloOO35i1b6F7QlEKMGinCqM+MxFtNMSoSDUCwzBhEDb1yGd9/mfX16wlkwIC+H3KMkn0RDuFt40q1aBTivMSyA3NRowkgO2IPSyxSMh4fktTTTg8dbtchAZEKMflB4eEVgPhLsHgqtpT2oOsQC2OeFfDyvkIjuJXhveWc/fqe1P5LiyGN1+Vx4A3gVVb1MFF/hHbBOcrVLoFrwAnTiOi9iDXz8ZKcAZTli0Z5dQipZtGMwGXQcQk8DHwjEx+L4akTynASMAcEi0f0ysa6CTdpa14pl12RedkXOlCO1PT0oPNFhEzP9/16qElhZWUsFSUtJljC6l2maPQOj/tQ0MqCFfpP3wMCYSgkuHm5PMecFW3Ouys+XP/JhsNweFz9wJpZt9C5FRioPP5QqcqYj19OTF236HacXPxoy77PJhB8FBCsNpxAcD64bz4x/TT0+CxCALDsegZc9FwQnBG7Dx2ZSXWZM83YK6r5imIsxoWAtyflKagsm0NvJSIVhK6DJVotR2v1LCoi6rvAc63eeDYacaZI+wqVyIXEA4vKZUvpPWiXv9MwxbebXh3hBP/7OJS/vrK0W7a17EZy90WTQeEB4cCipLJYU1jhpEcmFKJtni9WF5YR53vJVV29ww8gHVByIMig02mfSrewsQwX9Jrj489KX8Kg2K4+AiJuHbqbV4r4c/WHkybeGJVNBAKLatCS/CZWdQVwIMipLHiUKkn/cbZUm6nRfG2ryNTT82MXztxXqgMsGFZOYHSzVvLXy8K1xmNBB7BW/v/aJV75RWtMLXRLuQTvCD/mKG2zszRn0vZLp3d//vN35xtPf+hAzLSH9yZNf/jA97/sOrszNzPjsOj4S5bbRtybZYQIXk3uB/Qca4vPyfqFQGBBCYTyYDYlJ4KeHyvNm4wACGlw0nf73TxwHI8jEqlogagvrN/ipz/YZy1qDsswArkER0i+GFQUbQNZ8uD1YB9SO5RwqOknHU0TEL86tvue+v6Cm5GpxXvBa2/xp+emrKC7GT5rHRblgMcHk8r3i/DsRE72y/mw+kGK0JH2oNXiPrR6iUVrTfs7C4IbUhlUythNbTvsivEiGJ8iY0svODrzPuKN58dsxS0HrJg0F8V8rj90pJc8Hoh4fYyKcKsKLpMGr3XnumRQkKh5X6q2hovQGX7G62qIf3CcDWSp/o3BgTu6W71QUTT2kb8v/RNbf8ZlDph6q83XnjXpjmkfvdn3YvHleRVWKxlTeJ+r13Xlt8pM0JQVJu64rgiEAKSRIFcJkDh2lkTFipfFWxAFPdNRHnEJGzdlzHtznuLpccphDS9wO1wqkDkSHq28cyGCNgTeDdGzWYdPuujCIUA9eD1l8ImikDv08tgSBKc4XHD2H7eteHbtpC2bunLQzKR9MPXVzN2xaX9fPLinedSBXZb8h+AsSJEx6hlw+LDptaxpZOzHLzz41AU/ArHnJy/PbKIPzwVq0e5CSKIlkCrsDnVXSc7UWxaPfRMB9rp8rZ7WgzgU+mQiEMbjr6xKgTXwp1/txX1w9loOtuinMaJe005iks7EmkQlfkb3Elhn1JMirfjr2OxYbfg38KCj29Co6iaaH6ynJBzgUg+V5i0euOzZdUu3v98AjIT7x2UQ8UI1RTYO1/gPXupx7+qZY6DQPKa4oL4GMUbUbcV3J8Jg3BpLQW7grhR8ttAIuiTh5brnnFZ2MPvkt/esnTV75idvtOA10Pig9LKdWxIeXDd37PeHf9px1mM3IrQSef8FrRIMEuSoSs2Z3jage999QsKUh74v0sj9/ZPsE4c++K6rvxLUAnSqKtAHNAR6fRwhntZk95qt6z5eyBHPNznBYKe+yX0Wj3t3t6XgERy2h5EodJA2ag97SWAlBrGLFg6zsnwEQZmsOrjdRGh17bJdlZGF8GeiDSdIFDJ2BE2+ejxq5+hEcUCnXt3XPzzmMLn3kAcDIRJUyJe/Ljo/RnDBxwPSM2gluEnrJqhM2JKWhFZaE4LySWdtslxA+Y1MbOiU1FZn8R4hsIqQxEF5dZAsbq9L7B3bpHj+hKmtB8e1rSQVJC09jcfRunet+bb9+ad+wJtwZRy58xlwqGCtBM4KR2xVjQg3io0UbWUDY9SvFYr7V6siu6IlSR+nDbuxyF7RDIH/WuYqTlYJB0BIWcxfcCmLccI5VlXzQPOuOz6ZuHgAmuPz1WbWsENnPNYbcN4YAx3axwwMT4HTK+LDG9gNYhh6JByrVBWLgak6k6jpeEaxhyEQBqQ2XpRbj68aYrZ4FBxd7W2Ie3Wv+eWR9XC9WiPyP76EqkEUzwmYSxlc0Y2gbCAIrBC7dJSX9Wpxw7SKrN1Dsf+ih0U3pGMftYfAU4KMwADH7IUaqGbd+MEwLCaYFXtyOIUGwgDKhiYOIDUoWPHow8J07WKTniPiYCkpEsyRfPFvhpWsSXzT5zuWFIw5rpRCm9AGNTtSdyAR0Bp6ixNLODSlwXv2WmMzqzUXuXQ+H/sEeG0zAtGERiIaKwT/9iZGRunaxCetJOJIgUqEfhDHl+mo6efPmnfetuTpr/KY6x7EbHaj/qAGEOLcdGbVYoOEZ/bIU17r7UzS3q7DNuM5sk/jKAOFMgUDASvD3i7WUqGIg/pXJ01oI0FdklvGN3qlqOTSSxWynWRJyCDpdJ6Dv+DJ6ZIP0wuftNquPoMiTQI24nEaAJoBnVkOKQRADKrX69a20UWpXTp1WkaOstedilVnoH6nGyAOHj5m7aOjL7dNaDw8zmAir28EsRHoBfNBk9/KIUka8F2EUBUgRohD60Ss8viE+wi2TmHUR3vl4FQuptPoeoc12IVXyfFFP/zKuOpC8JDE2/z4xLOtYxqtZGFGrKvx7okQsFAb9AgfmmewdpFWPTiAgLe9QBUFZ8TpwtCTT8QBu78b9kJdB130j+8+vWAV1ZlRzfuAog3SvQG9+o7qKoWDAas6vAKOjpEETaS/gGphmwPrx7gITo/HbXN5ELDBQ9cUGIHGDnSNmAzBJUfQiunm+jNEtMK3U1ZtaC6a9oMh6DDmQdyIr9TgU5ugmmt0FCgaY0MbrwwLKgoJIeClMqH5KbYAEB9b9SThxUM3JDWf/WrahPMpYB7/zxAIDSNHBizYP528bEvzsKhHm0RGwZKIE/kCYixhgK4Mdc1f4DqE7JQP465qwFZD4QyfASAi+LniCQ8z6nuExf3ytznDSWVgZp/J+Eo7/veZfDn9uRm3GhJ2MYNWh/pdYHFX8tQEhV8RYoIYiJY4TIAP9uvQRQAPqaZuvL5Y110fc/yhB1MHU0V+eHid/mswkRTJfOdf82IiYnonavRWnP/Q0viEgolapdcSEHFiCOk95siPw3S4Jq5OY3ctKZAL39Q9nih8Kv24qUWnv7ZkRhvsckRt9RIJ5UebPnhovgBHfeeXiHEAaCjTqhIRYdI1lcI2fPTMUjKGiBlgHv9PEQgNHsMxTbJqHZy/6d1bGnV4uEtYvJsjJikx8CMkXfa3DgrnzlizwHwKIw/eCI5VYKzRpO0Z1vC9d+ZvvnW00JMfDQVCVk0+hwWEEEDS2X+bNLCPMXGXZNDrQV2kTnnAmTlQ/rzX/EXw4AMKIjzBG4NVWYwIN+l6hifu6nfL0BvHd+5v9UeBqQ0PmEiGl8Zn54y1x/u17NI7OSKxGOs8Hb3MFdVymLiZ+JqhCZ6RKqNxJsIjKQ5tjd5hSBKpSqWjnfEUcPHXnpp8pkNis16djNEWhcQ3TmOhLCFvgK6CNxLiLuBH23yeiS68cE7VNDCaNLfFNH5u37xNT/NimEj6Js85qMkYJ+43r0IK/RE+ONgGONEDwE79AAP9DYmHxAenTB8/9x+De/yp9Y2aqNcaSHpZi4BgOJkHDz+qlN7XwieBVDBZDwLAAl3l31joYmowqWgfSEPSWaZhhk4RH2bSdtZFHu+X2PovGbPXDiMzKl+U1wqPEwCXiIaIZDDOZOxesLFfL0P83Jb6CNiltDgKJotQc0gl8xAsvE0IDz3ZwgELfQgeIswqeOh99/QuEQlPSAAABIhJREFUFsyoAkfPCKNR294YVXp7fPMZ+82b+q0fPNhFxJFeT5BvGh8iko+enp85avioNnfEtni1rSlaNtL4oDmMD8AhPBE8/jHwQhVD9wkWvlikBSP/0D16FoAdY4l+0FILwRAUkC7qQi9pgWCQwmFhdHvy+dj43aoywMUJlm+mLs964JYBHfuaEr6J0Rs1IBS8AjAAB/PBgTkhIwSNCW8X3/Sb5g/w0Dhy/Ab8ZMgQFaz66DRmn+jGx3sltkj5asrzpAaT2yn4k09JEBpMfXh/UZiYTO95I/L9IyVSHARYLYxljpWWtR/OYBhIkhDX2gfiTjQBlP+BF8ztLlhynwJtPISXlTYrAc7RC0KxJ4BxwbTjBaY+nkeoh3HSG4ACWMFiP8EEjpSEo9haSfy2QXjMa/+cvhrvg0PCglzdsYMW8yhUfyIiwYcT+rBXV7e5XHBxWrGjckiB19moDIo03j7na5eYGSIucpgIDqIfHWChPUo8o32DCKCpzqtURmr1P7eNa7y13w09XqWX0RAE1dupH6KaMWsnf7y53dEzJ54stVTcU+yyd7Tg2Hk52saaH21DDmCjlCtHBEd1PKLxo6SH6Zhgx3hFYDx1GJFoBbYGrbbEIGnOmzTaIxjLHexSwacZG9OtICggKf76U0q1uRq4fGqKxVU5qcRh718seCNssJB7uOEW40FjQ/yN4OBCAL9xBoT/xj0sZFgcjOp6D7sUExa5Jykq+s2vJj33FW8GTNNvog40y4R2sx59tMLjbo8KsJFDS8s/TsILtIkzhWPBujV3zf/9gNnHxlkdNabeDpkJMVkGymVwQvlaVfVvrF3Y8UxxTle9TroJQVs6ny4rEpITmnaxed0Son+Q/0/5wdLLZzvFNihzOpyHGsfEH+/cqtORVUOfOB1oLKXahAbuXcM3TL8p2HDzwfJFXp7p9Y82984pyE02GAwdL1sqWoAgjE1jEjva3E5IDXQeEF22lJ0oV7zWznFJlYUVJXtjImMPtWrY6Ai8B3zcGA0TF+aS8xqAqJ6FTMAChQfyw0TPiIArKgpvvVRe3DbMaOyxJ/+idHN847Y2xRtd5nLIThAzaSi01xRvCNOEa3Xlh8vyT/dq0EK+WFr4c+voBLsqSQdbN2ha1LB9m7Pm3oO5N261dgkPq4gjcJ/PFbm0+4O6jXn77cQzuYdvvVxZ1DnCFHbDibKimBtiGrSGq3i0TfaQBiCGSTpvZtGlY4mRMSoOph/DnsnJxlHxh3t0v/EwXi1e9RoPf1AMPzUHWgStX/n5B/9VTSz+Kz2pTSi16/i6pCSy4OJFURerEfo06+po6YvuVzubCMIQM6pZhmpnuJbrq8Hy3oULMVZvEcLBMBaeoBMfad4Nv4IkmG1TOiOuGbl6X4MUC1JD1S2CCQTLXV2qblb7cV5VDR/s+sp4/vIlpfDSZaEczxJMBrVHpy7iw7feE2q8AjVwxpDCUsiQQkhahzgCGembq6wb0wVYyTlTq/6M4Nh98agRb9RV7JUaoX2zcIXM2dXzVP2GhE8dx1/5QZI7aJv/H+y6kJy2/hwbAAAAAElFTkSuQmCC"},{"id":"USGS-Scanned_Topographic","name":"USGS Topographic Maps","type":"tms","template":"https://caltopo.s3.amazonaws.com/topo/{zoom}/{x}/{y}.png","scaleExtent":[0,16],"polygon":[[[-55.9959409871,52.00107125754],[-112.02896100663,52.00107125754],[-112.03994733476,56.01308253302],[-120.0049439862,56.00592357111],[-120.01711631014,60.01202439709],[-132.00196823895,60.00239237126],[-132.01208445818,63.00193292546],[-133.96882922149,63.00050478005],[-133.97240257168,63.9922484722],[-141.04429430438,63.98726254018],[-141.06879354491,69.92045693283],[-156.24893170976,71.51583202984],[-160.44570905351,70.83527373985],[-167.08145124101,68.42906280103],[-164.08218366288,67.03913532024],[-169.01504499101,65.68268604273],[-166.57608014726,64.50777504773],[-161.82998639726,64.0500622981],[-165.08193952226,63.26030016403],[-168.02627545976,59.7862264253],[-162.53311139726,59.73089435789],[-162.35733014726,58.55904663221],[-157.83096295976,58.31752983705],[-158.00674420976,57.52404350658],[-168.22402936601,53.51022153947],[-166.55410749101,53.14277307072],[-158.77578717851,54.88541314654],[-158.68240338944,55.7496444805],[-156.55105573319,56.00847621073],[-156.15554792069,56.7746616888],[-154.70535260819,56.14336689443],[-152.07412702226,57.37034511851],[-151.62918073319,58.22653323066],[-152.00820905351,58.98055685754],[-145.98770124101,60.24740887373],[-140.38467389726,59.48634241018],[-136.53945905351,57.80610084736],[-133.79287702226,54.83482554482],[-133.33145124101,53.14277307072],[-131.46377545976,51.69838238021],[-128.52493268632,51.74602265442],[-129.79385358476,50.90159054062],[-124.56436139726,47.49785657441],[-124.03701764726,45.48627362525],[-124.69619733476,42.90428451679],[-124.49844342851,40.3414647251],[-122.80654889726,37.53929308709],[-119.99404889726,33.37084692374],[-117.24746686601,32.54119524801],[-111.13906842851,31.19770451575],[-106.70059186601,31.23528720858],[-103.20693952226,28.64618215851],[-101.84463483476,29.81580068657],[-99.20791608476,26.28743998885],[-96.79092389726,25.75431753335],[-96.92275983476,27.96911213371],[-93.47305280351,29.68226300815],[-88.94668561601,28.87732407469],[-88.61709577226,30.17736083469],[-86.20010358476,30.3671253082],[-84.96963483476,29.43379356715],[-84.09072858476,30.06332630046],[-82.97012311601,28.95425748047],[-82.97012311601,27.26823750278],[-81.25625592851,25.07956298739],[-82.09121686601,24.5610471236],[-80.06973249101,24.76073298597],[-79.85000592851,27.11188091684],[-81.27822858476,30.70777424386],[-78.99307233476,33.20554049136],[-75.03799420976,35.59830000028],[-75.85098249101,37.2425160052],[-73.74160749101,40.4585957587],[-69.89639264726,41.60224497127],[-70.68740827226,43.17628724449],[-66.93008405351,44.69516042167],[-66.53457624101,43.08006996122],[-64.20547467851,43.35229243812],[-59.50332624101,45.73220792131],[-59.51431256913,46.24761804024],[-60.00320417069,46.25901313529],[-59.99221784257,47.24505773341],[-59.00894147538,47.23759898478],[-58.99795514726,47.50266941922],[-56.51504499101,47.50266941922],[-56.52603131913,46.74770404019],[-53.99917585038,46.74770404019],[-53.97720319413,46.48358117386],[-52.49404889726,46.46354265729],[-52.50503522538,48.75360583388],[-52.99667340898,48.75451123442],[-53.01315290116,49.99551104004],[-55.00167829179,50.00610367548],[-55.03738385819,53.74720613495],[-56.00418073319,53.73421061801],[-55.9959409871,52.00107125754]],[[-59.50126630448,43.7495431608],[-60.50239545487,43.7495431608],[-60.50239545487,43.99999882251],[-59.99839765214,43.99999882251],[-59.99839765214,44.2494016836],[-59.50126630448,44.2494016836],[-59.50126630448,43.7495431608]],[[-155.95024091386,20.49523373356],[-157.3267518687,20.49153389084],[-157.32902509355,21.23181053727],[-155.95251413871,21.23549220541],[-155.95024091386,20.49523373356]],[[-157.64488202714,21.24845058596],[-158.28534362719,21.24673774522],[-158.28689557694,21.7499618541],[-157.6464339769,21.75166877943],[-157.64488202714,21.24845058596]],[[-156.12602216386,20.32469602374],[-154.7461696274,20.3284088686],[-154.74174482011,18.87578125335],[-156.12159735656,18.87203473488],[-156.12602216386,20.32469602374]],[[-159.29077130937,22.24504086823],[-159.2892966564,21.76857042389],[-160.28916841131,21.76590592196],[-160.29064306428,22.24238530626],[-159.29077130937,22.24504086823]]],"terms_url":"https://caltopo.com/","terms_text":"© Caltopo","icon":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAA2CAYAAACCwNb3AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAcppVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+UGFpbnQuTkVUIHYzLjMwPC94bXA6Q3JlYXRvclRvb2w+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgofPyfmAABAAElEQVR4AeW9B4AURfY/Xt3TEzdHYMk5I7KICKILhwE8DCe7eieiomRByRmGjKCAIHhgjl+PNUc4UVZEggKSdsmwsMuyOU0O3f3/vJqZZcPMgnfeHf5/BbMz3V3hVdVL9erVa6HNhEciCxS7VtBJKvsDJlWUxCjFa8tdk+6oD/zU1ZOMhyttYXYmK1EhMlbgfnudQWgd161y8+jRnhDZgt6+ZdIkY0nU71N/ijlFyjBneAMNTX/3lSZH8k51u1RR0i3KFHZTvrUy9qy13NWvVbtebkWJ0agq0yusdH9+zv5u0Ym4YgfCw0wHY6Lj93zw5Iw8fz2C2WymjxKo91q/U8xmwGOugufhDUuaFpcV9XJ53T0kSUo+VFooJIaHxSXGxifbnE4lwWASL5cUHRA1YmmEVn/Crsjfx2gjD26f+dzFQJu16wzcv4ZvAWU1AXhUVRWGvrSwvdNj73uxorhNpGTofryiSDIJGm2HpOZ9y1wOKdxoYnar9ezlyuKzbSITbSqTf0mMitvfuVW7febBwyp5mykpEtuxQ2aCUIMOhEaTH/qkQHEOEgShHE801wDg9ZNFELwiY4lhXmFWxbqPVzIgFquGWARoYCJ6zRsz/YS9eLmLqYUCE6SanVDQcZHZFK/S0RQZ0a998p2bhz+zK3XLFk16WppcM2+tK3+bzab9dXqx4lmuoH7G6yc8BHQ8+euXPUq3sNiI/sm33vniX54MVr/AUlNFlp4uY+LFQatn/i2nrDDV7XGnWEQlslRRmFslcFSmEUQmW0DSCtEDkkYjaMIjQP4K00sSixAEZnSzypjwyB/ijNEv7pix8jvKVpv46F49qQY8dzw3+eFiS8UTZV5H3wqmGB3AFpfHwzSihsn4ZjYrANMIzOtVWUSEwACHiH9hBItXsbUMiz5q0Bs3Z8x68U3gG8Etms1mhs81EW31+Xj2/15u8ePJQ0MdLucjFtndzY4JLGcKk71eJogiU1VUSeMjAEhZVpnBIIh6I3IoLAxwxSoahju5kTrjBze37v76xuHjj9M4ABaCqQoeSRZZnKLX6ZnL24CJAo29L+HndZcCsAUAAzKoJgNTLe5wfivPUgdqS14ev2cTvOF2o1b02uwNGQawdhIxcEzxMlmnZS7Fq6/9POS1v02rIKN+CVTmRP0BMK7QFq9f9TJFr2Gq7KlbPzghZhP/0+XUF+c/0Hn248suM1eHMsDE3G7MiwAABUUEshHXlAVZNRjCNRgS0Dv+qEx1uj2YTgFI62Iuqk9kkTkO75A4Z+WQ3gvHfZPcptPYDY88fSGllkQI2jcqj7aIWAmeboDnEuAplQGLB/3i8DBFgzyyCiIBxmvDIjWEWVoUdCqKrLhloKnMLCB2C+ik0F7SO8yl7d1yxrBpf14zd/6Xk5Z8CGRk1RE/KCy4mboltYpZ3WoeN/Orw7tm54tyhMXtBAFgFDAk6LpK40NEIAJ+ozFSQ2oApgMPMbser0Izb0MZG7IC6CaS4J5qObFv8i2Lx5n3zNu4mIgjNRVtod8EC8ZTcDMvuqUyD2c/CrCOPsSKrrdPADb/N6bPrQHsXoFh1pCSImqTEItISuL38Ac4RdOH/tII1voncJYjYAyIO0uU8dqSv01JEWWR1w9YatVN17x+jLEqY9xFQvZqyYeMKk1wj/mjVu68fPrjLE9lhzK73Su4vV5R0CjAP8J9AKZKQF2S9JJTVQQXUNCFqaLfdI+eUz4BhVBEofIlDoey11Yw6LvMX44OXD+vawbUJSKSahDU/AkuCrygcVP7LRy7cmfB6Y+PeiwdSh12r+hRILUFFXjI4ZH97eFbAxgg4RRmg5Sja9As2uDwiETAohe6sNPpzVbtHQ8VZ6cPWDZpM4idIz4RSU0grlz5iCNdNn/9bpOOsx//6ainbPlppyXCYnd60EMZRKFidDSB8aE2MRoamx8eECvzKIpI8ND4YCwlEWJGVETF63B7TtnKxJ/txYtuXTx+16a8/SYiDhAK56KiqoCSiFOAygHSH+OjchkAWAXZi5HHyISUIIFhJlGPAaREncVFrQ/q5GPgyxMo9tu+r1a/jyHVrRMzRjdbTRu2MdNbOa3Abge5qSAMkRaGErQoTO5vSxy7feWADCAXj+w+4ayIyL6UvWfEO2vbE5EQ4gWpVWBmM2+uzYxhG391l00rsNkUjax4UQ1xDvpw6glSNuQtVEhcAcQrSBr0Ldda6f3eljdyyJrZu8+rqoFU2QBSVq8kQBxzvtjS+Lv9Px077i7vU2FzeCTONJgWCE9S6zfBQ51DGXw4zmslUaPKDrd7l62g73tvvfVPah+wUBbQXSCBewV+Xu/fYAHgCYpXlURje8HA+sY32U0wpw5sRZ2qJ/072F9PtVWPfnv9yaNGaVFc6b1o/OwigzLW5XC4RfB+dIS4YNBEtykLvmX6gMNx1SFoZtykjJhcHRiJ+4xiDTt5/uR7lDc9jasRVF31RDih3r746XVnRPdYq9XhAa8lFSWkFYeLs2rw0PxcQazqVft+Q0hLQEqJWR2ub0rO9Rr13OS36AmQ0pfhyl/BDyP7cu/WLT9WXI4CIC6wE60XyB0KYYn7EQw0NvTxDeeVSmv/ghILDsJ0zOlxHbQW9U1Z9sxMypMCY8CVfpCAv84TAQiAsQT0irHGMKlnWMLOlHY9222d9+LnGF0xMJjXeTeqgZelObB5s2fYaytuyLWVLbVUWsHSBHDF0HMBJIdAgaKmyiIYhEbVajRQHkRonRwhqlVe5yfK6Zhbdp/3WJL/+tKSxygDIUEgI36T2iU//PKSBy54LROY3eEFonGJEchT+5sQELCAW3lFgoVggiYlKqqCZTDRVfAEBGfIqpdtDvdhW3HavS/MHoacih8GXigA213PTZ+RLTj7QP11oz19KMLw4wcWBjLDarIKHhLG0A5kiJlQRblE0Yii1upwsNPlhdOe/eSN6AxI2dB6aPB+/c/ukjLrRSdVrSS1l6K8rWIbzPxm6soX9hNEWFQxsznkZPzPgL5Kw+lZmTzHpYL853NVF1mDvNDdSaIETdBPyIwgJphMrLFoLHeJ4gmnwJwGr9zIpnrbX3TbgZIYI6gdwSog8QrVRJPnsLELxbljcPkWkKBK6hJCULn9F08ty3ZZAI8kAJEJ7+okugkVX1Z1oqa9IYpFSYZLxbLnrB4EHmEQOhaqzuhsu4X0GBkaJBkT6iQiEp0gSYXWCnZe0ax87cSJz57s0AFrelriMJYBK+XML9+L2fLj19MrXDbAI0qygppqQRTQr/AE+CFqWmjDWEPJdKlYkc/qYTvQKkrHE15rtBPGDqjaCqmstesg4GA6BCEJHouWxR7OPDwCt1Zf9wTCRRwZDmVFig8Ll9rronZ1btd95Oa/jT5BnRq1aZQ26XKSbE5Pp8s/VjKnu4dvfqHdj2cPDmQON1iqJjRxQGUgztwjIrG8fVKLme2bdP/IPGRIMXV4h6pKmzetGCiez1ybrdrai2ReCWGy53q3W2aXHRW9xr2zoc3GR8efMUP6ZkA4E4H0mDd6WKantAMQ2wOWGxQejp/YTGBaQXNrRMN9PVp0WnRrcv+daZ07WwmeV7Zvb7Dn3C99ThfmLdxrKejqcblBJCwokcCiAQOf4AGDaPRO+ktpKP5a/4ULNSn4kQFt4fDpQ8PKtUoscwIeFfDUIg5k4wnEoej1Ok0PU/zOlo2bzRvcJeXQsN69+R7H6q1bY7cf3fH40aILz+W4HbQmA20HrwmcRayElatMqHwQFfsIhNokkiUqp8/1kgJSA7JY6qCPltvEN5n15eRlq34CgKS7D/lrkmrub/Zt6AUsQfUC/5/u3W+v/1LZpbuLNaThk/SAhTRIIh3aq8hi1/D40sE33d5zyb3Dz1fLJvQHp8X11nFbNqTsPPLz6WPW0nDsitCOSR10AoSwP4leu8Sky2X5t6HcmQw/cVCdHtU93eXlZlsxlEhGHV4Rmy3Jxrivds3f+OddKLeOCvvaU0cOHFiA35/Qp8u8EVuOqRWpqkcmGIMyZEgGsczlZOWSnbj2ayBUhaX6YL9YVDiwFGZrvi4LNbywNGNRpmkhmf6xZ8HGh/egkvfxQaL+q5PvvrsU36v/vHZ2sT3/3FslDrsCI1ZQgqXRYW4vc0ieHpM/fb2pCAEKoSzTfhN2d1RYKtB5iPI6I0vN/ZcStc23m2A4iQsPl26LarL7js59uhFxEAijNm3SHkg6RcThXfPrjugR61bcAAoH+MHVgf8S2GjmGkat1iTLLvdtFtlDa6ughekmdhOUOKhVLWOT5hBxtDA/biCu72+Q97vJpFTjxrTx+S1ik9ZqDUZSF4Lit695US2DmeNs8eVmNDbG2BKukt29fOZNpR5nV5j98TS4moaMqEKR2jJ95Z9vuYsQGnsUZh2pRfhJ1dNuvTho3QS+1zPqnqFPddSGV0Ifk3xlqUTNhA5AiiisyGG/cdimpY3wVGHpTF51eFsYiLkP9AcMTjWDUrXiGAQY6BVNG63JPbB///H0KNVcAx5mVvlYSV8+u+ztFrqwnxnUMN/WSLWK/D99kkWQKwXFcPLsmTaiVhCiI8LDWJTRqDcYjRLp+DDaY59FhewTvFho1ZrSupX+nncg/kCrEKeiIHU0xSm3xbecuXPu+r7rh43JIqlh3mGWuBsIdswnvb2+Z/rnW07+cPEILfBY8ujRQTnUFfiC4uCVx/+1X1fALHDbmnOFiMvwugAAYiIAKRrbHs0aNfyccjzOWriBhJhLv8AHc7jlFt9eUKwx8uNGfPtBqWaBqVkvYQd251miKbwjPfnm4Bd8YByCc+glEYxegCG2ZpGqKzzwag0G1jKu4Wvmu/5S2NmcqktPM7uxzggUUQm2byaud9Gzib0HV0YbIzYzgx5snv7XTT6kZF6HRjWWlFfcHMhx+Kefm5TarTGcJEMxP5IeOokl6iP+uWHgYyUshUnp5hrwMLNgVoA7vI/Nw+K+MWFfHAyAxq9O4p3ARnIxNkTPFeVqxJYxCa8PiG258e5mXV9INias6qgJ/6CjIfJiQ/jTKFBtZOw0wJ6GvTj/ZNSp8ve5QdDjQ7wLi9Bw7W3RTffendy32yfPLnmOWiDCOHDKJzWIWw1dM3fZtuO//LLbXZJ41mUnNypGUoW+r+uETmKfkLqLPn0RD4W4DXFIrA5JItRJWhp94EDTsJiKOwbegVUvYwsWLKjTz/TULXzCW7VsfSFaZ6gAvRHL5WzdP7ZcRPGGaaihKlR63MStGXszmyOuxW4Dt5ZDwsIBVGVNM1HPGic2+YiKduqUGhTp6VkCK/IhocC2x3DvHp+ptDY8PpgE1QmI7R7XjVSWUqGlvJlghHWa1jscPfjtGn+wZlc1ko5l2yy/0IPkdj5CqJEJF60GlnFYPFpxN8QSRkbl/hTBYVHVaK2O9WzV8SZp9+z1L9eubMOOHeGf/rqtTwerdVShtvLBLNkmwRUFLEmEiST4RNau47dck+kSSp7CtDqpoSxYbghLmLdtzpoXd6ISkhqtBg5UzP3TSIdlE7as63X7kgmvHnaWdK2wV3r0hjCtEXtP5b+lwesk78nLeczicQFryD2i/kRbfY3j24dERtTBicZ8d1pph1mPncL1TbASkYcBV5+q187VL1XQFNtt8NPgyUPqzKtb3msDoy2KYlfA7+JVvRzNE0hbjBT1l4Y9dv+B1x6fxNJTU0OCnsJSlAwstVtFJOWcLy30YIqx5Q3vD/ytqpegpiswYbvi1f5QcM4VeJZVVuAppi6AcOpwhECmQHHsi9OtgOdEtcf+n6n4TmftW7TzZlcUsSK53KtIZDEOUrOqeuxeWSorq9BLJAYzs4tE9mYGLXb5BIzv35+sEbSj+M9Rb6+92XQua062UDmk2GmHSijC2hp60whlri0BLr9hwItFkBRpNIpNmWFr1+ZtR30wfm4OVZICuzwGWD2QtpnDdf+auQt2HP3VfMyONZfMPEbRoDqAFxoRmiClIL5Y/P51+kfr8cCRgSboCr7UBhXrDzwUWYndEvvl1+mReG6vnSdwHdh1LrDZ5YjYKKY4XXpy3KudYMORnGDMsaIp6pz/4eG9+9s7ZW9DqHtggcH1fWCgQlt8UcawrP5CSyIu0EzovQ7zArPKzIyVll7OpU6YwsM0vt29uv3FxolUqZfYPbFN+37lhwlrC0g6/0WIL/RO8GIN1zYirttl5MnIMAfN2TkrSyU7p+xwZju8biZEROrDMa5ByANbRbIUGxnGEqIidFImTI1UI9QWcep7mzpl5meHaXUaTaw+qqilLuGSefgT+/D43j+vmzv0QkHeO0edZQb4FcENglwgqOS/lrA5S3tbCqzUUhuN0ZNgjHp69/yXNtPOQDJMt61iBip+T1p15JurO2deOPvmpwWnejJs5EgaiXQSER1VI/SRLNotlnOsCeKL9a9B9x8sVW3M4JKtMYq+tWsoTABnAIoI3suy0/TrmaMDANn7PTfztZbPelcNVJ+aJbBBbbq+ZxO9hyEGHGguCIUAqWUlXK8z7uT7SKijwFYebyfsBcLj75VFUrX6AQtOF8CZk6kH+G1zCtxSMqrlqPXTj9w3J9/pjck5+LzV6w6DixgEGCRILajgOgDlmpliJOPeQC1hBqNY7oF/F19ehaQUDbwzWaFUOYg299Y+8EQ51kA1PHKpPtzjI7/m0w25D/T7y7LOTIgig5RaXZoFGobjI9xOw+Ni476Q0jYt7X+5KO+xtnOHJ+tVsVO54hG14DqwbFX8qjMU9l024ecoKfyDLycu+XDjkR+/e/3Dd77b7yi+UXV7PXzjhtTKkLAHWrzyzRUBAIbdGikcA9CM6bcP7N570rqHxx5DLhFOa0JR1kY1fbRPavRbOnHCP7N+eeECc2NmvF6dRivCIQ6dVaRWkdGsbXiDtU927vViGvsHRiGDS5orrV2HvzBWWHLwdHO/uyt/PLWvCEgZidUC+lRN9fCDTrNKfodFLuzwFufM26+q6T0FwROQFv5svi+fmiW8P3H+SzXu13NBKizt5oczqYeH89N6fI4g7eJFibWIiLOSKTUF/yDh66ndx6CxX0P8a2Z9Gas/C7jkd4lvarPmnYTnLVc2gnJ7SDVohKL3hNcerj/00wzUM+vdkn1kLq9S1fx1cwJh6ZnuT9Iz51Rvr77f0i/ZJ5df0Mk3K9hdhTM9VQKbGlZUWimKuZ1RTHC2jWKlj7SfOfzEt//8buT+RZt79F487h8XvZa0vLJyGdwc2g55btafiIZASVho4D9O2TRmOkfTsPgpe+etfzmLveWXGmUkNUiXVB9at7j1iaLzmw/biwZUum1ctQNBCm7sBxhNRrGLLvJs15btR77+2JQd26hp4kpXLCl057pNosYne59o2dLZc9HYo8xjaa14sLdHDpNBEje5Kqr3nNveYeayKaQp3E9uNVwF9e9+VyumEvGc2x4jhtbHcVQCxwBo4VqU5fN2/i7/vNbJFVUSI6FmUxXhjsysLvtBai+hU2aojNXA8f0kWKnN+mDKwPNUrDexrpFhemK9OnY6fvzyubI8puJQmIA9iBCsmPxVXV52Xq2Y2X3+qIOHFm1OB+1K5hSzAslB+FQjEQFa8trVCwvBOiQpSZZK3A6rip1VLHHsilZnitPpJZOXlUZodBcahkcVV7isF42SvvsFe2nDS56SH/ssHL9+97wND/35hZn5Lpd7YokHqijWAzjAQ6ZhLqQDfJATBawMWPPBWwfre0HRRhtNYpKo294uvuXITyeZswG5iMETMy5jrTHaJwFSVkwcvzc3a/UFwaNDx2F4kDRwV1YVDXbT4U6UHNVk7UvTV81sKwguNipZyzbtJ6K+5smqMVr/44sG+oi9Ea6y+y0uaDb1SGLghuR0ueTtpefu67vw6S3PjJjxWFrTpo5giOD3SbuqND2wGZ1PSefqVK+Yhk22l+fysxN1MArZCDTMLzOCITpNOv86KBV3iV6vnjLqEnLQQumbCSiexJl3pFXcMO/Jg2Cof1Khc+BuHYODPy9QTFQqvR4x2162ZfDKaU9/PX3VBjPWI34JSTK7Cj8y+KG6DH/R0F+kR4pGYmfovU6vM7XWhh3pG9vs2ZQuPTpmLX+rx/dz1t15YNHrT+2a/3LPnOf/0aR1XEIXtOKcuOkF85dTVjzTPizhTzeYYs4nhIdpZQ3cjqHPYQwhJEio0F4VllmgDxCHGGnSa1vrwktuDEscn7X0rTuIOAh4UqkweOAYGd5H317Vsvu8kd8eqix66YLHphPdMihE1Higk5hMBm1yWMLJGxu2uHHbjOcnEXGQmwkrgwfvdUMcVXMQetRrZenYqPFXTRRoBIoXi5HQFELFyKcJ29vyT47C1FWbF2U++eoLf4KG4+Vckk42htorCA0NVrU+xDHpjB3JggUOFxQILtowuZGilrU2RIZC1Ppa+k3PiGlSAb3W8EGEXgeEAlaFSIS/tHdHG9zlXhc7UJn3Um/z6A9mbX8rjtRHFFNRX9B1VYgqq25LDqZGNtaHsWbayAV7zBsWna16xAdKYljNsEzfJtT/jZpPa+jpw7ZsCB+1aUXU5tEzv9+Wn991yRsr/tpEY32yzGnvbmFeg42GGDMaBmNIGCY0wRBxLjLC9O7tbZL/bv7LcBxJZQIAxiBnqOl+C9WdK6eN3Z15ZM1Z1a7HVr8Hbj4i7II43SSL7SJjWfuoRi+Pnbpi0mAQBhEWierNo7lzXQDl/K1e6cB//1dQ3KoJRrUsgyZM0D8//JljtywY8yFTHEMVl0Im0KDuJlQJ7ygdlsLRwV/chS0rsj3b+5jHru/TqtuS54ePLSS1hBAh4xq5NQfMLwTyLGXw5MOGNqFi0OQbXnj3gpmaAmMeNOfvcRN94IAM7nD723n7P55nEYVmIF5iuJxwgrVBzyBJ1AKrRS4yeh4q2Lat/4DlExd8N/PFTWAuJEWwxk2tcqEPVkfte1JnQ/SeyPCoWdtmrNxBD8nsa2gUA3WHU54HxMGwMNQ+vH6i2KTUIjRt1VkzPm08d0qj/Hc1bGjD16v0eeL1F5rm5l+68bylNAq2W2+rqDhvUmzMkXfGzj1LAFID5AZQBIL3D4A6/r2Xmu8/dXTzLxW5d5ZhrQFB5KFVlwdrDZPJKNxgiM7u1qrjqE2PPvvtF9Oe4wiAatQAEvQyjx5ThrPHp1/44O/cq9d/VBJ5rvsU3i9OZesZ69C8zYKi07ahZ9RyrQYjgEMM1cioZjf8RKKVVFE+VVEinjLpJ1hP7XtyyJqZyx59dvmKNB8iCECE3+T+X+ay+4REzeaqrgIAgUszA/uXmHFVXdf4g3N9c1qa+5aF4xYVOYteddnh9EgUUE8FEDOURVIdHs95wZnocAovd5r72JN3rZw5b9v0FVuhfgIJmcbcGQ4oQdYntauW9izeNInfhIhO7TQOHJ1vyCk7zp83rP1403155cUDxywa3T+3olS4ALNsg2MHNL0WjKqINoXtjo+I/eT9cfO2+yvVvDFiSg5+04enbP/3u+PmCeQ/FNdIJ6ePNnOzMj26Z83MUd9m7nvxlGw3wFTn1SFCCYIS0FxoEnRGlhzXbMP8KSun9REErmunpJhZRiYWhiCCOV+81XjfsV83HXCX3lMhO5fzpmLO0SSHYoE8y/X1pxNUS7P0xoipWXesmjolX/C8YLU5vHBO1F6tE9gE1GgkEBPU0CPuUlOmbFuSPWfEiLSXFi3d8vT81/k6JCUFC9WUoAvVK+PgEyFwhvSLqCtP6v7CBhi0AoPBRyB+4VM32+90hzNBMxPhgPhaz3kj0341Vtwpk886HW6qJ3FdDJIY/otKfrlVzteKPa2Vl77pYR71TZQhZtqOmc9hd8PMGKmlCzL4WfZQ1VFPObcpyuqME2a+CB7DXl7+4PS3lq3K8dpb5sOTEvv/IEuYfoG6uR4Hy1UdQEND94YVheNaz3jkwI3N2i77cLz5Y2pk5OZVD2c7Cg98+8yq09UaVbPNbzqzcWMLDu289vy0O3LKC6fvK7pwW7EDm4+QGhKOCUOzwqLIIPUNS8xp3bTF8DefmJaxdeoq7tJ+6nJSldS4dcnEB9L3fPfqKa89FuCzSFjEuF/zH2EfpNqg8J8+dUj8dtrzq29bMrHPLjX/QdnhcsMnTcdtXQHWXbscroHSeEqIICmywysf1ZS3ys8/8doN80c80alhm7n/N272D+aMjGtSu7Bg5LUFaYbf4mAgCzaKoePVI0Fo7ZCZWQ/UoVrw3Td37lyDs5uZ798dXe8YVrb/i1/O6rzNNR4VuyOqtj5JQrWhT3QYEschVTmnsoLl6G2Dmjosg25fOuHNbm1vnL4+bUQRqvcHhPAFafBBceWvBDEjcGpKT+eesVu3f7Pup0vHHz1vh/OGLHi02PsENKBHURuF8C4NdAa3Tqu7iGNblXbVo4nQSD1OluR9NHDZM1+2a9Pur0qlO8dl83zUY8EoS5Sg2WbXas7FR0brC4sKaQvjxkXzRtxazjwdc3G4B34/Xh1UCjc6gnMBmg7RcayhKfr5V2asmUuLcFprkJvJZh/hKrTo+ipj55oTtuJHi5028liwa416k12mg2Z/3ARjBk4ICWzn3HVDsbj8PEuqHFJpteE0G05Q1Yu2vj5jt500H5hbBLnIalOKdK5biy4ey+i9ZPwbKd37TFnx50fKSK0Adwpp0OC+v/UtvfkIKwzno5hJbwiVk86zh1xMX8sM+c/1UGsc/4Gf/JTh8rS0oj8tnX2zq+LCz7kaWzOsKMBEmO5qjfmf4ywahggHanJUm5RjcT+e/2vZ0LQX5y/b8syi5fWYzBkRCK9j+N+X3PfuZ+9vOuCqaICzwrIRZ3dcGHEEsdA2NUWwhobIH2D23ZwQ3XDv3U8MvZwmwMSINPOnbYk/HdjXqMBe8UR5acXrI/9y34jPM/akZJ069tkptXJhCaQCKyghxzjf1o0b1wocbMCJsOTSubUia2g0MhgKDndq1PaZd0ZN/6HtzLVVUiMg1R57ZdmT2zJ+WHPEUxkBdUzWI96RCwEt3NiCbaLXm3IJGNi2ySzzR0sgDuKafPd3r3nTvbctfvrVXTrvk16ckQC3plOG9bDsK72l/ShIHg04midPsUn5gvxE5U9bBz+wes7oTyYv/QxmMOCvr50rpa7tF5kkmUarKbBUuAut5eepVBbcN6pKQxUCN1ZaTXlwZoHKegC9wQFDL6iryvl/kJ9XpaKYUlt1OZj+zOIVuE3qMsfNDEhZ8q74bvSygtQNK2/OKTq/e6+jqKUKtRwqH/yPr96On1AomomKmETek4IlvKTo7LIBSyfe36lt14dfSht5nqtcteKqSbM+fitu/5nDz+/KPfn4ORu5/Ekeg06rcXghNySdlGyIq+zStO2Et0bOfNvfF/b6CL5sIS4ij+17F1ml6PPs6i1bjF9+uyNxDWIv4brfk68+f1tW7pkxFcw5yCZqoitxZsapk5heo9HpoB800Ohko1b/U1xY5GvfTF/1Nvdf8G3wMPNobsVQEOol8suff1z//cXjw3Os5RSSB3suGhGxq3CQQW+41ZhwuXPrlp9tYh8wMzZ2zGj4j5iAuLRW4ESyc95LT93/wsyzZ8oLlx2zlUp04g4UIiGCC+fj9fXPhwiQ97QtBX09izkaOMtzP+23ZMKyH+eun1O9nbr1hK6elAjEWRDOuu2Vq1aNJrcnhrquEEhmKgqnMxxxHGqL1CULDuzLExO8xsT1JY0Gu9RqKxQhAqkBDBmNUrBeSx8/PX+Hqnaas3jsO2c05UMLrdhEhusRtttCBpWoDgLGByYQHOpgGqXYavV+77T1unyo8vi9G+c/+Pm4RV8hL8frQBlp+6+73vmV2Qd5Ky0eHRzRPJD2cFoTm4RHiV0iGnwx4OYBo6b3vyefCsICpUlvlKcyn4WLryM3wcIFWzPLcbnEyWlpJFUuBCp/7ampO/F7J4VsuVSc0+d0fk4UNnLcjQzhUuPwuLJ2DRofWfXw6LOB/HQQ6tTly8RNgf2M3bl6zpD3f9y2+bTqaqg6XF69Ros4UAhvBXWsdUQ06xjd5I3RUyY8PURIslOwL5TjMAXq+6N9A354CkLb6i9oPp2yYvnYd9ftMJ469topT0WnChvWajh1CM5MQRSumqCjE4LpcAZdPldRouaHu2YPWD65+/ezVt9D7eDDibFmRVfwveZ9UCcQy4v16A0RCfFpc99rN+eBRw5hDwuWspqRJ+HcVMps8NaSVSdgDaWK1a4ePADTqnoN2KmEJ2rwlAG8IC+B/ohLhxypd6+c9vhlofiVw+4KCYGvEL0E0SYhRYOXrnkXIfywPBF0Gq/gOe4p0dsvyV8O37hkztvj5i7j6igObFEJKctaZvLCUcQAlcopexDkFYsKfYKla6M2z7w1bvYbW9kL1Z0HuQVqxpa3m2XmZD3icrvuenH+iKRchxXAwUQ873FNpNZ4IiI8Ymuflh2/Nj/wRDY1snRI2iV8VW250kXASY4lM23KELMmg2V4A/FwZ3y7JerggT2vZpZeHHrJSctv0aMXtBqXjHPbBkg1Y3Rej2YdR78yYsqXX05dzhehOCTDiQqZ/9CJ1C10wEseAi8Pm7gXBNN10Mpp888qebNPq07ovbKMdSGc2eDeU4PHBu82XK/BVrSqHdFDvpdzB6csfebrjDkvDiYi4RuLaWm+gldh9tDO4KSlyCYj9tJFIYEKBbNiIZPE1Wevl/ZzrglZqS70Gu6nAAIMgK5DJVov+ImbbZ2+6s2ZH723M/zEnjVnbaX35mNdCkqDFVDEfirWZVdJxGiwwajVCpJ8wVIu7C45v/S+tXNLPnt2ySZS6UhqSVhky3YEFHTKLm3DiEjWJTzhq3v63jZy0m0PkhjVpGAR73MD2UxqqHD3qqkrth3NmHpCtotONyxcZP3wi9IyWthLlrZRrvIhRaXFnsHPT3uvS8sb5q18cFjulPdevivfXlnx3sgZVd6aHP4DzJNxwHeufNn2j+P2Hz847ssdX0/K9FTGMI9X1mKMPThgROuNZmGRrH1kwlsjn3jq6bREBAhIYVLquC2qz3fHzKv7/82fzQe4SgGCIcI3j3tn9btJF86vPucoH5Jjo/Nh/LQnnWa/Kpl4oJoBaXSy0+k6oi0e9Kflk5d9N2v1bLawPxA4gYsNEIB/WRx8BGmaaVnghprsUOA++z9MnLjRPhlxVjz4yDn8vO/B9eb7z5fkrTzqKGvr4dFL+Lhdk7SFMqiBe6ByprhArbRY/566aUlm+ui5PHayZCcvKZwN6KpPqOjQoOmU9AmLXtvOXqwuNThnfnjtopt7zB/x+iHZ1km1Yv0lYi1AthOSjdxNhoYPo4x4rBVOh/qrYtX+Klsfz6soSRu6fuHQTs27Hs7c/dkbty8a34BpNf+AC8HppOg4I4hMLrNaYnCm//Z/7PzqT5dke2yx3Y44DdgSod10FQxBpxe6aSPzOzdpNeb9MXM/+3bGmurw+dQqEO/143Ly+2BPBklF9KvzwjTtxkcnn0Gt9963zjywSenltSfcFZ0RmhQaCc7ngC1x/K2nWTLjgtnoSysq5FOKOCv15cXb08fO+56fB4I6gRMOJLfqT5heLwxhdrfPalilEtQsRZIJxAbrSbUNT0gWEo1XJeaaVdV/RW4kFLIUah77aIL5U+T+9J4XZs44W3pp9gmPLRJ+fDIPrH0NahckLTRYrbdQcUsnLpx5B5vj7chrWmokGSJv0IfvfvCuB//ybG8ejUKE1PA7D/qkBiLNLd1bcHJWtgciTIbfuUarBdVp+cFlrhH4OoKR4T+gClIgEgrn6DmkFphckvC1Z89Xz0Ak3pVsfup5l1dYVuq1shOWQkhthZXhAIsVh16YCxJJ0DgwjIicx3TwKGZNEDmxbUTCG08O/NuzPIxLQGrAJR4iUDZ/9UbDvYcyE7cKwhGuMlw3fln1T+41P0V/MsF2Aojw2UTzdpTtAheKMZfUklUnZWc4XHMowNtVTcKQJPD706o5TguLz7+4CvUkY8eML2midXAf8SKuFlA4GLHxe+BBFAe4POCvH6QTWEHpcWCHifAWwsGrqhyqh/xJiUyqbv0uPwJrIOCsRAzlqykrnpvx7aa/h/34y+JKg3fCaUsZ9tkgTXhc4/qbBJFI4ADu0zpnixFznhqH3C+Kt7boOPnHBS/3JeIgvcvvPOgl58GHNiy6CQh9ZJ+tYFa2rVLVyFxs6UAc9XaTBpPy4DyYTo/gecdLCuT91twX+yG85gHzq1MHt+/doYGsec5jd2RX2KzYDoEQQCER0TjC4F/SQGeUmkv6gt7h8R8MaNejz46560YQcXD4xqXSbj93bhyx6flbv96/98KhoouPUtevHrSBcv0xkx8RZEIE6sH3s9b9/b6eKR1vj2i4tQGiTMLED74U+nRfoNeQJBKcEr3FXluPxzYvuxf3udyINYSDrZGtKpCz5jesRGBeAuYVgbK9tEaulbDBR3ewu5kt2Oz5WK6cZF7PGRUfGKpPJUo6B2EN6g/RQq36fuMlEQcxSFK7nrtjdMWBRa9O7JnU9s52hqhTEtatiLZIx06v2jZUUcnpdLIKr2Pq6t1bjNJrY2f/RLBwCrxMLue+g0p9lk1YvDv35FzspmMIFbdGo4H7Awb3NyZEH8f+oFa9VF4h2yLkpZ3mjtCuTHtyIaqZad7/xaIjew/0PF5woV3bqPi2JoMp+uDFcwd6tOhwqVF82+/XwCrGFyxwCUjBgqO6S/zN5vGL/3n2wNxcyBpJ8ZJ9+o8RtKHa+BVlZdXLaKplrfoZQARSu1Y+ODIXDwYNXTt39LGCi38/4ayEoiSA3YS25BCG4AAWy4HX65niy3/DJY+Ugqg2dh8NEImEwCNAi0PCDO/jqAs3LfqRytd89Bh9V6XUVMmTnu6Om/vUykK5YhpzQJSEiP9VVeZf/QFpi60Cj5ksdBlm8f/GzPkW6+aOt+CIRo7WOu5SZbkKAvDFC6vbA94qtCB4bOJMupY1+Xrnz0MkMpvBzYRczjkn+duLi5KPFWW/ftBa3M1ps9ELnOigAm1b/MuJFonQlcVyq022GGUziETIWvK62dyTnzTbiYp3Hq9W+6nA79TOukH9BgjffHxUzsjwwXf/i/OSzxbmvH7IXdLN5bLDumXQGplG4hQSKPdH+b6dAxpiqup04grWVqld9M6MdPVDWF0e2bRid/7JA9vKBU+j+iIrUq1YGsAM5mVFtoqe606f1k9s29Z1oPjiL6JWNxjnu9HOlaYCUPjuCMyBRfqlcgRg4CnoKoQTSqAcvjnqFLuslZIWR0mrPbiGn799bFApCIRgUOg4BNQ6gnV86npzznfOzOWl2LCGeZdi/gStm/qJMkIRwv5UOiz9xfSsoiri6L/kmYV78k/sP+Io6+a0O0lqgJiuvgBEnVdNBBAAE+FnJJ9V7AtwqOUNKjRwxqgoWMa6Ba0AxyMpvhJO4nuf3vJKy9uXPrNx36XT+4+6Ld1cDic24TUKLO6snP37QRsCKBH4DgpP/TeDDnh9RTIQ+A7Pqcmrf8gIUStxh0QgQpsJg/TvjZ55tH+rzilttOEUdoFiYoXsCp1hg64NhwRP84O7PmtJ1eKkOL0bCqWCF+N3cfANbkEsUdUnURlirPRdK9G9K5+YGICCcx2wEwWvuVbpmpdU5Fo+NUv5rzbDTEvShLYS0ieYVwxo1nF+NNR4jA9FwgiZoKpifBAFWfX2kGit8bfNS7tn5Z5/42d7QXebDS7nElRaQf23pEaw1olIMAmiy2b37NPkPX7nc5Oj/zlj9QMDVky596aFY17D+ZGPEsKj9uBo6fksp4PdGRkTVVZp61rutQ/YdvCH4Rc1Xi2kBkUFR9xYbI5gbZpoDGdt9XFlpCemJA1RM5gvnkCw9q/lHhkayKx8LXmr5yGWdfWEajHdsF7z/QEwibWI6j4EngEkAPm9GnUAkzGXWq0olCgLRw9Cz6DvcuSrgWtn1n/jIiL55Gnzqd6Lxj11TnG9objJgy5Inb4GCBAKuCbZ7I4WuHWiS2xjZ0nZRTCbGlX7cgf+whAFWwA5rnamW4G3dwUe+79rVuB/gREd5GCcVGrlDnH57BtrIg7lZ3+Bl/bE4Kg1SYE6c4Ib8C9XI+OMph3fzVo7EqJDxKfGVIBA6Fplo5j2wwmLFicvHH3zAcVzD/kB4m7QJQNwVCPDYKSJ0PaUbl3y9LifL5zYcAaWDZCMb61BC7n/UIK8hfFWoy2ptLh2qMr9nec9+eH3M18YetO8kbkXZfsbZxi8hUsraFfU/ZOlXEch9UsU7E86ET9Kg/NdoqD14ugu0+lYG0OEvY0xcdrWGS9spAHM8KuJQUEn9KtHvvsWoSJzgHMUl5f+Zo3SAGdnpKBNX7kJZRV7RuRgSvfKnY5bj7jKWuG1TGQjD56gDDSTTCwtuX+DA2zzeUw4hfas0xCIBIPE2J55G97qPPexRVleN+LKIpJ5ED8ljkHQsophPTx2+TwflUK7dT+PhYH8fE8wGDSAugIuPjDdc/z4TwTq49INbR+6kCsdt+b1KhDgz1pXePqgo/HWSayBq7KI38g01yEifzfUlCQzmKeZdUxq8Xz+ecs9l9xWKFLBw/7AmwTzIbGLzkpRPF5e9MQZOqiEN3lh3khqhGrE39a//4VFJIX613vwcpZMV9mDPcwjd/6y+JU3zy17W4h0CevaGcLcsUadsViUNSWykwMk0EsYdVpjpM4gtdSFFSXrY1endElu5ScOAqoO0lSH1IAOh8LBqsKQrOWke1rKTL6yQXXs6tUylpnB270hvmkPFUwJ3Cfo+Pluko6psHCNBHs231OoBFMCG1PcuE+vcKvx0eMcP0OM0MTwSPKgbUNlOnXqFLR+PFLJ2Q6zjoA08lcM71oEstXgplS+eiKmHkhNo+Id0UAYVINRCJ7AYwQVOnyUwdSL5zD7+h489793N1/nhFIp4IAqXoCqIKx9rbHh1yoYOliA1ePlpx3gbhSy0YwFCzjTS+7Z+xDOGkFQQqUMabOjakgLRegddLocHA0rKQVnmkPW/7s/ICLBTGjheerOclb26zZ/REG3xq0HvTt6zjPPvP/KsovFF+9xOO39LtrKowvwuq4GEVHaaJ3xAhag27u167ADgZqtXJmCWY9t2nTVoA2t4hsJ53LLKaYT73zwDgmKBpRr0uop/OU3Ph37KkSS7hu1M+UF8fQLa7ag+AVkBFfAe5FdjspThbknqH2OoDAaYY7hN11XHaLlMuQtK8a7MbIunee21fqhSUGBDHbSZb+gMdI5bh6lBvdqJgKQqsZ5f/h7mjgRNUhqdlxbcKYc0Ef7H9fpB6S6KEPquF3ODrtV1cgPstHaCERZs4Xf5wqijS8HaHyoldq10k0ZDKe5MTI+Cw/9a7La2fg1H0r8eqh7ivvzrZ9CXcqPxsE0eudMnXqxVgbfUtQ4nUmQaNr4CAVqCFr9f+amv0kdPCDcR9zOxPILzgN9Fo5b+OLfRprR4uv+D2+8hP/1/dlFXzgaPApHgzdvR8zVa5ggMOpDfJVIfAkDEGxGcVuwwD3/QllRO2oiA//qTT7kUO5fY47+Je9kJ4prC4wOKqi45QRrw0amiNIR9/3Z+slYM8P+hYBXwBKjCJp8BISYtTDcwr2/LTL9WL9pOIPX0ys6MelnRylhVFDMpeawtmHxiD/buXFzdhDXdHio3exHT4OIbyLswK06ayJflEcBUditjd9/86XmyHPCvHChYPbRGy5/j+QbjFvatBf3HbFpSq2kVeM100GrhkkWBILJbEMv2uHnXkIQbGCIvz+zT8L5IWgIcAIJQhzUDM708mPPyISQo//jxBEVG4rQl+WLeCPREVfpgi6zHzvdc+GYBzft3+9XdfxAwhpBrhHUB4aIkGSloOO35i1b6F7QlEKMGinCqM+MxFtNMSoSDUCwzBhEDb1yGd9/mfX16wlkwIC+H3KMkn0RDuFt40q1aBTivMSyA3NRowkgO2IPSyxSMh4fktTTTg8dbtchAZEKMflB4eEVgPhLsHgqtpT2oOsQC2OeFfDyvkIjuJXhveWc/fqe1P5LiyGN1+Vx4A3gVVb1MFF/hHbBOcrVLoFrwAnTiOi9iDXz8ZKcAZTli0Z5dQipZtGMwGXQcQk8DHwjEx+L4akTynASMAcEi0f0ysa6CTdpa14pl12RedkXOlCO1PT0oPNFhEzP9/16qElhZWUsFSUtJljC6l2maPQOj/tQ0MqCFfpP3wMCYSgkuHm5PMecFW3Ouys+XP/JhsNweFz9wJpZt9C5FRioPP5QqcqYj19OTF236HacXPxoy77PJhB8FBCsNpxAcD64bz4x/TT0+CxCALDsegZc9FwQnBG7Dx2ZSXWZM83YK6r5imIsxoWAtyflKagsm0NvJSIVhK6DJVotR2v1LCoi6rvAc63eeDYacaZI+wqVyIXEA4vKZUvpPWiXv9MwxbebXh3hBP/7OJS/vrK0W7a17EZy90WTQeEB4cCipLJYU1jhpEcmFKJtni9WF5YR53vJVV29ww8gHVByIMig02mfSrewsQwX9Jrj489KX8Kg2K4+AiJuHbqbV4r4c/WHkybeGJVNBAKLatCS/CZWdQVwIMipLHiUKkn/cbZUm6nRfG2ryNTT82MXztxXqgMsGFZOYHSzVvLXy8K1xmNBB7BW/v/aJV75RWtMLXRLuQTvCD/mKG2zszRn0vZLp3d//vN35xtPf+hAzLSH9yZNf/jA97/sOrszNzPjsOj4S5bbRtybZYQIXk3uB/Qca4vPyfqFQGBBCYTyYDYlJ4KeHyvNm4wACGlw0nf73TxwHI8jEqlogagvrN/ipz/YZy1qDsswArkER0i+GFQUbQNZ8uD1YB9SO5RwqOknHU0TEL86tvue+v6Cm5GpxXvBa2/xp+emrKC7GT5rHRblgMcHk8r3i/DsRE72y/mw+kGK0JH2oNXiPrR6iUVrTfs7C4IbUhlUythNbTvsivEiGJ8iY0svODrzPuKN58dsxS0HrJg0F8V8rj90pJc8Hoh4fYyKcKsKLpMGr3XnumRQkKh5X6q2hovQGX7G62qIf3CcDWSp/o3BgTu6W71QUTT2kb8v/RNbf8ZlDph6q83XnjXpjmkfvdn3YvHleRVWKxlTeJ+r13Xlt8pM0JQVJu64rgiEAKSRIFcJkDh2lkTFipfFWxAFPdNRHnEJGzdlzHtznuLpccphDS9wO1wqkDkSHq28cyGCNgTeDdGzWYdPuujCIUA9eD1l8ImikDv08tgSBKc4XHD2H7eteHbtpC2bunLQzKR9MPXVzN2xaX9fPLinedSBXZb8h+AsSJEx6hlw+LDptaxpZOzHLzz41AU/ArHnJy/PbKIPzwVq0e5CSKIlkCrsDnVXSc7UWxaPfRMB9rp8rZ7WgzgU+mQiEMbjr6xKgTXwp1/txX1w9loOtuinMaJe005iks7EmkQlfkb3Elhn1JMirfjr2OxYbfg38KCj29Co6iaaH6ynJBzgUg+V5i0euOzZdUu3v98AjIT7x2UQ8UI1RTYO1/gPXupx7+qZY6DQPKa4oL4GMUbUbcV3J8Jg3BpLQW7grhR8ttAIuiTh5brnnFZ2MPvkt/esnTV75idvtOA10Pig9LKdWxIeXDd37PeHf9px1mM3IrQSef8FrRIMEuSoSs2Z3jage999QsKUh74v0sj9/ZPsE4c++K6rvxLUAnSqKtAHNAR6fRwhntZk95qt6z5eyBHPNznBYKe+yX0Wj3t3t6XgERy2h5EodJA2ag97SWAlBrGLFg6zsnwEQZmsOrjdRGh17bJdlZGF8GeiDSdIFDJ2BE2+ejxq5+hEcUCnXt3XPzzmMLn3kAcDIRJUyJe/Ljo/RnDBxwPSM2gluEnrJqhM2JKWhFZaE4LySWdtslxA+Y1MbOiU1FZn8R4hsIqQxEF5dZAsbq9L7B3bpHj+hKmtB8e1rSQVJC09jcfRunet+bb9+ad+wJtwZRy58xlwqGCtBM4KR2xVjQg3io0UbWUDY9SvFYr7V6siu6IlSR+nDbuxyF7RDIH/WuYqTlYJB0BIWcxfcCmLccI5VlXzQPOuOz6ZuHgAmuPz1WbWsENnPNYbcN4YAx3axwwMT4HTK+LDG9gNYhh6JByrVBWLgak6k6jpeEaxhyEQBqQ2XpRbj68aYrZ4FBxd7W2Ie3Wv+eWR9XC9WiPyP76EqkEUzwmYSxlc0Y2gbCAIrBC7dJSX9Wpxw7SKrN1Dsf+ih0U3pGMftYfAU4KMwADH7IUaqGbd+MEwLCaYFXtyOIUGwgDKhiYOIDUoWPHow8J07WKTniPiYCkpEsyRfPFvhpWsSXzT5zuWFIw5rpRCm9AGNTtSdyAR0Bp6ixNLODSlwXv2WmMzqzUXuXQ+H/sEeG0zAtGERiIaKwT/9iZGRunaxCetJOJIgUqEfhDHl+mo6efPmnfetuTpr/KY6x7EbHaj/qAGEOLcdGbVYoOEZ/bIU17r7UzS3q7DNuM5sk/jKAOFMgUDASvD3i7WUqGIg/pXJ01oI0FdklvGN3qlqOTSSxWynWRJyCDpdJ6Dv+DJ6ZIP0wuftNquPoMiTQI24nEaAJoBnVkOKQRADKrX69a20UWpXTp1WkaOstedilVnoH6nGyAOHj5m7aOjL7dNaDw8zmAir28EsRHoBfNBk9/KIUka8F2EUBUgRohD60Ss8viE+wi2TmHUR3vl4FQuptPoeoc12IVXyfFFP/zKuOpC8JDE2/z4xLOtYxqtZGFGrKvx7okQsFAb9AgfmmewdpFWPTiAgLe9QBUFZ8TpwtCTT8QBu78b9kJdB130j+8+vWAV1ZlRzfuAog3SvQG9+o7qKoWDAas6vAKOjpEETaS/gGphmwPrx7gITo/HbXN5ELDBQ9cUGIHGDnSNmAzBJUfQiunm+jNEtMK3U1ZtaC6a9oMh6DDmQdyIr9TgU5ugmmt0FCgaY0MbrwwLKgoJIeClMqH5KbYAEB9b9SThxUM3JDWf/WrahPMpYB7/zxAIDSNHBizYP528bEvzsKhHm0RGwZKIE/kCYixhgK4Mdc1f4DqE7JQP465qwFZD4QyfASAi+LniCQ8z6nuExf3ytznDSWVgZp/J+Eo7/veZfDn9uRm3GhJ2MYNWh/pdYHFX8tQEhV8RYoIYiJY4TIAP9uvQRQAPqaZuvL5Y110fc/yhB1MHU0V+eHid/mswkRTJfOdf82IiYnonavRWnP/Q0viEgolapdcSEHFiCOk95siPw3S4Jq5OY3ctKZAL39Q9nih8Kv24qUWnv7ZkRhvsckRt9RIJ5UebPnhovgBHfeeXiHEAaCjTqhIRYdI1lcI2fPTMUjKGiBlgHv9PEQgNHsMxTbJqHZy/6d1bGnV4uEtYvJsjJikx8CMkXfa3DgrnzlizwHwKIw/eCI5VYKzRpO0Z1vC9d+ZvvnW00JMfDQVCVk0+hwWEEEDS2X+bNLCPMXGXZNDrQV2kTnnAmTlQ/rzX/EXw4AMKIjzBG4NVWYwIN+l6hifu6nfL0BvHd+5v9UeBqQ0PmEiGl8Zn54y1x/u17NI7OSKxGOs8Hb3MFdVymLiZ+JqhCZ6RKqNxJsIjKQ5tjd5hSBKpSqWjnfEUcPHXnpp8pkNis16djNEWhcQ3TmOhLCFvgK6CNxLiLuBH23yeiS68cE7VNDCaNLfFNH5u37xNT/NimEj6Js85qMkYJ+43r0IK/RE+ONgGONEDwE79AAP9DYmHxAenTB8/9x+De/yp9Y2aqNcaSHpZi4BgOJkHDz+qlN7XwieBVDBZDwLAAl3l31joYmowqWgfSEPSWaZhhk4RH2bSdtZFHu+X2PovGbPXDiMzKl+U1wqPEwCXiIaIZDDOZOxesLFfL0P83Jb6CNiltDgKJotQc0gl8xAsvE0IDz3ZwgELfQgeIswqeOh99/QuEQlPSAAABIhJREFUFsyoAkfPCKNR294YVXp7fPMZ+82b+q0fPNhFxJFeT5BvGh8iko+enp85avioNnfEtni1rSlaNtL4oDmMD8AhPBE8/jHwQhVD9wkWvlikBSP/0D16FoAdY4l+0FILwRAUkC7qQi9pgWCQwmFhdHvy+dj43aoywMUJlm+mLs964JYBHfuaEr6J0Rs1IBS8AjAAB/PBgTkhIwSNCW8X3/Sb5g/w0Dhy/Ab8ZMgQFaz66DRmn+jGx3sltkj5asrzpAaT2yn4k09JEBpMfXh/UZiYTO95I/L9IyVSHARYLYxljpWWtR/OYBhIkhDX2gfiTjQBlP+BF8ztLlhynwJtPISXlTYrAc7RC0KxJ4BxwbTjBaY+nkeoh3HSG4ACWMFiP8EEjpSEo9haSfy2QXjMa/+cvhrvg0PCglzdsYMW8yhUfyIiwYcT+rBXV7e5XHBxWrGjckiB19moDIo03j7na5eYGSIucpgIDqIfHWChPUo8o32DCKCpzqtURmr1P7eNa7y13w09XqWX0RAE1dupH6KaMWsnf7y53dEzJ54stVTcU+yyd7Tg2Hk52saaH21DDmCjlCtHBEd1PKLxo6SH6Zhgx3hFYDx1GJFoBbYGrbbEIGnOmzTaIxjLHexSwacZG9OtICggKf76U0q1uRq4fGqKxVU5qcRh718seCNssJB7uOEW40FjQ/yN4OBCAL9xBoT/xj0sZFgcjOp6D7sUExa5Jykq+s2vJj33FW8GTNNvog40y4R2sx59tMLjbo8KsJFDS8s/TsILtIkzhWPBujV3zf/9gNnHxlkdNabeDpkJMVkGymVwQvlaVfVvrF3Y8UxxTle9TroJQVs6ny4rEpITmnaxed0Son+Q/0/5wdLLZzvFNihzOpyHGsfEH+/cqtORVUOfOB1oLKXahAbuXcM3TL8p2HDzwfJFXp7p9Y82984pyE02GAwdL1sqWoAgjE1jEjva3E5IDXQeEF22lJ0oV7zWznFJlYUVJXtjImMPtWrY6Ai8B3zcGA0TF+aS8xqAqJ6FTMAChQfyw0TPiIArKgpvvVRe3DbMaOyxJ/+idHN847Y2xRtd5nLIThAzaSi01xRvCNOEa3Xlh8vyT/dq0EK+WFr4c+voBLsqSQdbN2ha1LB9m7Pm3oO5N261dgkPq4gjcJ/PFbm0+4O6jXn77cQzuYdvvVxZ1DnCFHbDibKimBtiGrSGq3i0TfaQBiCGSTpvZtGlY4mRMSoOph/DnsnJxlHxh3t0v/EwXi1e9RoPf1AMPzUHWgStX/n5B/9VTSz+Kz2pTSi16/i6pCSy4OJFURerEfo06+po6YvuVzubCMIQM6pZhmpnuJbrq8Hy3oULMVZvEcLBMBaeoBMfad4Nv4IkmG1TOiOuGbl6X4MUC1JD1S2CCQTLXV2qblb7cV5VDR/s+sp4/vIlpfDSZaEczxJMBrVHpy7iw7feE2q8AjVwxpDCUsiQQkhahzgCGembq6wb0wVYyTlTq/6M4Nh98agRb9RV7JUaoX2zcIXM2dXzVP2GhE8dx1/5QZI7aJv/H+y6kJy2/hwbAAAAAElFTkSuQmCC"},{"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}","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,"description":"Public domain street and address data from the San Juan County, WA. Updated at least quarterly."},{"id":"Vejmidte_Denmark","name":"Vejmidte","type":"tms","template":"http://{switch:a,b,c}.tile.openstreetmap.dk/danmark/vejmidte/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[8.3743941,54.9551655],[8.3683809,55.4042149],[8.2103997,55.4039795],[8.2087314,55.4937345],[8.0502655,55.4924731],[8.0185123,56.7501399],[8.1819161,56.7509948],[8.1763274,57.0208898],[8.3413329,57.0219872],[8.3392467,57.1119574],[8.5054433,57.1123212],[8.5033923,57.2020499],[9.3316304,57.2027636],[9.3319079,57.2924835],[9.4978864,57.2919578],[9.4988593,57.3820608],[9.6649749,57.3811615],[9.6687295,57.5605591],[9.8351961,57.5596265],[9.8374896,57.6493322],[10.1725726,57.6462818],[10.1754245,57.7367768],[10.5118282,57.7330269],[10.5152095,57.8228945],[10.6834853,57.8207722],[10.6751613,57.6412021],[10.5077045,57.6433097],[10.5039992,57.5535088],[10.671038,57.5514113],[10.6507805,57.1024538],[10.4857673,57.1045138],[10.4786236,56.9249051],[10.3143981,56.9267573],[10.3112341,56.8369269],[10.4750295,56.83509],[10.4649016,56.5656681],[10.9524239,56.5589761],[10.9479249,56.4692243],[11.1099335,56.4664675],[11.1052639,56.376833],[10.9429901,56.3795284],[10.9341235,56.1994768],[10.7719685,56.2020244],[10.7694751,56.1120103],[10.6079695,56.1150259],[10.4466742,56.116717],[10.2865948,56.118675],[10.2831527,56.0281851],[10.4439274,56.0270388],[10.4417713,55.7579243],[10.4334961,55.6693533],[10.743814,55.6646861],[10.743814,55.5712253],[10.8969041,55.5712253],[10.9051793,55.3953852],[11.0613726,55.3812841],[11.0593038,55.1124061],[11.0458567,55.0318621],[11.2030844,55.0247474],[11.2030844,55.117139],[11.0593038,55.1124061],[11.0613726,55.3812841],[11.0789572,55.5712253],[10.8969041,55.5712253],[10.9258671,55.6670198],[10.743814,55.6646861],[10.7562267,55.7579243],[10.4417713,55.7579243],[10.4439274,56.0270388],[10.4466742,56.116717],[10.6079695,56.1150259],[10.6052053,56.0247462],[10.9258671,56.0201215],[10.9197132,55.9309388],[11.0802782,55.92792],[11.0858066,56.0178284],[11.7265047,56.005058],[11.7319981,56.0952142],[12.0540333,56.0871256],[12.0608477,56.1762576],[12.7023469,56.1594405],[12.6611131,55.7114318],[12.9792318,55.7014026],[12.9612912,55.5217294],[12.3268659,55.5412096],[12.3206071,55.4513655],[12.4778226,55.447067],[12.4702432,55.3570479],[12.6269738,55.3523837],[12.6200898,55.2632576],[12.4627339,55.26722],[12.4552949,55.1778223],[12.2987046,55.1822303],[12.2897344,55.0923641],[12.6048608,55.0832904],[12.5872011,54.9036285],[12.2766618,54.9119031],[12.2610181,54.7331602],[12.1070691,54.7378161],[12.0858621,54.4681655],[11.7794953,54.4753579],[11.7837381,54.5654783],[11.1658525,54.5782155],[11.1706443,54.6686508],[10.8617173,54.6733956],[10.8651245,54.7634667],[10.7713646,54.7643888],[10.7707276,54.7372807],[10.7551428,54.7375776],[10.7544039,54.7195666],[10.7389074,54.7197588],[10.7384368,54.7108482],[10.7074486,54.7113045],[10.7041094,54.6756741],[10.5510973,54.6781698],[10.5547184,54.7670245],[10.2423994,54.7705935],[10.2459845,54.8604673],[10.0902268,54.8622134],[10.0873731,54.7723851],[9.1555798,54.7769557],[9.1562752,54.8675369],[8.5321973,54.8663765],[8.531432,54.95516],[8.3743941,54.9551655]],[[11.4577738,56.819554],[11.7849181,56.8127385],[11.7716715,56.6332796],[11.4459621,56.6401087],[11.4577738,56.819554]],[[11.3274736,57.3612962],[11.3161808,57.1818004],[11.1508692,57.1847276],[11.1456628,57.094962],[10.8157703,57.1001693],[10.8290599,57.3695272],[11.3274736,57.3612962]],[[11.5843266,56.2777928],[11.5782882,56.1880397],[11.7392309,56.1845765],[11.7456428,56.2743186],[11.5843266,56.2777928]],[[14.6825922,55.3639405],[14.8395247,55.3565231],[14.8263755,55.2671261],[15.1393406,55.2517359],[15.1532015,55.3410836],[15.309925,55.3330556],[15.295719,55.2437356],[15.1393406,55.2517359],[15.1255631,55.1623802],[15.2815819,55.1544167],[15.2535578,54.9757646],[14.6317464,55.0062496],[14.6825922,55.3639405]]],"terms_url":"http://wiki.openstreetmap.org/wiki/Vejmidte","terms_text":"Danish municipalities"},{"id":"wien.gv.at-labels","name":"Vienna: Beschriftungen (annotations)","type":"tms","template":"https://maps.wien.gv.at/wmts/beschriftung/normal/google3857/{zoom}/{y}/{x}.png","scaleExtent":[12,19],"polygon":[[[16.17,48.1],[16.17,48.33],[16.58,48.33],[16.58,48.1],[16.17,48.1]]],"terms_url":"https://data.wien.gv.at/","terms_text":"Stadt Wien","icon":"https://www.wien.gv.at/layout-a/logo/wappen-klein.gif"},{"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","icon":"https://www.wien.gv.at/layout-a/logo/wappen-klein.gif"},{"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","icon":"https://www.wien.gv.at/layout-a/logo/wappen-klein.gif"}];
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/hindu":{"icon":"poi-hinduist","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["garbhargriha","mandu","puja","shrine","temple"],"tags":{"amenity":"place_of_worship","religion":"hindu"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Hindu Temple"},"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/place_of_worship/shinto":{"icon":"poi-shintoist","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["kami","torii"],"tags":{"amenity":"place_of_worship","religion":"shinto"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Shinto Shrine"},"amenity/place_of_worship/sikh":{"icon":"poi-sikhist","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["gurudwara","temple"],"tags":{"amenity":"place_of_worship","religion":"sikh"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Sikh Temple"},"amenity/place_of_worship/taoist":{"icon":"poi-taoist","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["daoist","monastery","temple"],"tags":{"amenity":"place_of_worship","religion":"taoist"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Taoist Temple"},"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/scrapyard":{"icon":"car","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["car","junk","metal","salvage","scrap","u-pull-it","vehicle","wreck","yard"],"tags":{"amenity":"scrapyard"},"reference":{"key":"industrial","value":"scrap_yard"},"name":"Scrap Yard"},"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/waste/dog_excrement":{"icon":"waste-basket","fields":["collection_times"],"geometry":["point","vertex","area"],"tags":{"amenity":"waste_basket","waste":"dog_excrement"},"reference":{"key":"waste","value":"dog_excrement"},"terms":["bin","garbage","rubbish","litter","trash","poo","dog"],"name":"Dog Excrement Bin"},"amenity/water_point":{"icon":"drinking-water","geometry":["area","vertex","point"],"tags":{"amenity":"water_point"},"name":"RV Drinking Water"},"amenity/watering_place":{"icon":"drinking-water","geometry":["area","vertex","point"],"tags":{"amenity":"watering_place"},"name":"Animal Watering Place"},"area":{"name":"Area","tags":{"area":"yes"},"geometry":["area"],"matchScore":0.1},"area/highway":{"fields":["area/highway"],"geometry":["area"],"tags":{"area:highway":"*"},"name":"Road Surface"},"barrier":{"icon":"roadblock","geometry":["point","vertex","line","area"],"tags":{"barrier":"*"},"fields":["barrier"],"name":"Barrier","matchScore":0.4},"barrier/entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"barrier":"entrance"},"name":"Entrance","searchable":false},"barrier/block":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex"],"tags":{"barrier":"block"},"name":"Block"},"barrier/bollard":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex","line"],"tags":{"barrier":"bollard"},"name":"Bollard"},"barrier/border_control":{"icon":"roadblock","fields":["access","building_area"],"geometry":["vertex","area"],"tags":{"barrier":"border_control"},"name":"Border Control"},"barrier/cattle_grid":{"icon":"barrier","geometry":["vertex"],"tags":{"barrier":"cattle_grid"},"name":"Cattle Grid"},"barrier/city_wall":{"icon":"barrier","fields":["height"],"geometry":["line","area"],"tags":{"barrier":"city_wall"},"name":"City Wall"},"barrier/cycle_barrier":{"icon":"roadblock","fields":["access"],"geometry":["vertex"],"tags":{"barrier":"cycle_barrier"},"name":"Cycle Barrier"},"barrier/ditch":{"icon":"roadblock","geometry":["line","area"],"tags":{"barrier":"ditch"},"name":"Trench","matchScore":0.25},"barrier/fence":{"icon":"fence","fields":["fence_type","height"],"geometry":["line"],"tags":{"barrier":"fence"},"name":"Fence","matchScore":0.25},"barrier/gate":{"icon":"barrier","fields":["access"],"geometry":["point","vertex","line"],"tags":{"barrier":"gate"},"name":"Gate"},"barrier/hedge":{"fields":["height"],"geometry":["line","area"],"tags":{"barrier":"hedge"},"name":"Hedge","matchScore":0.25},"barrier/kissing_gate":{"icon":"barrier","fields":["access"],"geometry":["vertex"],"tags":{"barrier":"kissing_gate"},"name":"Kissing Gate"},"barrier/lift_gate":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex"],"tags":{"barrier":"lift_gate"},"name":"Lift Gate"},"barrier/retaining_wall":{"geometry":["line","area"],"tags":{"barrier":"retaining_wall"},"name":"Retaining Wall"},"barrier/stile":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex"],"tags":{"barrier":"stile"},"name":"Stile"},"barrier/toll_booth":{"icon":"roadblock","fields":["access","building_area"],"geometry":["vertex","area"],"tags":{"barrier":"toll_booth"},"name":"Toll Booth"},"barrier/wall":{"icon":"barrier","fields":["wall","height"],"geometry":["line","area"],"tags":{"barrier":"wall"},"name":"Wall","matchScore":0.25},"boundary/administrative":{"name":"Administrative Boundary","geometry":["line"],"tags":{"boundary":"administrative"},"fields":["admin_level"]},"building":{"icon":"home","fields":["building","levels","address"],"geometry":["point","area"],"tags":{"building":"*"},"matchScore":0.6,"terms":[],"name":"Building"},"building/bunker":{"fields":["address","levels"],"geometry":["area"],"tags":{"building":"bunker"},"matchScore":0.5,"name":"Bunker","searchable":false},"building/entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"building":"entrance"},"name":"Entrance/Exit","searchable":false},"building/train_station":{"icon":"building","fields":["address","levels"],"geometry":["point","vertex","area"],"tags":{"building":"train_station"},"matchScore":0.5,"name":"Train Station","searchable":false},"building/apartments":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"apartments"},"matchScore":0.5,"name":"Apartments"},"building/barn":{"icon":"farm","fields":["address","levels"],"geometry":["area"],"tags":{"building":"barn"},"matchScore":0.5,"name":"Barn"},"building/cabin":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"cabin"},"matchScore":0.5,"name":"Cabin"},"building/cathedral":{"icon":"place-of-worship","fields":["address","levels"],"geometry":["area"],"tags":{"building":"cathedral"},"matchScore":0.5,"name":"Cathedral Building"},"building/chapel":{"icon":"place-of-worship","fields":["address","levels"],"geometry":["area"],"tags":{"building":"chapel"},"matchScore":0.5,"name":"Chapel Building"},"building/church":{"icon":"place-of-worship","fields":["address","levels"],"geometry":["area"],"tags":{"building":"church"},"matchScore":0.5,"name":"Church Building"},"building/college":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["university"],"tags":{"building":"college"},"matchScore":0.5,"name":"College Building"},"building/commercial":{"icon":"commercial","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"commercial"},"matchScore":0.5,"name":"Commercial Building"},"building/construction":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"construction"},"matchScore":0.5,"name":"Building Under Construction"},"building/detached":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"detached"},"terms":["home","single","family","residence","dwelling"],"matchScore":0.5,"name":"Detached House"},"building/dormitory":{"icon":"building","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"dormitory"},"matchScore":0.5,"name":"Dormitory"},"building/garage":{"icon":"warehouse","fields":["capacity"],"geometry":["area"],"tags":{"building":"garage"},"matchScore":0.5,"name":"Garage"},"building/garages":{"icon":"warehouse","fields":["capacity"],"geometry":["area"],"tags":{"building":"garages"},"matchScore":0.5,"name":"Garages"},"building/greenhouse":{"icon":"garden-center","fields":["address","levels"],"geometry":["area"],"tags":{"building":"greenhouse"},"matchScore":0.5,"name":"Greenhouse"},"building/hospital":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"hospital"},"matchScore":0.5,"name":"Hospital Building"},"building/hotel":{"icon":"building","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"hotel"},"matchScore":0.5,"name":"Hotel Building"},"building/house":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"house"},"terms":["home","family","residence","dwelling"],"matchScore":0.5,"name":"House"},"building/hut":{"geometry":["area"],"tags":{"building":"hut"},"matchScore":0.5,"name":"Hut"},"building/industrial":{"icon":"industry","fields":["address","levels"],"geometry":["area"],"tags":{"building":"industrial"},"matchScore":0.5,"name":"Industrial Building"},"building/kindergarten":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["kindergarden","pre-school"],"tags":{"building":"kindergarten"},"matchScore":0.5,"name":"Preschool/Kindergarten Building"},"building/public":{"icon":"building","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"public"},"matchScore":0.5,"name":"Public Building"},"building/residential":{"icon":"residential-community","fields":["address","levels"],"geometry":["area"],"tags":{"building":"residential"},"matchScore":0.5,"name":"Residential Building"},"building/retail":{"icon":"commercial","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"retail"},"matchScore":0.5,"name":"Retail Building"},"building/roof":{"icon":"shelter","fields":["address"],"geometry":["area"],"tags":{"building":"roof"},"matchScore":0.5,"name":"Roof"},"building/school":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["academy","elementary school","middle school","high school"],"tags":{"building":"school"},"matchScore":0.5,"name":"School Building"},"building/semidetached_house":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"semidetached_house"},"terms":["home","double","duplex","twin","family","residence","dwelling"],"matchScore":0.5,"name":"Semi-Detached House"},"building/shed":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"shed"},"matchScore":0.5,"name":"Shed"},"building/stable":{"icon":"horse-riding","fields":["address","levels"],"geometry":["area"],"tags":{"building":"stable"},"matchScore":0.5,"name":"Stable"},"building/static_caravan":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"static_caravan"},"matchScore":0.5,"name":"Static Mobile Home"},"building/terrace":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"terrace"},"terms":["home","terrace","brownstone","family","residence","dwelling"],"matchScore":0.5,"name":"Row Houses"},"building/university":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["college"],"tags":{"building":"university"},"matchScore":0.5,"name":"University Building"},"building/warehouse":{"icon":"warehouse","fields":["address","levels"],"geometry":["area"],"tags":{"building":"warehouse"},"matchScore":0.5,"name":"Warehouse"},"camp_site/camp_pitch":{"icon":"campsite","fields":["ref"],"geometry":["point","area"],"terms":["tent","rv"],"tags":{"camp_site":"camp_pitch"},"name":"Camp Pitch"},"club":{"icon":"heart","fields":["club","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"club":"*"},"terms":["social"],"name":"Club"},"craft":{"icon":"poi-tool","fields":["craft","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"*"},"terms":[],"name":"Craft"},"craft/jeweler":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"jeweler"},"reference":{"key":"shop","value":"jewelry"},"name":"Jeweler","searchable":false},"craft/locksmith":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"locksmith"},"reference":{"key":"shop","value":"locksmith"},"name":"Locksmith","searchable":false},"craft/optician":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"optician"},"reference":{"key":"shop","value":"optician"},"name":"Optician","searchable":false},"craft/tailor":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["clothes","suit"],"tags":{"craft":"tailor"},"reference":{"key":"shop","value":"tailor"},"name":"Tailor","searchable":false},"craft/basket_maker":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"basket_maker"},"name":"Basket Maker"},"craft/beekeeper":{"icon":"farm","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"beekeeper"},"name":"Beekeeper"},"craft/blacksmith":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"blacksmith"},"name":"Blacksmith"},"craft/boatbuilder":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"boatbuilder"},"name":"Boat Builder"},"craft/bookbinder":{"icon":"library","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["book repair"],"tags":{"craft":"bookbinder"},"name":"Bookbinder"},"craft/brewery":{"icon":"poi-storage-tank","fields":["operator","address","building_area","opening_hours","product"],"geometry":["point","area"],"terms":["alcohol","beer","beverage","bier","booze","cider"],"tags":{"craft":"brewery"},"name":"Brewery"},"craft/carpenter":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["woodworker"],"tags":{"craft":"carpenter"},"name":"Carpenter"},"craft/carpet_layer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"carpet_layer"},"name":"Carpet Layer"},"craft/caterer":{"icon":"restaurant","fields":["cuisine","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"caterer"},"name":"Caterer"},"craft/clockmaker":{"icon":"poi-clock","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"clockmaker"},"name":"Clockmaker"},"craft/confectionery":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sweets","candy"],"tags":{"craft":"confectionery"},"name":"Confectionery"},"craft/distillery":{"icon":"poi-storage-tank","fields":["operator","address","building_area","opening_hours","product"],"geometry":["point","area"],"terms":["alcohol","beverage","bourbon","booze","brandy","gin","hooch","liquor","mezcal","moonshine","rum","scotch","spirits","still","tequila","vodka","whiskey","whisky"],"tags":{"craft":"distillery"},"name":"Distillery"},"craft/dressmaker":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["seamstress"],"tags":{"craft":"dressmaker"},"name":"Dressmaker"},"craft/electrician":{"icon":"poi-power","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["power","wire"],"tags":{"craft":"electrician"},"name":"Electrician"},"craft/electronics_repair":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"electronics_repair"},"name":"Electronics Repair Shop"},"craft/gardener":{"icon":"garden","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["landscaper","grounds keeper"],"tags":{"craft":"gardener"},"name":"Gardener"},"craft/glaziery":{"icon":"fire-station","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["glass","stained-glass","window"],"tags":{"craft":"glaziery"},"name":"Glaziery"},"craft/handicraft":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"handicraft"},"name":"Handicraft"},"craft/hvac":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["heat*","vent*","air conditioning"],"tags":{"craft":"hvac"},"name":"HVAC"},"craft/insulator":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"insulation"},"name":"Insulator"},"craft/key_cutter":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"key_cutter"},"name":"Key Cutter"},"craft/metal_construction":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"metal_construction"},"name":"Metal Construction"},"craft/painter":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"painter"},"name":"Painter"},"craft/photographer":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"photographer"},"name":"Photographer"},"craft/photographic_laboratory":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["film"],"tags":{"craft":"photographic_laboratory"},"name":"Photographic Laboratory"},"craft/plasterer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"plasterer"},"name":"Plasterer"},"craft/plumber":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["pipe"],"tags":{"craft":"plumber"},"name":"Plumber"},"craft/pottery":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ceramic"],"tags":{"craft":"pottery"},"name":"Pottery"},"craft/rigger":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"rigger"},"name":"Rigger"},"craft/roofer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"roofer"},"name":"Roofer"},"craft/saddler":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"saddler"},"name":"Saddler"},"craft/sailmaker":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sailmaker"},"name":"Sailmaker"},"craft/sawmill":{"icon":"logging","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["lumber"],"tags":{"craft":"sawmill"},"name":"Sawmill"},"craft/scaffolder":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"scaffolder"},"name":"Scaffolder"},"craft/sculpter":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sculpter"},"name":"Sculpter"},"craft/shoemaker":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["cobbler"],"tags":{"craft":"shoemaker"},"name":"Shoemaker"},"craft/stonemason":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["masonry"],"tags":{"craft":"stonemason"},"name":"Stonemason"},"craft/sweep":{"icon":"poi-chimney","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sweep"},"name":"Chimney Sweep"},"craft/tiler":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"tiler"},"name":"Tiler"},"craft/tinsmith":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"tinsmith"},"name":"Tinsmith"},"craft/upholsterer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"upholsterer"},"name":"Upholsterer"},"craft/watchmaker":{"icon":"poi-clock","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"watchmaker"},"name":"Watchmaker"},"craft/window_construction":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["glass"],"tags":{"craft":"window_construction"},"name":"Window Construction"},"craft/winery":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"winery"},"name":"Winery"},"embankment":{"geometry":["line"],"tags":{"embankment":"yes"},"name":"Embankment","matchScore":0.2},"emergency/designated":{"fields":[],"geometry":["line"],"tags":{"emergency":"designated"},"terms":[],"name":"Emergency Access Designated","searchable":false,"matchScore":0.01},"emergency/destination":{"fields":[],"geometry":["line"],"tags":{"emergency":"destination"},"terms":[],"name":"Emergency Access Destination","searchable":false,"matchScore":0.01},"emergency/no":{"fields":[],"geometry":["line"],"tags":{"emergency":"no"},"terms":[],"name":"Emergency Access No","searchable":false,"matchScore":0.01},"emergency/official":{"fields":[],"geometry":["line"],"tags":{"emergency":"official"},"terms":[],"name":"Emergency Access Official","searchable":false,"matchScore":0.01},"emergency/private":{"fields":[],"geometry":["line"],"tags":{"emergency":"private"},"terms":[],"name":"Emergency Access Private","searchable":false,"matchScore":0.01},"emergency/yes":{"fields":[],"geometry":["line"],"tags":{"emergency":"yes"},"terms":[],"name":"Emergency Access Yes","searchable":false,"matchScore":0.01},"emergency/ambulance_station":{"icon":"hospital","fields":["operator","building_area","address"],"geometry":["point","area"],"terms":["EMS","EMT","rescue"],"tags":{"emergency":"ambulance_station"},"name":"Ambulance Station"},"emergency/defibrillator":{"icon":"defibrillator","fields":["access","opening_hours","indoor","phone"],"geometry":["point"],"terms":["AED"],"tags":{"emergency":"defibrillator"},"name":"Defibrillator"},"emergency/fire_hydrant":{"icon":"poi-fire-hydrant","fields":["fire_hydrant/type","fire_hydrant/position","ref","operator"],"geometry":["point","vertex"],"terms":["fire plug"],"tags":{"emergency":"fire_hydrant"},"name":"Fire Hydrant"},"emergency/phone":{"icon":"emergency-phone","fields":["operator"],"geometry":["point","vertex"],"tags":{"emergency":"phone"},"name":"Emergency Phone"},"entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"entrance":"*"},"fields":["entrance","access_simple","address"],"name":"Entrance/Exit"},"footway/crossing":{"fields":["crossing","access","surface","kerb","tactile_paving"],"geometry":["line"],"tags":{"highway":"footway","footway":"crossing"},"reference":{"key":"footway","value":"crossing"},"terms":[],"name":"Street Crossing"},"footway/crosswalk":{"icon":"highway-footway","fields":["crossing","access","surface","kerb","tactile_paving"],"geometry":["line"],"tags":{"highway":"footway","footway":"crossing","crossing":"zebra"},"reference":{"key":"highway","value":"crossing"},"terms":["zebra crossing"],"name":"Pedestrian Crosswalk"},"footway/sidewalk":{"icon":"highway-footway","fields":["surface","lit","width","structure","access"],"geometry":["line"],"tags":{"highway":"footway","footway":"sidewalk"},"reference":{"key":"footway","value":"sidewalk"},"terms":[],"name":"Sidewalk"},"ford":{"geometry":["vertex"],"tags":{"ford":"yes"},"name":"Ford"},"golf/bunker":{"icon":"golf","geometry":["area"],"tags":{"golf":"bunker","natural":"sand"},"terms":["hazard","bunker"],"reference":{"key":"golf","value":"bunker"},"name":"Sand Trap"},"golf/fairway":{"icon":"golf","geometry":["area"],"tags":{"golf":"fairway","landuse":"grass"},"reference":{"key":"golf","value":"fairway"},"name":"Fairway"},"golf/green":{"icon":"golf","geometry":["area"],"tags":{"golf":"green","landuse":"grass","leisure":"pitch","sport":"golf"},"reference":{"key":"golf","value":"green"},"name":"Putting Green"},"golf/hole":{"icon":"golf","fields":["golf_hole","par","handicap"],"geometry":["line"],"tags":{"golf":"hole"},"name":"Golf Hole"},"golf/lateral_water_hazard_area":{"icon":"golf","geometry":["area"],"tags":{"golf":"lateral_water_hazard","natural":"water"},"reference":{"key":"golf","value":"lateral_water_hazard"},"name":"Lateral Water Hazard"},"golf/lateral_water_hazard_line":{"icon":"golf","geometry":["line"],"tags":{"golf":"lateral_water_hazard"},"name":"Lateral Water Hazard"},"golf/rough":{"icon":"golf","geometry":["area"],"tags":{"golf":"rough","landuse":"grass"},"reference":{"key":"golf","value":"rough"},"name":"Rough"},"golf/tee":{"icon":"golf","geometry":["area"],"tags":{"golf":"tee","landuse":"grass"},"terms":["teeing ground"],"reference":{"key":"golf","value":"tee"},"name":"Tee Box"},"golf/water_hazard_area":{"icon":"golf","geometry":["area"],"tags":{"golf":"water_hazard","natural":"water"},"reference":{"key":"golf","value":"water_hazard"},"name":"Water Hazard"},"golf/water_hazard_line":{"icon":"golf","geometry":["line"],"tags":{"golf":"water_hazard"},"name":"Water Hazard"},"healthcare/blood_donation":{"icon":"blood-bank","fields":["operator","address","blood_components","opening_hours","ref"],"geometry":["point","area"],"terms":["blood bank","blood donation","blood transfusion","apheresis","plasmapheresis","plateletpheresis","stem cell donation"],"tags":{"healthcare":"blood_donation"},"name":"Blood Donor Center"},"highway/bridleway":{"fields":["surface","width","structure","access"],"icon":"highway-bridleway","geometry":["line"],"tags":{"highway":"bridleway"},"terms":["bridleway","equestrian","horse"],"name":"Bridle Path"},"highway/bus_stop":{"icon":"bus","fields":["network","operator","bench","shelter"],"geometry":["point","vertex"],"tags":{"highway":"bus_stop"},"terms":[],"name":"Bus Stop"},"highway/corridor":{"icon":"highway-footway","fields":["width","level","access_simple"],"geometry":["line"],"tags":{"highway":"corridor"},"terms":["gallery","hall","hallway","indoor","passage","passageway"],"name":"Indoor Corridor"},"highway/crossing":{"fields":["crossing","kerb","tactile_paving"],"geometry":["vertex"],"tags":{"highway":"crossing"},"reference":{"key":"footway","value":"crossing"},"terms":[],"name":"Street Crossing"},"highway/crosswalk":{"icon":"poi-foot","fields":["crossing","kerb","tactile_paving"],"geometry":["vertex"],"tags":{"highway":"crossing","crossing":"zebra"},"reference":{"key":"highway","value":"crossing"},"terms":["zebra crossing"],"name":"Pedestrian Crosswalk"},"highway/cycleway":{"icon":"highway-cycleway","fields":["oneway","surface","lit","width","structure","access"],"geometry":["line"],"tags":{"highway":"cycleway"},"terms":["bike"],"name":"Cycle Path"},"highway/elevator":{"icon":"poi-elevator","fields":["access_simple","opening_hours","maxweight","ref"],"geometry":["vertex"],"tags":{"highway":"elevator"},"terms":["lift"],"name":"Elevator"},"highway/footway":{"icon":"highway-footway","fields":["surface","lit","width","structure","access"],"geometry":["line","area"],"terms":["hike","hiking","trackway","trail","walk"],"tags":{"highway":"footway"},"name":"Foot Path"},"highway/give_way":{"icon":"poi-yield","fields":["parallel_direction"],"geometry":["vertex"],"tags":{"highway":"give_way"},"terms":["give way","yield","sign"],"name":"Yield Sign"},"highway/living_street":{"icon":"highway-living-street","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","access","cycleway"],"geometry":["line"],"tags":{"highway":"living_street"},"name":"Living Street"},"highway/mini_roundabout":{"icon":"circle-stroked","geometry":["vertex"],"tags":{"highway":"mini_roundabout"},"fields":["clock_direction"],"name":"Mini-Roundabout"},"highway/motorway_junction":{"icon":"poi-junction","geometry":["vertex"],"tags":{"highway":"motorway_junction"},"fields":["ref"],"name":"Motorway Junction / Exit"},"highway/motorway_link":{"icon":"highway-motorway-link","fields":["ref","oneway_yes","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"motorway_link"},"addTags":{"highway":"motorway_link","oneway":"yes"},"removeTags":{"highway":"motorway_link","oneway":"yes"},"terms":["ramp","on ramp","off ramp"],"name":"Motorway Link"},"highway/motorway":{"icon":"highway-motorway","fields":["ref","oneway_yes","maxspeed","lanes","surface","structure","maxheight","toll","access"],"geometry":["line"],"tags":{"highway":"motorway"},"terms":["autobahn","expressway","freeway","highway","interstate","parkway","thruway","turnpike"],"name":"Motorway"},"highway/path":{"icon":"highway-path","fields":["surface","width","structure","access","incline","sac_scale","trail_visibility","mtb/scale","mtb/scale/uphill","mtb/scale/imba","ref"],"geometry":["line"],"terms":["hike","hiking","trackway","trail","walk"],"tags":{"highway":"path"},"name":"Path"},"highway/pedestrian":{"icon":"highway-footway","fields":["surface","lit","width","oneway","structure","access"],"geometry":["line","area"],"tags":{"highway":"pedestrian"},"terms":[],"name":"Pedestrian Street"},"highway/primary_link":{"icon":"highway-primary-link","fields":["oneway","maxspeed","lanes","surface","maxheight","ref","cycleway","structure","access"],"geometry":["line"],"tags":{"highway":"primary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Primary Link"},"highway/primary":{"icon":"highway-primary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"primary"},"terms":[],"name":"Primary Road"},"highway/raceway":{"icon":"highway-unclassified","fields":["oneway","surface","sport_racing_motor","lit","width","lanes","structure"],"geometry":["point","line","area"],"tags":{"highway":"raceway"},"addTags":{"highway":"raceway","sport":"motor"},"terms":["auto*","formula one","kart","motocross","nascar","race*","track"],"name":"Racetrack (Motorsport)"},"highway/residential":{"icon":"highway-residential","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","cycleway","access"],"geometry":["line"],"tags":{"highway":"residential"},"terms":[],"name":"Residential Road"},"highway/rest_area":{"icon":"car","geometry":["point","vertex","area"],"tags":{"highway":"rest_area"},"terms":["rest stop"],"name":"Rest Area"},"highway/road":{"icon":"highway-road","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"road"},"terms":[],"name":"Unknown Road"},"highway/secondary_link":{"icon":"highway-secondary-link","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"secondary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Secondary Link"},"highway/secondary":{"icon":"highway-secondary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"secondary"},"terms":[],"name":"Secondary Road"},"highway/service":{"icon":"highway-service","fields":["service","oneway","maxspeed","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"service"},"terms":[],"name":"Service Road"},"highway/service/alley":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"alley"},"reference":{"key":"service","value":"alley"},"name":"Alley"},"highway/service/drive-through":{"icon":"highway-service","fields":["oneway","covered","maxheight","maxspeed","structure","access","surface"],"geometry":["line"],"tags":{"highway":"service","service":"drive-through"},"reference":{"key":"service","value":"drive-through"},"name":"Drive-Through"},"highway/service/driveway":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"driveway"},"reference":{"key":"service","value":"driveway"},"name":"Driveway"},"highway/service/emergency_access":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"emergency_access"},"reference":{"key":"service","value":"emergency_access"},"name":"Emergency Access"},"highway/service/parking_aisle":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"parking_aisle"},"reference":{"key":"service","value":"parking_aisle"},"name":"Parking Aisle"},"highway/services":{"icon":"car","geometry":["point","vertex","area"],"tags":{"highway":"services"},"terms":["services","travel plaza","service station"],"name":"Service Area"},"highway/speed_camera":{"icon":"attraction","geometry":["point"],"fields":["ref"],"tags":{"highway":"speed_camera"},"terms":[],"name":"Speed Camera"},"highway/steps":{"icon":"highway-steps","fields":["surface","lit","width","incline_steps","handrail","step_count"],"geometry":["line"],"tags":{"highway":"steps"},"terms":["stairs","staircase"],"name":"Steps"},"highway/stop":{"icon":"poi-stop","fields":["stop","parallel_direction"],"geometry":["vertex"],"tags":{"highway":"stop"},"terms":["stop","halt","sign"],"name":"Stop Sign"},"highway/street_lamp":{"icon":"poi-street-lamp","geometry":["point","vertex"],"tags":{"highway":"street_lamp"},"fields":["lamp_type","ref"],"terms":["streetlight","street light","lamp","light","gaslight"],"name":"Street Lamp"},"highway/tertiary_link":{"icon":"highway-tertiary-link","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"tertiary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Tertiary Link"},"highway/tertiary":{"icon":"highway-tertiary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"tertiary"},"terms":[],"name":"Tertiary Road"},"highway/track":{"icon":"highway-track","fields":["tracktype","surface","width","structure","access","incline","smoothness","mtb/scale","mtb/scale/uphill","mtb/scale/imba"],"geometry":["line"],"tags":{"highway":"track"},"terms":["woods road","forest road","logging road","fire road","farm road","agricultural road","ranch road","carriage road","primitive","unmaintained","rut","offroad","4wd","4x4","four wheel drive","atv","quad","jeep","double track","two track"],"name":"Unmaintained Track Road"},"highway/traffic_mirror":{"geometry":["point"],"tags":{"highway":"traffic_mirror"},"terms":["blind spot","convex","corner","curved","roadside","round","safety","sphere","visibility"],"name":"Traffic Mirror"},"highway/traffic_signals":{"icon":"poi-traffic-signals","geometry":["vertex"],"tags":{"highway":"traffic_signals"},"fields":["traffic_signals"],"terms":["light","stoplight","traffic light"],"name":"Traffic Signals"},"highway/trunk_link":{"icon":"highway-trunk-link","fields":["ref","oneway","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"trunk_link"},"terms":["ramp","on ramp","off ramp"],"name":"Trunk Link"},"highway/trunk":{"icon":"highway-trunk","fields":["ref","oneway","maxspeed","lanes","surface","structure","maxheight","toll","access"],"geometry":["line"],"tags":{"highway":"trunk"},"terms":[],"name":"Trunk Road"},"highway/turning_circle":{"icon":"circle-stroked","geometry":["vertex"],"tags":{"highway":"turning_circle"},"terms":["cul-de-sac"],"name":"Turning Circle"},"highway/turning_loop":{"icon":"circle","geometry":["vertex"],"tags":{"highway":"turning_loop"},"terms":["cul-de-sac"],"name":"Turning Loop (Island)"},"highway/unclassified":{"icon":"highway-unclassified","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","cycleway","access"],"geometry":["line"],"tags":{"highway":"unclassified"},"terms":[],"name":"Minor/Unclassified Road"},"historic":{"icon":"poi-ruins","fields":["historic","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"*"},"name":"Historic Site"},"historic/archaeological_site":{"icon":"poi-ruins","fields":["historic/civilization","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"archaeological_site"},"name":"Archaeological Site"},"historic/boundary_stone":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex"],"tags":{"historic":"boundary_stone"},"name":"Boundary Stone"},"historic/castle":{"icon":"castle","fields":["castle_type","building_area","historic/civilization"],"geometry":["point","area"],"tags":{"historic":"castle"},"name":"Castle"},"historic/memorial":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"memorial"},"name":"Memorial"},"historic/monument":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"monument"},"name":"Monument"},"historic/ruins":{"icon":"poi-ruins","fields":["historic/civilization","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"ruins"},"name":"Ruins"},"historic/tomb":{"icon":"cemetery","fields":["tomb","building_area","inscription"],"geometry":["point","area"],"tags":{"historic":"tomb"},"name":"Tomb"},"historic/wayside_cross":{"icon":"religious-christian","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"wayside_cross"},"name":"Wayside Cross"},"historic/wayside_shrine":{"icon":"landmark","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"wayside_shrine"},"name":"Wayside Shrine"},"junction":{"icon":"poi-junction","geometry":["vertex","area"],"tags":{"junction":"yes"},"name":"Junction"},"landuse":{"fields":["landuse"],"geometry":["area"],"tags":{"landuse":"*"},"matchScore":0.9,"name":"Land Use"},"landuse/farm":{"icon":"farm","fields":["operator","crop"],"geometry":["point","area"],"tags":{"landuse":"farm"},"terms":[],"name":"Farmland","searchable":false},"landuse/allotments":{"geometry":["area"],"tags":{"landuse":"allotments"},"terms":["allotment","garden"],"name":"Community Garden"},"landuse/aquaculture":{"icon":"aquarium","fields":["operator","produce"],"geometry":["area"],"tags":{"landuse":"aquaculture"},"terms":["fish farm","crustacean","algae","aquafarming","shrimp farm","oyster farm","mariculture","algaculture"],"name":"Aquaculture"},"landuse/basin":{"icon":"water","geometry":["area"],"tags":{"landuse":"basin"},"terms":[],"name":"Basin"},"landuse/cemetery":{"icon":"cemetery","fields":["religion","denomination"],"geometry":["area"],"tags":{"landuse":"cemetery"},"terms":[],"name":"Cemetery"},"landuse/churchyard":{"fields":["religion","denomination"],"geometry":["area"],"tags":{"landuse":"churchyard"},"terms":[],"name":"Churchyard"},"landuse/commercial":{"icon":"commercial","geometry":["area"],"tags":{"landuse":"commercial"},"terms":[],"name":"Commercial Area"},"landuse/construction":{"fields":["construction","operator"],"geometry":["area"],"tags":{"landuse":"construction"},"terms":[],"name":"Construction"},"landuse/farmland":{"icon":"farm","fields":["operator","crop","produce"],"geometry":["area"],"tags":{"landuse":"farmland"},"terms":["crop","grow","plant"],"name":"Farmland"},"landuse/farmyard":{"icon":"farm","fields":["operator","crop"],"geometry":["area"],"tags":{"landuse":"farmyard"},"terms":["crop","grow","plant"],"name":"Farmyard"},"landuse/forest":{"icon":"park-alt1","fields":["leaf_type","leaf_cycle","produce"],"geometry":["area"],"tags":{"landuse":"forest"},"terms":["tree"],"name":"Forest"},"landuse/garages":{"geometry":["area"],"tags":{"landuse":"garages"},"terms":[],"name":"Garages"},"landuse/grass":{"geometry":["area"],"tags":{"landuse":"grass"},"terms":[],"name":"Grass"},"landuse/harbour":{"icon":"harbor","fields":["operator"],"geometry":["area"],"terms":["boat"],"tags":{"landuse":"harbour"},"name":"Harbor"},"landuse/industrial":{"icon":"industry","geometry":["area"],"tags":{"landuse":"industrial"},"terms":[],"matchScore":0.9,"name":"Industrial Area"},"landuse/landfill":{"geometry":["area"],"tags":{"landuse":"landfill"},"terms":["dump"],"name":"Landfill"},"landuse/meadow":{"geometry":["area"],"tags":{"landuse":"meadow"},"terms":[],"name":"Meadow"},"landuse/military":{"icon":"poi-military","geometry":["area"],"tags":{"landuse":"military"},"terms":[],"matchScore":0.9,"name":"Military Area"},"landuse/military/airfield":{"icon":"airfield","fields":["ref","iata","icao"],"geometry":["point","area"],"tags":{"military":"airfield"},"addTags":{"landuse":"military","military":"airfield"},"removeTags":{"landuse":"military","military":"airfield"},"terms":["air force","army","base","bomb","fight","force","guard","heli*","jet","marine","navy","plane","troop","war"],"name":"Military Airfield"},"landuse/military/barracks":{"icon":"poi-military","fields":["building_area"],"geometry":["point","area"],"tags":{"military":"barracks"},"addTags":{"landuse":"military","military":"barracks"},"removeTags":{"landuse":"military","military":"barracks"},"terms":["air force","army","base","fight","force","guard","marine","navy","troop","war"],"name":"Barracks"},"landuse/military/bunker":{"icon":"poi-military","fields":["bunker_type","building_area"],"geometry":["point","area"],"tags":{"military":"bunker"},"addTags":{"building":"bunker","landuse":"military","military":"bunker"},"removeTags":{"building":"bunker","landuse":"military","military":"bunker"},"terms":["air force","army","base","fight","force","guard","marine","navy","troop","war"],"name":"Military Bunker"},"landuse/military/checkpoint":{"icon":"barrier","geometry":["point","vertex","area"],"tags":{"military":"checkpoint"},"addTags":{"landuse":"military","military":"checkpoint"},"removeTags":{"landuse":"military","military":"checkpoint"},"terms":["air force","army","base","force","guard","marine","navy","troop","war"],"name":"Checkpoint"},"landuse/military/danger_area":{"icon":"danger","geometry":["point","vertex","area"],"tags":{"military":"danger_area"},"addTags":{"landuse":"military","military":"danger_area"},"removeTags":{"landuse":"military","military":"danger_area"},"terms":["air force","army","base","blast","bomb","explo*","force","guard","mine","marine","navy","troop","war"],"name":"Danger Area"},"landuse/military/naval_base":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"naval_base"},"addTags":{"landuse":"military","military":"naval_base"},"removeTags":{"landuse":"military","military":"naval_base"},"terms":["base","fight","force","guard","marine","navy","ship","sub","troop","war"],"name":"Naval Base"},"landuse/military/nuclear_explosion_site":{"icon":"danger","geometry":["point","vertex","area"],"tags":{"military":"nuclear_explosion_site"},"addTags":{"landuse":"military","military":"nuclear_explosion_site"},"removeTags":{"landuse":"military","military":"nuclear_explosion_site"},"terms":["atom","blast","bomb","detonat*","nuke","site","test"],"name":"Nuclear Explosion Site"},"landuse/military/obstacle_course":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"obstacle_course"},"addTags":{"landuse":"military","military":"obstacle_course"},"removeTags":{"landuse":"military","military":"obstacle_course"},"terms":["army","base","force","guard","marine","navy","troop","war"],"name":"Obstacle Course"},"landuse/military/office":{"icon":"poi-military","fields":["building_area"],"geometry":["point","area"],"tags":{"military":"office"},"addTags":{"landuse":"military","military":"office"},"removeTags":{"landuse":"military","military":"office"},"terms":["air force","army","base","enlist","fight","force","guard","marine","navy","recruit","troop","war"],"name":"Military Office"},"landuse/military/range":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"range"},"addTags":{"landuse":"military","military":"range"},"removeTags":{"landuse":"military","military":"range"},"terms":["air force","army","base","fight","fire","force","guard","gun","marine","navy","rifle","shoot*","snip*","train","troop","war"],"name":"Military Range"},"landuse/military/training_area":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"training_area"},"addTags":{"landuse":"military","military":"training_area"},"removeTags":{"landuse":"military","military":"training_area"},"terms":["air force","army","base","fight","fire","force","guard","gun","marine","navy","rifle","shoot*","snip*","train","troop","war"],"name":"Training Area"},"landuse/orchard":{"icon":"park-alt1","fields":["operator","trees"],"geometry":["area"],"tags":{"landuse":"orchard"},"terms":["fruit"],"name":"Orchard"},"landuse/plant_nursery":{"icon":"garden","fields":["operator","plant"],"geometry":["area"],"tags":{"landuse":"plant_nursery"},"terms":["flower","garden","grow","vivero"],"name":"Plant Nursery"},"landuse/quarry":{"geometry":["area"],"tags":{"landuse":"quarry"},"terms":[],"name":"Quarry"},"landuse/railway":{"icon":"rail","fields":["operator"],"geometry":["area"],"tags":{"landuse":"railway"},"terms":["rail","train","track"],"name":"Railway Corridor"},"landuse/recreation_ground":{"icon":"pitch","geometry":["area"],"tags":{"landuse":"recreation_ground"},"terms":["playing fields"],"name":"Recreation Ground"},"landuse/residential":{"icon":"building","geometry":["area"],"tags":{"landuse":"residential"},"terms":[],"name":"Residential Area"},"landuse/retail":{"icon":"shop","geometry":["area"],"tags":{"landuse":"retail"},"name":"Retail Area"},"landuse/vineyard":{"fields":["operator","grape_variety"],"geometry":["area"],"tags":{"landuse":"vineyard"},"addTags":{"landuse":"vineyard","crop":"grape"},"removeTags":{"landuse":"vineyard","crop":"grape","grape_variety":"*"},"terms":["grape","wine"],"name":"Vineyard"},"leisure":{"icon":"pitch","fields":["leisure"],"geometry":["point","vertex","area"],"tags":{"leisure":"*"},"name":"Leisure"},"leisure/adult_gaming_centre":{"icon":"poi-dice","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"terms":["gambling","slot machine"],"tags":{"leisure":"adult_gaming_centre"},"name":"Adult Gaming Center"},"leisure/bird_hide":{"icon":"poi-binoculars","fields":["building_area"],"geometry":["point","area"],"tags":{"leisure":"bird_hide"},"terms":["machan","ornithology"],"name":"Bird Hide"},"leisure/bowling_alley":{"icon":"poi-bowling","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"terms":[],"tags":{"leisure":"bowling_alley"},"name":"Bowling Alley"},"leisure/common":{"icon":"poi-foot","geometry":["point","area"],"terms":["open space"],"tags":{"leisure":"common"},"name":"Common"},"leisure/dance":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ballroom","jive","swing","tango","waltz"],"tags":{"leisure":"dance"},"name":"Dance Hall"},"leisure/dog_park":{"icon":"dog-park","geometry":["point","area"],"terms":[],"tags":{"leisure":"dog_park"},"name":"Dog Park"},"leisure/firepit":{"icon":"fire-station","geometry":["point","area"],"tags":{"leisure":"firepit"},"terms":["fireplace","campfire"],"name":"Firepit"},"leisure/fitness_centre":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"fitness_centre"},"terms":["health","gym","leisure","studio"],"name":"Gym / Fitness Center"},"leisure/fitness_centre/yoga":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["studio"],"tags":{"leisure":"fitness_centre","sport":"yoga"},"reference":{"key":"sport","value":"yoga"},"name":"Yoga Studio"},"leisure/fitness_station":{"icon":"pitch","fields":["sport","address","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"fitness_station"},"terms":["fitness","gym"],"name":"Outdoor Fitness Station"},"leisure/garden":{"icon":"garden","fields":["access_simple"],"geometry":["point","vertex","area"],"tags":{"leisure":"garden"},"name":"Garden"},"leisure/golf_course":{"icon":"golf","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["links"],"tags":{"leisure":"golf_course"},"name":"Golf Course"},"leisure/horse_riding":{"icon":"horse-riding","fields":["access_simple","operator","address","building"],"geometry":["point","area"],"terms":["equestrian","stable"],"tags":{"leisure":"horse_riding"},"name":"Horseback Riding Facility"},"leisure/ice_rink":{"icon":"pitch","fields":["seasonal","sport_ice","operator","address","building","opening_hours"],"geometry":["point","area"],"terms":["hockey","skating","curling"],"tags":{"leisure":"ice_rink"},"name":"Ice Rink"},"leisure/marina":{"icon":"harbor","fields":["operator","address","capacity","fee","sanitary_dump_station","power_supply","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["boat"],"tags":{"leisure":"marina"},"name":"Marina"},"leisure/miniature_golf":{"icon":"golf","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["crazy golf","mini golf","putt-putt"],"tags":{"leisure":"miniature_golf"},"name":"Miniature Golf"},"leisure/nature_reserve":{"icon":"park","geometry":["point","area"],"tags":{"leisure":"nature_reserve"},"terms":["protected","wildlife"],"name":"Nature Reserve"},"leisure/park":{"icon":"park","geometry":["point","area"],"terms":["esplanade","estate","forest","garden","grass","green","grounds","lawn","lot","meadow","parkland","place","playground","plaza","pleasure garden","recreation area","square","tract","village green","woodland"],"tags":{"leisure":"park"},"name":"Park"},"leisure/picnic_table":{"icon":"picnic-site","geometry":["point"],"tags":{"leisure":"picnic_table"},"terms":["bench"],"name":"Picnic Table"},"leisure/pitch":{"icon":"pitch","fields":["sport","surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch"},"terms":["field"],"name":"Sport Pitch"},"leisure/pitch/american_football":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"american_football"},"reference":{"key":"sport","value":"american_football"},"terms":[],"name":"American Football Field"},"leisure/pitch/baseball":{"icon":"baseball","fields":["lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"baseball"},"reference":{"key":"sport","value":"baseball"},"terms":[],"name":"Baseball Diamond"},"leisure/pitch/basketball":{"icon":"basketball","fields":["surface","hoops","lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"basketball"},"reference":{"key":"sport","value":"basketball"},"terms":[],"name":"Basketball Court"},"leisure/pitch/beachvolleyball":{"icon":"basketball","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"beachvolleyball"},"addTags":{"leisure":"pitch","sport":"beachvolleyball","surface":"sand"},"removeTags":{"leisure":"pitch","sport":"beachvolleyball","surface":"sand"},"reference":{"key":"sport","value":"beachvolleyball"},"terms":["volleyball"],"name":"Beach Volleyball Court"},"leisure/pitch/bowls":{"icon":"pitch","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"bowls"},"reference":{"key":"sport","value":"bowls"},"terms":[],"name":"Bowling Green"},"leisure/pitch/cricket":{"icon":"cricket","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"cricket"},"reference":{"key":"sport","value":"cricket"},"terms":[],"name":"Cricket Field"},"leisure/pitch/equestrian":{"icon":"horse-riding","fields":["surface","lit","building"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"equestrian"},"reference":{"key":"sport","value":"equestrian"},"terms":["dressage","equestrian","horse","horseback","riding"],"name":"Riding Arena"},"leisure/pitch/rugby_league":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"rugby_league"},"reference":{"key":"sport","value":"rugby_league"},"terms":[],"name":"Rugby League Field"},"leisure/pitch/rugby_union":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"rugby_union"},"reference":{"key":"sport","value":"rugby_union"},"terms":[],"name":"Rugby Union Field"},"leisure/pitch/skateboard":{"icon":"pitch","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"skateboard"},"reference":{"key":"sport","value":"skateboard"},"terms":[],"name":"Skate Park"},"leisure/pitch/soccer":{"icon":"soccer","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"soccer"},"reference":{"key":"sport","value":"soccer"},"terms":["football"],"name":"Soccer Field"},"leisure/pitch/table_tennis":{"icon":"tennis","fields":["lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"table_tennis"},"reference":{"key":"sport","value":"table_tennis"},"terms":["table tennis","ping pong"],"name":"Ping Pong Table"},"leisure/pitch/tennis":{"icon":"tennis","fields":["surface","lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"tennis"},"reference":{"key":"sport","value":"tennis"},"terms":[],"name":"Tennis Court"},"leisure/pitch/volleyball":{"icon":"basketball","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"volleyball"},"reference":{"key":"sport","value":"volleyball"},"terms":[],"name":"Volleyball Court"},"leisure/playground":{"icon":"playground","geometry":["point","area"],"terms":["jungle gym","play area"],"tags":{"leisure":"playground"},"name":"Playground"},"leisure/resort":{"icon":"lodging","fields":["operator","address","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"resort"},"name":"Resort"},"leisure/running_track":{"icon":"pitch","fields":["surface","sport_racing_nonmotor","lit","width","lanes"],"geometry":["point","line","area"],"tags":{"leisure":"track","sport":"running"},"terms":["race*","running","sprint","track"],"name":"Racetrack (Running)"},"leisure/slipway":{"icon":"poi-beach","geometry":["point","line"],"terms":["boat launch","boat ramp"],"tags":{"leisure":"slipway"},"name":"Slipway"},"leisure/sports_centre":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"sports_centre"},"terms":[],"name":"Sports Center / Complex"},"leisure/sports_centre/swimming":{"icon":"swimming","fields":["access_simple","operator","address","building"],"geometry":["point","area"],"terms":["dive","water"],"tags":{"leisure":"sports_centre","sport":"swimming"},"reference":{"key":"sport","value":"swimming"},"name":"Swimming Pool Facility"},"leisure/stadium":{"icon":"pitch","fields":["sport","address"],"geometry":["point","area"],"tags":{"leisure":"stadium"},"name":"Stadium"},"leisure/swimming_pool":{"icon":"swimming","fields":["access_simple","operator","address"],"geometry":["point","area"],"terms":["dive","water"],"tags":{"leisure":"swimming_pool"},"name":"Swimming Pool"},"leisure/track":{"icon":"highway-road","fields":["surface","sport_racing_nonmotor","lit","width","lanes"],"geometry":["point","line","area"],"tags":{"leisure":"track"},"terms":["cycle","dog","greyhound","horse","race*","track"],"name":"Racetrack (Non-Motorsport)"},"leisure/water_park":{"icon":"swimming","fields":["operator","address"],"geometry":["point","area"],"terms":["swim","pool","dive"],"tags":{"leisure":"water_park"},"name":"Water Park"},"line":{"name":"Line","tags":{},"geometry":["line"],"matchScore":0.1},"man_made":{"icon":"poi-storage-tank","fields":["man_made"],"geometry":["point","vertex","line","area"],"tags":{"man_made":"*"},"name":"Man Made"},"man_made/embankment":{"geometry":["line"],"tags":{"man_made":"embankment"},"name":"Embankment","searchable":false},"man_made/adit":{"icon":"triangle","geometry":["point","area"],"fields":["operator"],"terms":["entrance","underground","mine","cave"],"tags":{"man_made":"adit"},"name":"Adit"},"man_made/breakwater":{"geometry":["line","area"],"tags":{"man_made":"breakwater"},"name":"Breakwater"},"man_made/bridge":{"geometry":["area"],"tags":{"man_made":"bridge"},"name":"Bridge"},"man_made/chimney":{"icon":"poi-chimney","geometry":["point","area"],"tags":{"man_made":"chimney"},"name":"Chimney"},"man_made/cutline":{"geometry":["line"],"tags":{"man_made":"cutline"},"name":"Cut line"},"man_made/flagpole":{"icon":"embassy","geometry":["point"],"tags":{"man_made":"flagpole"},"name":"Flagpole"},"man_made/gasometer":{"icon":"poi-storage-tank","geometry":["point","area"],"terms":["gas holder"],"tags":{"man_made":"gasometer"},"name":"Gasometer"},"man_made/groyne":{"geometry":["line","area"],"tags":{"man_made":"groyne"},"name":"Groyne"},"man_made/lighthouse":{"icon":"lighthouse","fields":["building_area"],"geometry":["point","area"],"tags":{"man_made":"lighthouse"},"name":"Lighthouse"},"man_made/mast":{"icon":"poi-mast","fields":["tower/type","tower/construction","height","communication_multi"],"geometry":["point"],"terms":["antenna","broadcast tower","cell phone tower","cell tower","communication mast","communication tower","guyed tower","mobile phone tower","radio mast","radio tower","television tower","transmission mast","transmission tower","tv tower"],"tags":{"man_made":"mast"},"name":"Mast"},"man_made/observation":{"icon":"poi-tower","geometry":["point","area"],"terms":["lookout tower","fire tower"],"tags":{"man_made":"tower","tower:type":"observation"},"name":"Observation Tower"},"man_made/petroleum_well":{"icon":"poi-storage-tank","geometry":["point"],"terms":["drilling rig","oil derrick","oil drill","oil horse","oil rig","oil pump","petroleum well","pumpjack"],"tags":{"man_made":"petroleum_well"},"name":"Oil Well"},"man_made/pier":{"geometry":["line","area"],"terms":["dock"],"tags":{"man_made":"pier"},"name":"Pier"},"man_made/pipeline":{"icon":"pipeline-line","fields":["location","operator"],"geometry":["line"],"tags":{"man_made":"pipeline"},"name":"Pipeline"},"man_made/pumping_station":{"icon":"water","geometry":["point","area"],"tags":{"man_made":"pumping_station"},"name":"Pumping Station"},"man_made/silo":{"icon":"poi-silo","fields":["building_area","crop"],"geometry":["point","area"],"terms":["grain","corn","wheat"],"tags":{"man_made":"silo"},"name":"Silo"},"man_made/storage_tank":{"icon":"poi-storage-tank","fields":["building_area","content"],"geometry":["point","area"],"terms":["water","oil","gas","petrol"],"tags":{"man_made":"storage_tank"},"name":"Storage Tank"},"man_made/surveillance_camera":{"icon":"attraction","geometry":["point"],"fields":["surveillance","surveillance/type","camera/type","camera/mount","camera/direction","surveillance/zone","contact/webcam"],"terms":["anpr","alpr","camera","car plate recognition","cctv","guard","license plate recognition","monitoring","number plate recognition","security","video","webcam"],"tags":{"man_made":"surveillance","surveillance:type":"camera"},"name":"Surveillance Camera"},"man_made/surveillance":{"icon":"attraction","geometry":["point"],"fields":["surveillance","surveillance/type","surveillance/zone"],"terms":["anpr","alpr","camera","car plate recognition","cctv","guard","license plate recognition","monitoring","number plate recognition","security","video","webcam"],"tags":{"man_made":"surveillance"},"name":"Surveillance"},"man_made/survey_point":{"icon":"monument","fields":["ref"],"geometry":["point","vertex"],"tags":{"man_made":"survey_point"},"name":"Survey Point"},"man_made/tower":{"icon":"poi-tower","fields":["tower/type","tower/construction","height"],"geometry":["point","area"],"tags":{"man_made":"tower"},"name":"Tower"},"man_made/wastewater_plant":{"icon":"water","fields":["operator","address"],"geometry":["point","area"],"terms":["sewage*","water treatment plant","reclamation plant"],"tags":{"man_made":"wastewater_plant"},"name":"Wastewater Plant"},"man_made/water_tower":{"icon":"water","fields":["operator"],"geometry":["point","area"],"tags":{"man_made":"water_tower"},"name":"Water Tower"},"man_made/water_well":{"icon":"water","fields":["operator"],"geometry":["point","area"],"tags":{"man_made":"water_well"},"name":"Water Well"},"man_made/water_works":{"icon":"water","fields":["operator","address"],"geometry":["point","area"],"tags":{"man_made":"water_works"},"name":"Water Works"},"man_made/watermill":{"icon":"buddhism","fields":["building_area"],"geometry":["point","area"],"terms":["water","wheel","mill"],"tags":{"man_made":"watermill"},"name":"Watermill"},"man_made/windmill":{"icon":"poi-windmill","fields":["building_area"],"geometry":["point","area"],"terms":["wind","wheel","mill"],"tags":{"man_made":"windmill"},"name":"Windmill"},"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"},"manhole":{"icon":"circle-stroked","fields":["manhole","operator","label","ref"],"geometry":["point","vertex"],"tags":{"manhole":"*"},"terms":["cover","hole","sewer","sewage","telecom"],"name":"Manhole"},"manhole/drain":{"icon":"water","fields":["operator","ref"],"geometry":["point","vertex"],"tags":{"manhole":"drain"},"terms":["cover","drain","hole","rain","sewer","sewage","storm"],"name":"Storm Drain"},"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","generator/output/electricity"],"geometry":["point","vertex","area"],"terms":["hydro","solar","turbine","wind"],"tags":{"power":"generator"},"name":"Power Generator"},"power/generator/source_nuclear":{"icon":"poi-nuclear","fields":["operator","generator/source","generator/method","generator/type","generator/output/electricity"],"geometry":["point","vertex","area"],"terms":["fission","generator","nuclear","nuke","reactor"],"tags":{"power":"generator","generator:source":"nuclear","generator:method":"fission"},"reference":{"key":"generator:source","value":"nuclear"},"name":"Nuclear Reactor"},"power/generator/source_wind":{"icon":"poi-wind","fields":["operator","generator/source","generator/method","generator/type","generator/output/electricity","height"],"geometry":["point","vertex","area"],"terms":["generator","turbine","windmill","wind"],"tags":{"power":"generator","generator:source":"wind","generator:method":"wind_turbine"},"reference":{"key":"generator:source","value":"wind"},"name":"Wind Turbine"},"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","address","plant/output/electricity","start_date"],"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","vertex"],"tags":{"railway":"subway_entrance"},"terms":["metro","transit"],"name":"Subway Entrance"},"railway/subway":{"icon":"railway-subway","geometry":["line"],"tags":{"railway":"subway"},"fields":["structure","gauge","electrified","service_rail"],"terms":["metro","transit"],"name":"Subway"},"railway/tram_stop":{"icon":"rail-light","fields":["network","operator"],"geometry":["vertex"],"tags":{"railway":"tram_stop"},"terms":["light rail","streetcar","tram","trolley"],"name":"Tram Stop"},"railway/tram":{"icon":"railway-light-rail","geometry":["line"],"tags":{"railway":"tram"},"fields":["structure","gauge","electrified","service_rail"],"terms":["light rail","streetcar","tram","trolley"],"name":"Tram"},"relation":{"name":"Relation","icon":"relation","tags":{},"geometry":["relation"],"fields":["relation"]},"route/ferry":{"icon":"ferry-line","geometry":["line"],"tags":{"route":"ferry"},"name":"Ferry Route"},"shop":{"icon":"shop","fields":["shop","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"*"},"terms":[],"name":"Shop"},"shop/fishmonger":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"fishmonger"},"reference":{"key":"shop","value":"seafood"},"name":"Fishmonger","searchable":false},"shop/vacant":{"icon":"shop","fields":["address","building_area"],"geometry":["point","area"],"tags":{"shop":"vacant"},"name":"Vacant Shop","searchable":false},"shop/alcohol":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours","drive_through"],"geometry":["point","area"],"terms":["alcohol","beer","booze","wine"],"tags":{"shop":"alcohol"},"name":"Liquor Store"},"shop/anime":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"anime"},"terms":["manga","japan","cosplay","figurine","dakimakura"],"name":"Anime Shop"},"shop/antiques":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"antiques"},"name":"Antiques Shop"},"shop/appliance":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["air conditioner","appliance","dishwasher","dryer","freezer","fridge","grill","kitchen","oven","refrigerator","stove","washer","washing machine"],"tags":{"shop":"appliance"},"name":"Appliance Store"},"shop/art":{"icon":"shop","fields":["artwork_type","operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["art*","exhibit*","gallery"],"tags":{"shop":"art"},"name":"Art Store"},"shop/baby_goods":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"baby_goods"},"name":"Baby Goods Store"},"shop/bag":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["handbag","purse"],"tags":{"shop":"bag"},"name":"Bag/Luggage Store"},"shop/bakery":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"bakery"},"name":"Bakery"},"shop/bathroom_furnishing":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"bathroom_furnishing"},"name":"Bathroom Furnishing Store"},"shop/beauty":{"icon":"shop","fields":["operator","address","building_area","opening_hours","beauty"],"geometry":["point","area"],"terms":["spa","salon","tanning"],"tags":{"shop":"beauty"},"name":"Beauty Shop"},"shop/beauty/nails":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["manicure","pedicure"],"tags":{"shop":"beauty","beauty":"nails"},"reference":{"key":"shop","value":"beauty"},"name":"Nail Salon"},"shop/beauty/tanning":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"beauty","beauty":"tanning"},"reference":{"key":"leisure","value":"tanning_salon"},"name":"Tanning Salon"},"shop/bed":{"icon":"lodging","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"bed"},"name":"Bedding/Mattress Store"},"shop/beverages":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"beverages"},"name":"Beverage Store"},"shop/bicycle":{"icon":"bicycle","fields":["operator","address","building_area","opening_hours","service/bicycle"],"geometry":["point","area"],"terms":["bike","repair"],"tags":{"shop":"bicycle"},"name":"Bicycle Shop"},"shop/bookmaker":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["betting"],"tags":{"shop":"bookmaker"},"name":"Bookmaker"},"shop/books":{"icon":"shop","fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"shop":"books"},"name":"Book Store"},"shop/boutique":{"icon":"shop","fields":["clothes","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":["clothes","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"clothes"},"name":"Clothing Store"},"shop/coffee":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"coffee"},"name":"Coffee Store"},"shop/computer":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"computer"},"name":"Computer Store"},"shop/confectionery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"confectionery"},"name":"Candy Store"},"shop/convenience":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"convenience"},"name":"Convenience Store"},"shop/copyshop":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"copyshop"},"name":"Copy Store"},"shop/cosmetics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"cosmetics"},"name":"Cosmetics Store"},"shop/craft":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"craft"},"terms":["art*","paint*","frame"],"name":"Arts and Crafts Store"},"shop/curtain":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["drape*","window"],"tags":{"shop":"curtain"},"name":"Curtain Store"},"shop/dairy":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["milk","egg","cheese"],"tags":{"shop":"dairy"},"name":"Dairy Store"},"shop/deli":{"icon":"restaurant","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["lunch","meat","sandwich"],"tags":{"shop":"deli"},"name":"Deli"},"shop/department_store":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"department_store"},"name":"Department Store"},"shop/doityourself":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"doityourself"},"name":"DIY Store"},"shop/dry_cleaning":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"dry_cleaning"},"name":"Dry Cleaner"},"shop/e-cigarette":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"e-cigarette"},"terms":["electronic","vapor"],"name":"E-Cigarette Shop"},"shop/electronics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["appliance","audio","blueray","camera","computer","dvd","home theater","radio","speaker","tv","video"],"tags":{"shop":"electronics"},"name":"Electronics Store"},"shop/erotic":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sex","porn"],"tags":{"shop":"erotic"},"name":"Erotic Store"},"shop/fabric":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sew"],"tags":{"shop":"fabric"},"name":"Fabric Store"},"shop/farm":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["farm shop","farm stand"],"tags":{"shop":"farm"},"name":"Produce Stand"},"shop/fashion":{"icon":"shop","fields":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/洋服の青山":{"tags":{"name":"洋服の青山","shop":"clothes"},"name":"洋服の青山","icon":"clothing-store","geometry":["point","area"],"fields":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","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":["clothes","operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/ユニクロ":{"tags":{"name":"ユニクロ","shop":"clothes"},"name":"ユニクロ","icon":"clothing-store","geometry":["point","area"],"fields":["clothes","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":["clothes","operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Одежда":{"tags":{"name":"Одежда","shop":"clothes"},"name":"Одежда","icon":"clothing-store","geometry":["point","area"],"fields":["clothes","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":["clothes","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":["clothes","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":["clothes","operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/しまむら":{"tags":{"name":"しまむら","shop":"clothes"},"name":"しまむら","icon":"clothing-store","geometry":["point","area"],"fields":["clothes","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"}}},"clothes":{"key":"clothes","type":"semiCombo","label":"Clothes"},"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":"Content"},"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/output/electricity":{"key":"generator:output:electricity","type":"text","label":"Power Output","placeholder":"50 MW, 100 MW, 200 MW..."},"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"},"label":{"key":"label","type":"textarea","label":"Label"},"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"},"manhole":{"key":"manhole","type":"typeCombo","label":"Type"},"map_size":{"key":"map_size","type":"typeCombo","label":"Coverage"},"map_type":{"key":"map_type","type":"typeCombo","label":"Type"},"maxheight":{"key":"maxheight","type":"combo","label":"Max Height","placeholder":"4, 4.5, 5, 14'0\", 14'6\", 15'0\"","snake_case":false},"maxspeed":{"key":"maxspeed","type":"maxspeed","label":"Speed Limit","placeholder":"40, 50, 60..."},"maxstay":{"key":"maxstay","type":"combo","label":"Max Stay","options":["15 min","30 min","45 min","1 hr","1.5 hr","2 hr","2.5 hr","3 hr","4 hr","1 day","2 day"],"snake_case":false},"maxweight":{"key":"maxweight","type":"combo","label":"Max Weight","snake_case":false},"mtb/scale":{"key":"mtb:scale","type":"combo","label":"Mountain Biking Difficulty","placeholder":"0, 1, 2, 3...","strings":{"options":{"0":"0: Solid gravel/packed earth, no obstacles, wide curves","1":"1: Some loose surface, small obstacles, wide curves","2":"2: Much loose surface, large obstacles, easy hairpins","3":"3: Slippery surface, large obstacles, tight hairpins","4":"4: Loose surface or boulders, dangerous hairpins","5":"5: Maximum difficulty, boulder fields, landslides","6":"6: Not rideable except by the very best mountain bikers"}}},"mtb/scale/imba":{"key":"mtb:scale:imba","type":"combo","label":"IMBA Trail Difficulty","placeholder":"Easy, Medium, Difficult...","strings":{"options":{"0":"Easiest (white circle)","1":"Easy (green circle)","2":"Medium (blue square)","3":"Difficult (black diamond)","4":"Extremely Difficult (double black diamond)"}}},"mtb/scale/uphill":{"key":"mtb:scale:uphill","type":"combo","label":"Mountain Biking Uphill Difficulty","placeholder":"0, 1, 2, 3...","strings":{"options":{"0":"0: Avg. incline <10%, gravel/packed earth, no obstacles","1":"1: Avg. incline <15%, gravel/packed earth, few small objects","2":"2: Avg. incline <20%, stable surface, fistsize rocks/roots","3":"3: Avg. incline <25%, variable surface, fistsize rocks/branches","4":"4: Avg. incline <30%, poor condition, big rocks/branches","5":"5: Very steep, bike generally needs to be pushed or carried"}}},"name":{"key":"name","type":"localized","label":"Name","placeholder":"Common name (if any)"},"natural":{"key":"natural","type":"typeCombo","label":"Natural"},"network_bicycle":{"key":"network","type":"combo","label":"Network Type","placeholder":"Local, Regional, National, International","strings":{"options":{"lcn":"Local","rcn":"Regional","ncn":"National","icn":"International"}}},"network_foot":{"key":"network","type":"combo","label":"Network Type","placeholder":"Local, Regional, National, International","strings":{"options":{"lwn":"Local","rwn":"Regional","nwn":"National","iwn":"International"}}},"network_horse":{"key":"network","type":"combo","label":"Network Type","placeholder":"Local, Regional, National, International","strings":{"options":{"lhn":"Local","rhn":"Regional","nhn":"National","ihn":"International"}}},"network_road":{"key":"network","type":"networkCombo","label":"Network"},"network":{"key":"network","type":"text","label":"Network"},"note":{"key":"note","type":"textarea","universal":true,"icon":"note","label":"Note"},"office":{"key":"office","type":"typeCombo","label":"Type"},"oneway_yes":{"key":"oneway","type":"onewayCheck","label":"One Way","strings":{"options":{"undefined":"Assumed to be Yes","yes":"Yes","no":"No"}}},"oneway":{"key":"oneway","type":"onewayCheck","label":"One Way","strings":{"options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}}},"opening_hours":{"key":"opening_hours","type":"combo","label":"Hours","snake_case":false},"operator":{"key":"operator","type":"text","label":"Operator"},"outdoor_seating":{"key":"outdoor_seating","type":"check","label":"Outdoor Seating"},"par":{"key":"par","type":"number","label":"Par","placeholder":"3, 4, 5..."},"parallel_direction":{"key":"direction","type":"combo","label":"Direction","strings":{"options":{"forward":"Forward","backward":"Backward"}}},"park_ride":{"key":"park_ride","type":"check","label":"Park and Ride"},"parking":{"key":"parking","type":"combo","label":"Type","strings":{"options":{"surface":"Surface","multi-storey":"Multilevel","underground":"Underground","sheds":"Sheds","carports":"Carports","garage_boxes":"Garage Boxes","lane":"Roadside Lane"}}},"payment_multi":{"key":"payment:","type":"multiCombo","label":"Payment Types"},"phone":{"key":"phone","type":"tel","icon":"telephone","universal":true,"label":"Phone","placeholder":"+31 42 123 4567"},"piste/difficulty":{"key":"piste:difficulty","type":"combo","label":"Difficulty","placeholder":"Easy, Intermediate, Advanced...","strings":{"options":{"novice":"Novice (instructional)","easy":"Easy (green circle)","intermediate":"Intermediate (blue square)","advanced":"Advanced (black diamond)","expert":"Expert (double black diamond)","freeride":"Freeride (off-piste)","extreme":"Extreme (climbing equipment required)"}}},"piste/grooming":{"key":"piste:grooming","type":"combo","label":"Grooming","strings":{"options":{"classic":"Classic","mogul":"Mogul","backcountry":"Backcountry","classic+skating":"Classic and Skating","scooter":"Scooter/Snowmobile","skating":"Skating"}}},"piste/type":{"key":"piste:type","type":"typeCombo","label":"Type","strings":{"options":{"downhill":"Downhill","nordic":"Nordic","skitour":"Skitour","sled":"Sled","hike":"Hike","sleigh":"Sleigh","ice_skate":"Ice Skate","snow_park":"Snow Park","playground":"Playground"}}},"place":{"key":"place","type":"typeCombo","label":"Type"},"plant":{"key":"plant","type":"combo","label":"Plant"},"plant/output/electricity":{"key":"plant:output:electricity","type":"text","label":"Power Output","placeholder":"500 MW, 1000 MW, 2000 MW..."},"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.10.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.5) + ",0)";
19838 }
19839
19840 function translateY(y) {
19841   return "translate(0," + (y + 0.5) + ")";
19842 }
19843
19844 function number$1(scale) {
19845   return function(d) {
19846     return +scale(d);
19847   };
19848 }
19849
19850 function center(scale) {
19851   var offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset.
19852   if (scale.round()) offset = Math.round(offset);
19853   return function(d) {
19854     return +scale(d) + offset;
19855   };
19856 }
19857
19858 function entering() {
19859   return !this.__axis;
19860 }
19861
19862 function axis(orient, scale) {
19863   var tickArguments = [],
19864       tickValues = null,
19865       tickFormat = null,
19866       tickSizeInner = 6,
19867       tickSizeOuter = 6,
19868       tickPadding = 3,
19869       k = orient === top || orient === left ? -1 : 1,
19870       x = orient === left || orient === right ? "x" : "y",
19871       transform = orient === top || orient === bottom ? translateX : translateY;
19872
19873   function axis(context) {
19874     var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
19875         format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$1) : tickFormat,
19876         spacing = Math.max(tickSizeInner, 0) + tickPadding,
19877         range = scale.range(),
19878         range0 = +range[0] + 0.5,
19879         range1 = +range[range.length - 1] + 0.5,
19880         position = (scale.bandwidth ? center : number$1)(scale.copy()),
19881         selection = context.selection ? context.selection() : context,
19882         path = selection.selectAll(".domain").data([null]),
19883         tick = selection.selectAll(".tick").data(values, scale).order(),
19884         tickExit = tick.exit(),
19885         tickEnter = tick.enter().append("g").attr("class", "tick"),
19886         line = tick.select("line"),
19887         text = tick.select("text");
19888
19889     path = path.merge(path.enter().insert("path", ".tick")
19890         .attr("class", "domain")
19891         .attr("stroke", "#000"));
19892
19893     tick = tick.merge(tickEnter);
19894
19895     line = line.merge(tickEnter.append("line")
19896         .attr("stroke", "#000")
19897         .attr(x + "2", k * tickSizeInner));
19898
19899     text = text.merge(tickEnter.append("text")
19900         .attr("fill", "#000")
19901         .attr(x, k * spacing)
19902         .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
19903
19904     if (context !== selection) {
19905       path = path.transition(context);
19906       tick = tick.transition(context);
19907       line = line.transition(context);
19908       text = text.transition(context);
19909
19910       tickExit = tickExit.transition(context)
19911           .attr("opacity", epsilon)
19912           .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); });
19913
19914       tickEnter
19915           .attr("opacity", epsilon)
19916           .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); });
19917     }
19918
19919     tickExit.remove();
19920
19921     path
19922         .attr("d", orient === left || orient == right
19923             ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter
19924             : "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter);
19925
19926     tick
19927         .attr("opacity", 1)
19928         .attr("transform", function(d) { return transform(position(d)); });
19929
19930     line
19931         .attr(x + "2", k * tickSizeInner);
19932
19933     text
19934         .attr(x, k * spacing)
19935         .text(format);
19936
19937     selection.filter(entering)
19938         .attr("fill", "none")
19939         .attr("font-size", 10)
19940         .attr("font-family", "sans-serif")
19941         .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
19942
19943     selection
19944         .each(function() { this.__axis = position; });
19945   }
19946
19947   axis.scale = function(_) {
19948     return arguments.length ? (scale = _, axis) : scale;
19949   };
19950
19951   axis.ticks = function() {
19952     return tickArguments = slice$1.call(arguments), axis;
19953   };
19954
19955   axis.tickArguments = function(_) {
19956     return arguments.length ? (tickArguments = _ == null ? [] : slice$1.call(_), axis) : tickArguments.slice();
19957   };
19958
19959   axis.tickValues = function(_) {
19960     return arguments.length ? (tickValues = _ == null ? null : slice$1.call(_), axis) : tickValues && tickValues.slice();
19961   };
19962
19963   axis.tickFormat = function(_) {
19964     return arguments.length ? (tickFormat = _, axis) : tickFormat;
19965   };
19966
19967   axis.tickSize = function(_) {
19968     return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
19969   };
19970
19971   axis.tickSizeInner = function(_) {
19972     return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
19973   };
19974
19975   axis.tickSizeOuter = function(_) {
19976     return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
19977   };
19978
19979   axis.tickPadding = function(_) {
19980     return arguments.length ? (tickPadding = +_, axis) : tickPadding;
19981   };
19982
19983   return axis;
19984 }
19985
19986 function axisTop(scale) {
19987   return axis(top, scale);
19988 }
19989
19990 function axisRight(scale) {
19991   return axis(right, scale);
19992 }
19993
19994 function axisBottom(scale) {
19995   return axis(bottom, scale);
19996 }
19997
19998 function axisLeft(scale) {
19999   return axis(left, scale);
20000 }
20001
20002 var noop = {value: function() {}};
20003
20004 function dispatch() {
20005   for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
20006     if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
20007     _[t] = [];
20008   }
20009   return new Dispatch(_);
20010 }
20011
20012 function Dispatch(_) {
20013   this._ = _;
20014 }
20015
20016 function parseTypenames(typenames, types) {
20017   return typenames.trim().split(/^|\s+/).map(function(t) {
20018     var name = "", i = t.indexOf(".");
20019     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20020     if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
20021     return {type: t, name: name};
20022   });
20023 }
20024
20025 Dispatch.prototype = dispatch.prototype = {
20026   constructor: Dispatch,
20027   on: function(typename, callback) {
20028     var _ = this._,
20029         T = parseTypenames(typename + "", _),
20030         t,
20031         i = -1,
20032         n = T.length;
20033
20034     // If no callback was specified, return the callback of the given type and name.
20035     if (arguments.length < 2) {
20036       while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
20037       return;
20038     }
20039
20040     // If a type was specified, set the callback for the given type and name.
20041     // Otherwise, if a null callback was specified, remove callbacks of the given name.
20042     if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
20043     while (++i < n) {
20044       if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
20045       else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
20046     }
20047
20048     return this;
20049   },
20050   copy: function() {
20051     var copy = {}, _ = this._;
20052     for (var t in _) copy[t] = _[t].slice();
20053     return new Dispatch(copy);
20054   },
20055   call: function(type, that) {
20056     if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
20057     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20058     for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20059   },
20060   apply: function(type, that, args) {
20061     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20062     for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20063   }
20064 };
20065
20066 function get(type, name) {
20067   for (var i = 0, n = type.length, c; i < n; ++i) {
20068     if ((c = type[i]).name === name) {
20069       return c.value;
20070     }
20071   }
20072 }
20073
20074 function set(type, name, callback) {
20075   for (var i = 0, n = type.length; i < n; ++i) {
20076     if (type[i].name === name) {
20077       type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
20078       break;
20079     }
20080   }
20081   if (callback != null) type.push({name: name, value: callback});
20082   return type;
20083 }
20084
20085 var xhtml = "http://www.w3.org/1999/xhtml";
20086
20087 var namespaces = {
20088   svg: "http://www.w3.org/2000/svg",
20089   xhtml: xhtml,
20090   xlink: "http://www.w3.org/1999/xlink",
20091   xml: "http://www.w3.org/XML/1998/namespace",
20092   xmlns: "http://www.w3.org/2000/xmlns/"
20093 };
20094
20095 var namespace = function(name) {
20096   var prefix = name += "", i = prefix.indexOf(":");
20097   if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
20098   return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
20099 };
20100
20101 function creatorInherit(name) {
20102   return function() {
20103     var document = this.ownerDocument,
20104         uri = this.namespaceURI;
20105     return uri === xhtml && document.documentElement.namespaceURI === xhtml
20106         ? document.createElement(name)
20107         : document.createElementNS(uri, name);
20108   };
20109 }
20110
20111 function creatorFixed(fullname) {
20112   return function() {
20113     return this.ownerDocument.createElementNS(fullname.space, fullname.local);
20114   };
20115 }
20116
20117 var creator = function(name) {
20118   var fullname = namespace(name);
20119   return (fullname.local
20120       ? creatorFixed
20121       : creatorInherit)(fullname);
20122 };
20123
20124 var nextId = 0;
20125
20126 function local$1() {
20127   return new Local;
20128 }
20129
20130 function Local() {
20131   this._ = "@" + (++nextId).toString(36);
20132 }
20133
20134 Local.prototype = local$1.prototype = {
20135   constructor: Local,
20136   get: function(node) {
20137     var id = this._;
20138     while (!(id in node)) if (!(node = node.parentNode)) return;
20139     return node[id];
20140   },
20141   set: function(node, value) {
20142     return node[this._] = value;
20143   },
20144   remove: function(node) {
20145     return this._ in node && delete node[this._];
20146   },
20147   toString: function() {
20148     return this._;
20149   }
20150 };
20151
20152 var matcher = function(selector) {
20153   return function() {
20154     return this.matches(selector);
20155   };
20156 };
20157
20158 if (typeof document !== "undefined") {
20159   var element = document.documentElement;
20160   if (!element.matches) {
20161     var vendorMatches = element.webkitMatchesSelector
20162         || element.msMatchesSelector
20163         || element.mozMatchesSelector
20164         || element.oMatchesSelector;
20165     matcher = function(selector) {
20166       return function() {
20167         return vendorMatches.call(this, selector);
20168       };
20169     };
20170   }
20171 }
20172
20173 var matcher$1 = matcher;
20174
20175 var filterEvents = {};
20176
20177 var event = null;
20178
20179 if (typeof document !== "undefined") {
20180   var element$1 = document.documentElement;
20181   if (!("onmouseenter" in element$1)) {
20182     filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
20183   }
20184 }
20185
20186 function filterContextListener(listener, index, group) {
20187   listener = contextListener(listener, index, group);
20188   return function(event) {
20189     var related = event.relatedTarget;
20190     if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
20191       listener.call(this, event);
20192     }
20193   };
20194 }
20195
20196 function contextListener(listener, index, group) {
20197   return function(event1) {
20198     var event0 = event; // Events can be reentrant (e.g., focus).
20199     event = event1;
20200     try {
20201       listener.call(this, this.__data__, index, group);
20202     } finally {
20203       event = event0;
20204     }
20205   };
20206 }
20207
20208 function parseTypenames$1(typenames) {
20209   return typenames.trim().split(/^|\s+/).map(function(t) {
20210     var name = "", i = t.indexOf(".");
20211     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20212     return {type: t, name: name};
20213   });
20214 }
20215
20216 function onRemove(typename) {
20217   return function() {
20218     var on = this.__on;
20219     if (!on) return;
20220     for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
20221       if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
20222         this.removeEventListener(o.type, o.listener, o.capture);
20223       } else {
20224         on[++i] = o;
20225       }
20226     }
20227     if (++i) on.length = i;
20228     else delete this.__on;
20229   };
20230 }
20231
20232 function onAdd(typename, value, capture) {
20233   var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
20234   return function(d, i, group) {
20235     var on = this.__on, o, listener = wrap(value, i, group);
20236     if (on) for (var j = 0, m = on.length; j < m; ++j) {
20237       if ((o = on[j]).type === typename.type && o.name === typename.name) {
20238         this.removeEventListener(o.type, o.listener, o.capture);
20239         this.addEventListener(o.type, o.listener = listener, o.capture = capture);
20240         o.value = value;
20241         return;
20242       }
20243     }
20244     this.addEventListener(typename.type, listener, capture);
20245     o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
20246     if (!on) this.__on = [o];
20247     else on.push(o);
20248   };
20249 }
20250
20251 var selection_on = function(typename, value, capture) {
20252   var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t;
20253
20254   if (arguments.length < 2) {
20255     var on = this.node().__on;
20256     if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
20257       for (i = 0, o = on[j]; i < n; ++i) {
20258         if ((t = typenames[i]).type === o.type && t.name === o.name) {
20259           return o.value;
20260         }
20261       }
20262     }
20263     return;
20264   }
20265
20266   on = value ? onAdd : onRemove;
20267   if (capture == null) capture = false;
20268   for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
20269   return this;
20270 };
20271
20272 function customEvent(event1, listener, that, args) {
20273   var event0 = event;
20274   event1.sourceEvent = event;
20275   event = event1;
20276   try {
20277     return listener.apply(that, args);
20278   } finally {
20279     event = event0;
20280   }
20281 }
20282
20283 var sourceEvent = function() {
20284   var current = event, source;
20285   while (source = current.sourceEvent) current = source;
20286   return current;
20287 };
20288
20289 var point = function(node, event) {
20290   var svg = node.ownerSVGElement || node;
20291
20292   if (svg.createSVGPoint) {
20293     var point = svg.createSVGPoint();
20294     point.x = event.clientX, point.y = event.clientY;
20295     point = point.matrixTransform(node.getScreenCTM().inverse());
20296     return [point.x, point.y];
20297   }
20298
20299   var rect = node.getBoundingClientRect();
20300   return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
20301 };
20302
20303 var mouse = function(node) {
20304   var event = sourceEvent();
20305   if (event.changedTouches) event = event.changedTouches[0];
20306   return point(node, event);
20307 };
20308
20309 function none() {}
20310
20311 var selector = function(selector) {
20312   return selector == null ? none : function() {
20313     return this.querySelector(selector);
20314   };
20315 };
20316
20317 var selection_select = function(select) {
20318   if (typeof select !== "function") select = selector(select);
20319
20320   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20321     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
20322       if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
20323         if ("__data__" in node) subnode.__data__ = node.__data__;
20324         subgroup[i] = subnode;
20325       }
20326     }
20327   }
20328
20329   return new Selection(subgroups, this._parents);
20330 };
20331
20332 function empty$1() {
20333   return [];
20334 }
20335
20336 var selectorAll = function(selector) {
20337   return selector == null ? empty$1 : function() {
20338     return this.querySelectorAll(selector);
20339   };
20340 };
20341
20342 var selection_selectAll = function(select) {
20343   if (typeof select !== "function") select = selectorAll(select);
20344
20345   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
20346     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
20347       if (node = group[i]) {
20348         subgroups.push(select.call(node, node.__data__, i, group));
20349         parents.push(node);
20350       }
20351     }
20352   }
20353
20354   return new Selection(subgroups, parents);
20355 };
20356
20357 var selection_filter = function(match) {
20358   if (typeof match !== "function") match = matcher$1(match);
20359
20360   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20361     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
20362       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
20363         subgroup.push(node);
20364       }
20365     }
20366   }
20367
20368   return new Selection(subgroups, this._parents);
20369 };
20370
20371 var sparse = function(update) {
20372   return new Array(update.length);
20373 };
20374
20375 var selection_enter = function() {
20376   return new Selection(this._enter || this._groups.map(sparse), this._parents);
20377 };
20378
20379 function EnterNode(parent, datum) {
20380   this.ownerDocument = parent.ownerDocument;
20381   this.namespaceURI = parent.namespaceURI;
20382   this._next = null;
20383   this._parent = parent;
20384   this.__data__ = datum;
20385 }
20386
20387 EnterNode.prototype = {
20388   constructor: EnterNode,
20389   appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
20390   insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
20391   querySelector: function(selector) { return this._parent.querySelector(selector); },
20392   querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
20393 };
20394
20395 var constant$1 = function(x) {
20396   return function() {
20397     return x;
20398   };
20399 };
20400
20401 var keyPrefix = "$"; // Protect against keys like “__proto__”.
20402
20403 function bindIndex(parent, group, enter, update, exit, data) {
20404   var i = 0,
20405       node,
20406       groupLength = group.length,
20407       dataLength = data.length;
20408
20409   // Put any non-null nodes that fit into update.
20410   // Put any null nodes into enter.
20411   // Put any remaining data into enter.
20412   for (; i < dataLength; ++i) {
20413     if (node = group[i]) {
20414       node.__data__ = data[i];
20415       update[i] = node;
20416     } else {
20417       enter[i] = new EnterNode(parent, data[i]);
20418     }
20419   }
20420
20421   // Put any non-null nodes that don’t fit into exit.
20422   for (; i < groupLength; ++i) {
20423     if (node = group[i]) {
20424       exit[i] = node;
20425     }
20426   }
20427 }
20428
20429 function bindKey(parent, group, enter, update, exit, data, key) {
20430   var i,
20431       node,
20432       nodeByKeyValue = {},
20433       groupLength = group.length,
20434       dataLength = data.length,
20435       keyValues = new Array(groupLength),
20436       keyValue;
20437
20438   // Compute the key for each node.
20439   // If multiple nodes have the same key, the duplicates are added to exit.
20440   for (i = 0; i < groupLength; ++i) {
20441     if (node = group[i]) {
20442       keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
20443       if (keyValue in nodeByKeyValue) {
20444         exit[i] = node;
20445       } else {
20446         nodeByKeyValue[keyValue] = node;
20447       }
20448     }
20449   }
20450
20451   // Compute the key for each datum.
20452   // If there a node associated with this key, join and add it to update.
20453   // If there is not (or the key is a duplicate), add it to enter.
20454   for (i = 0; i < dataLength; ++i) {
20455     keyValue = keyPrefix + key.call(parent, data[i], i, data);
20456     if (node = nodeByKeyValue[keyValue]) {
20457       update[i] = node;
20458       node.__data__ = data[i];
20459       nodeByKeyValue[keyValue] = null;
20460     } else {
20461       enter[i] = new EnterNode(parent, data[i]);
20462     }
20463   }
20464
20465   // Add any remaining nodes that were not bound to data to exit.
20466   for (i = 0; i < groupLength; ++i) {
20467     if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
20468       exit[i] = node;
20469     }
20470   }
20471 }
20472
20473 var selection_data = function(value, key) {
20474   if (!value) {
20475     data = new Array(this.size()), j = -1;
20476     this.each(function(d) { data[++j] = d; });
20477     return data;
20478   }
20479
20480   var bind = key ? bindKey : bindIndex,
20481       parents = this._parents,
20482       groups = this._groups;
20483
20484   if (typeof value !== "function") value = constant$1(value);
20485
20486   for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
20487     var parent = parents[j],
20488         group = groups[j],
20489         groupLength = group.length,
20490         data = value.call(parent, parent && parent.__data__, j, parents),
20491         dataLength = data.length,
20492         enterGroup = enter[j] = new Array(dataLength),
20493         updateGroup = update[j] = new Array(dataLength),
20494         exitGroup = exit[j] = new Array(groupLength);
20495
20496     bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
20497
20498     // Now connect the enter nodes to their following update node, such that
20499     // appendChild can insert the materialized enter node before this node,
20500     // rather than at the end of the parent node.
20501     for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
20502       if (previous = enterGroup[i0]) {
20503         if (i0 >= i1) i1 = i0 + 1;
20504         while (!(next = updateGroup[i1]) && ++i1 < dataLength);
20505         previous._next = next || null;
20506       }
20507     }
20508   }
20509
20510   update = new Selection(update, parents);
20511   update._enter = enter;
20512   update._exit = exit;
20513   return update;
20514 };
20515
20516 var selection_exit = function() {
20517   return new Selection(this._exit || this._groups.map(sparse), this._parents);
20518 };
20519
20520 var selection_merge = function(selection$$1) {
20521
20522   for (var groups0 = this._groups, groups1 = selection$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
20523     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
20524       if (node = group0[i] || group1[i]) {
20525         merge[i] = node;
20526       }
20527     }
20528   }
20529
20530   for (; j < m0; ++j) {
20531     merges[j] = groups0[j];
20532   }
20533
20534   return new Selection(merges, this._parents);
20535 };
20536
20537 var selection_order = function() {
20538
20539   for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
20540     for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
20541       if (node = group[i]) {
20542         if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
20543         next = node;
20544       }
20545     }
20546   }
20547
20548   return this;
20549 };
20550
20551 var selection_sort = function(compare) {
20552   if (!compare) compare = ascending$1;
20553
20554   function compareNode(a, b) {
20555     return a && b ? compare(a.__data__, b.__data__) : !a - !b;
20556   }
20557
20558   for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
20559     for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
20560       if (node = group[i]) {
20561         sortgroup[i] = node;
20562       }
20563     }
20564     sortgroup.sort(compareNode);
20565   }
20566
20567   return new Selection(sortgroups, this._parents).order();
20568 };
20569
20570 function ascending$1(a, b) {
20571   return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
20572 }
20573
20574 var selection_call = function() {
20575   var callback = arguments[0];
20576   arguments[0] = this;
20577   callback.apply(null, arguments);
20578   return this;
20579 };
20580
20581 var selection_nodes = function() {
20582   var nodes = new Array(this.size()), i = -1;
20583   this.each(function() { nodes[++i] = this; });
20584   return nodes;
20585 };
20586
20587 var selection_node = function() {
20588
20589   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20590     for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
20591       var node = group[i];
20592       if (node) return node;
20593     }
20594   }
20595
20596   return null;
20597 };
20598
20599 var selection_size = function() {
20600   var size = 0;
20601   this.each(function() { ++size; });
20602   return size;
20603 };
20604
20605 var selection_empty = function() {
20606   return !this.node();
20607 };
20608
20609 var selection_each = function(callback) {
20610
20611   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20612     for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
20613       if (node = group[i]) callback.call(node, node.__data__, i, group);
20614     }
20615   }
20616
20617   return this;
20618 };
20619
20620 function attrRemove(name) {
20621   return function() {
20622     this.removeAttribute(name);
20623   };
20624 }
20625
20626 function attrRemoveNS(fullname) {
20627   return function() {
20628     this.removeAttributeNS(fullname.space, fullname.local);
20629   };
20630 }
20631
20632 function attrConstant(name, value) {
20633   return function() {
20634     this.setAttribute(name, value);
20635   };
20636 }
20637
20638 function attrConstantNS(fullname, value) {
20639   return function() {
20640     this.setAttributeNS(fullname.space, fullname.local, value);
20641   };
20642 }
20643
20644 function attrFunction(name, value) {
20645   return function() {
20646     var v = value.apply(this, arguments);
20647     if (v == null) this.removeAttribute(name);
20648     else this.setAttribute(name, v);
20649   };
20650 }
20651
20652 function attrFunctionNS(fullname, value) {
20653   return function() {
20654     var v = value.apply(this, arguments);
20655     if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
20656     else this.setAttributeNS(fullname.space, fullname.local, v);
20657   };
20658 }
20659
20660 var selection_attr = function(name, value) {
20661   var fullname = namespace(name);
20662
20663   if (arguments.length < 2) {
20664     var node = this.node();
20665     return fullname.local
20666         ? node.getAttributeNS(fullname.space, fullname.local)
20667         : node.getAttribute(fullname);
20668   }
20669
20670   return this.each((value == null
20671       ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
20672       ? (fullname.local ? attrFunctionNS : attrFunction)
20673       : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
20674 };
20675
20676 var defaultView = function(node) {
20677   return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
20678       || (node.document && node) // node is a Window
20679       || node.defaultView; // node is a Document
20680 };
20681
20682 function styleRemove(name) {
20683   return function() {
20684     this.style.removeProperty(name);
20685   };
20686 }
20687
20688 function styleConstant(name, value, priority) {
20689   return function() {
20690     this.style.setProperty(name, value, priority);
20691   };
20692 }
20693
20694 function styleFunction(name, value, priority) {
20695   return function() {
20696     var v = value.apply(this, arguments);
20697     if (v == null) this.style.removeProperty(name);
20698     else this.style.setProperty(name, v, priority);
20699   };
20700 }
20701
20702 var selection_style = function(name, value, priority) {
20703   return arguments.length > 1
20704       ? this.each((value == null
20705             ? styleRemove : typeof value === "function"
20706             ? styleFunction
20707             : styleConstant)(name, value, priority == null ? "" : priority))
20708       : styleValue(this.node(), name);
20709 };
20710
20711 function styleValue(node, name) {
20712   return node.style.getPropertyValue(name)
20713       || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
20714 }
20715
20716 function propertyRemove(name) {
20717   return function() {
20718     delete this[name];
20719   };
20720 }
20721
20722 function propertyConstant(name, value) {
20723   return function() {
20724     this[name] = value;
20725   };
20726 }
20727
20728 function propertyFunction(name, value) {
20729   return function() {
20730     var v = value.apply(this, arguments);
20731     if (v == null) delete this[name];
20732     else this[name] = v;
20733   };
20734 }
20735
20736 var selection_property = function(name, value) {
20737   return arguments.length > 1
20738       ? this.each((value == null
20739           ? propertyRemove : typeof value === "function"
20740           ? propertyFunction
20741           : propertyConstant)(name, value))
20742       : this.node()[name];
20743 };
20744
20745 function classArray(string) {
20746   return string.trim().split(/^|\s+/);
20747 }
20748
20749 function classList(node) {
20750   return node.classList || new ClassList(node);
20751 }
20752
20753 function ClassList(node) {
20754   this._node = node;
20755   this._names = classArray(node.getAttribute("class") || "");
20756 }
20757
20758 ClassList.prototype = {
20759   add: function(name) {
20760     var i = this._names.indexOf(name);
20761     if (i < 0) {
20762       this._names.push(name);
20763       this._node.setAttribute("class", this._names.join(" "));
20764     }
20765   },
20766   remove: function(name) {
20767     var i = this._names.indexOf(name);
20768     if (i >= 0) {
20769       this._names.splice(i, 1);
20770       this._node.setAttribute("class", this._names.join(" "));
20771     }
20772   },
20773   contains: function(name) {
20774     return this._names.indexOf(name) >= 0;
20775   }
20776 };
20777
20778 function classedAdd(node, names) {
20779   var list = classList(node), i = -1, n = names.length;
20780   while (++i < n) list.add(names[i]);
20781 }
20782
20783 function classedRemove(node, names) {
20784   var list = classList(node), i = -1, n = names.length;
20785   while (++i < n) list.remove(names[i]);
20786 }
20787
20788 function classedTrue(names) {
20789   return function() {
20790     classedAdd(this, names);
20791   };
20792 }
20793
20794 function classedFalse(names) {
20795   return function() {
20796     classedRemove(this, names);
20797   };
20798 }
20799
20800 function classedFunction(names, value) {
20801   return function() {
20802     (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
20803   };
20804 }
20805
20806 var selection_classed = function(name, value) {
20807   var names = classArray(name + "");
20808
20809   if (arguments.length < 2) {
20810     var list = classList(this.node()), i = -1, n = names.length;
20811     while (++i < n) if (!list.contains(names[i])) return false;
20812     return true;
20813   }
20814
20815   return this.each((typeof value === "function"
20816       ? classedFunction : value
20817       ? classedTrue
20818       : classedFalse)(names, value));
20819 };
20820
20821 function textRemove() {
20822   this.textContent = "";
20823 }
20824
20825 function textConstant(value) {
20826   return function() {
20827     this.textContent = value;
20828   };
20829 }
20830
20831 function textFunction(value) {
20832   return function() {
20833     var v = value.apply(this, arguments);
20834     this.textContent = v == null ? "" : v;
20835   };
20836 }
20837
20838 var selection_text = function(value) {
20839   return arguments.length
20840       ? this.each(value == null
20841           ? textRemove : (typeof value === "function"
20842           ? textFunction
20843           : textConstant)(value))
20844       : this.node().textContent;
20845 };
20846
20847 function htmlRemove() {
20848   this.innerHTML = "";
20849 }
20850
20851 function htmlConstant(value) {
20852   return function() {
20853     this.innerHTML = value;
20854   };
20855 }
20856
20857 function htmlFunction(value) {
20858   return function() {
20859     var v = value.apply(this, arguments);
20860     this.innerHTML = v == null ? "" : v;
20861   };
20862 }
20863
20864 var selection_html = function(value) {
20865   return arguments.length
20866       ? this.each(value == null
20867           ? htmlRemove : (typeof value === "function"
20868           ? htmlFunction
20869           : htmlConstant)(value))
20870       : this.node().innerHTML;
20871 };
20872
20873 function raise() {
20874   if (this.nextSibling) this.parentNode.appendChild(this);
20875 }
20876
20877 var selection_raise = function() {
20878   return this.each(raise);
20879 };
20880
20881 function lower() {
20882   if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
20883 }
20884
20885 var selection_lower = function() {
20886   return this.each(lower);
20887 };
20888
20889 var selection_append = function(name) {
20890   var create = typeof name === "function" ? name : creator(name);
20891   return this.select(function() {
20892     return this.appendChild(create.apply(this, arguments));
20893   });
20894 };
20895
20896 function constantNull() {
20897   return null;
20898 }
20899
20900 var selection_insert = function(name, before) {
20901   var create = typeof name === "function" ? name : creator(name),
20902       select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
20903   return this.select(function() {
20904     return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
20905   });
20906 };
20907
20908 function remove() {
20909   var parent = this.parentNode;
20910   if (parent) parent.removeChild(this);
20911 }
20912
20913 var selection_remove = function() {
20914   return this.each(remove);
20915 };
20916
20917 var selection_datum = function(value) {
20918   return arguments.length
20919       ? this.property("__data__", value)
20920       : this.node().__data__;
20921 };
20922
20923 function dispatchEvent(node, type, params) {
20924   var window = defaultView(node),
20925       event = window.CustomEvent;
20926
20927   if (typeof event === "function") {
20928     event = new event(type, params);
20929   } else {
20930     event = window.document.createEvent("Event");
20931     if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
20932     else event.initEvent(type, false, false);
20933   }
20934
20935   node.dispatchEvent(event);
20936 }
20937
20938 function dispatchConstant(type, params) {
20939   return function() {
20940     return dispatchEvent(this, type, params);
20941   };
20942 }
20943
20944 function dispatchFunction(type, params) {
20945   return function() {
20946     return dispatchEvent(this, type, params.apply(this, arguments));
20947   };
20948 }
20949
20950 var selection_dispatch = function(type, params) {
20951   return this.each((typeof params === "function"
20952       ? dispatchFunction
20953       : dispatchConstant)(type, params));
20954 };
20955
20956 var root = [null];
20957
20958 function Selection(groups, parents) {
20959   this._groups = groups;
20960   this._parents = parents;
20961 }
20962
20963 function selection() {
20964   return new Selection([[document.documentElement]], root);
20965 }
20966
20967 Selection.prototype = selection.prototype = {
20968   constructor: Selection,
20969   select: selection_select,
20970   selectAll: selection_selectAll,
20971   filter: selection_filter,
20972   data: selection_data,
20973   enter: selection_enter,
20974   exit: selection_exit,
20975   merge: selection_merge,
20976   order: selection_order,
20977   sort: selection_sort,
20978   call: selection_call,
20979   nodes: selection_nodes,
20980   node: selection_node,
20981   size: selection_size,
20982   empty: selection_empty,
20983   each: selection_each,
20984   attr: selection_attr,
20985   style: selection_style,
20986   property: selection_property,
20987   classed: selection_classed,
20988   text: selection_text,
20989   html: selection_html,
20990   raise: selection_raise,
20991   lower: selection_lower,
20992   append: selection_append,
20993   insert: selection_insert,
20994   remove: selection_remove,
20995   datum: selection_datum,
20996   on: selection_on,
20997   dispatch: selection_dispatch
20998 };
20999
21000 var select = function(selector) {
21001   return typeof selector === "string"
21002       ? new Selection([[document.querySelector(selector)]], [document.documentElement])
21003       : new Selection([[selector]], root);
21004 };
21005
21006 var selectAll = function(selector) {
21007   return typeof selector === "string"
21008       ? new Selection([document.querySelectorAll(selector)], [document.documentElement])
21009       : new Selection([selector == null ? [] : selector], root);
21010 };
21011
21012 var touch = function(node, touches, identifier) {
21013   if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches;
21014
21015   for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) {
21016     if ((touch = touches[i]).identifier === identifier) {
21017       return point(node, touch);
21018     }
21019   }
21020
21021   return null;
21022 };
21023
21024 var touches = function(node, touches) {
21025   if (touches == null) touches = sourceEvent().touches;
21026
21027   for (var i = 0, n = touches ? touches.length : 0, points = new Array(n); i < n; ++i) {
21028     points[i] = point(node, touches[i]);
21029   }
21030
21031   return points;
21032 };
21033
21034 function nopropagation() {
21035   event.stopImmediatePropagation();
21036 }
21037
21038 var noevent = function() {
21039   event.preventDefault();
21040   event.stopImmediatePropagation();
21041 };
21042
21043 var dragDisable = function(view) {
21044   var root = view.document.documentElement,
21045       selection$$1 = select(view).on("dragstart.drag", noevent, true);
21046   if ("onselectstart" in root) {
21047     selection$$1.on("selectstart.drag", noevent, true);
21048   } else {
21049     root.__noselect = root.style.MozUserSelect;
21050     root.style.MozUserSelect = "none";
21051   }
21052 };
21053
21054 function yesdrag(view, noclick) {
21055   var root = view.document.documentElement,
21056       selection$$1 = select(view).on("dragstart.drag", null);
21057   if (noclick) {
21058     selection$$1.on("click.drag", noevent, true);
21059     setTimeout(function() { selection$$1.on("click.drag", null); }, 0);
21060   }
21061   if ("onselectstart" in root) {
21062     selection$$1.on("selectstart.drag", null);
21063   } else {
21064     root.style.MozUserSelect = root.__noselect;
21065     delete root.__noselect;
21066   }
21067 }
21068
21069 var constant$2 = function(x) {
21070   return function() {
21071     return x;
21072   };
21073 };
21074
21075 function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) {
21076   this.target = target;
21077   this.type = type;
21078   this.subject = subject;
21079   this.identifier = id;
21080   this.active = active;
21081   this.x = x;
21082   this.y = y;
21083   this.dx = dx;
21084   this.dy = dy;
21085   this._ = dispatch;
21086 }
21087
21088 DragEvent.prototype.on = function() {
21089   var value = this._.on.apply(this._, arguments);
21090   return value === this._ ? this : value;
21091 };
21092
21093 // Ignore right-click, since that should open the context menu.
21094 function defaultFilter$1() {
21095   return !event.button;
21096 }
21097
21098 function defaultContainer() {
21099   return this.parentNode;
21100 }
21101
21102 function defaultSubject(d) {
21103   return d == null ? {x: event.x, y: event.y} : d;
21104 }
21105
21106 function touchable() {
21107   return "ontouchstart" in this;
21108 }
21109
21110 var drag = function() {
21111   var filter = defaultFilter$1,
21112       container = defaultContainer,
21113       subject = defaultSubject,
21114       gestures = {},
21115       listeners = dispatch("start", "drag", "end"),
21116       active = 0,
21117       mousedownx,
21118       mousedowny,
21119       mousemoving,
21120       touchending,
21121       clickDistance2 = 0;
21122
21123   function drag(selection) {
21124     selection
21125         .on("mousedown.drag", mousedowned)
21126       .filter(touchable)
21127         .on("touchstart.drag", touchstarted)
21128         .on("touchmove.drag", touchmoved)
21129         .on("touchend.drag touchcancel.drag", touchended)
21130         .style("touch-action", "none")
21131         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
21132   }
21133
21134   function mousedowned() {
21135     if (touchending || !filter.apply(this, arguments)) return;
21136     var gesture = beforestart("mouse", container.apply(this, arguments), mouse, this, arguments);
21137     if (!gesture) return;
21138     select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
21139     dragDisable(event.view);
21140     nopropagation();
21141     mousemoving = false;
21142     mousedownx = event.clientX;
21143     mousedowny = event.clientY;
21144     gesture("start");
21145   }
21146
21147   function mousemoved() {
21148     noevent();
21149     if (!mousemoving) {
21150       var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;
21151       mousemoving = dx * dx + dy * dy > clickDistance2;
21152     }
21153     gestures.mouse("drag");
21154   }
21155
21156   function mouseupped() {
21157     select(event.view).on("mousemove.drag mouseup.drag", null);
21158     yesdrag(event.view, mousemoving);
21159     noevent();
21160     gestures.mouse("end");
21161   }
21162
21163   function touchstarted() {
21164     if (!filter.apply(this, arguments)) return;
21165     var touches$$1 = event.changedTouches,
21166         c = container.apply(this, arguments),
21167         n = touches$$1.length, i, gesture;
21168
21169     for (i = 0; i < n; ++i) {
21170       if (gesture = beforestart(touches$$1[i].identifier, c, touch, this, arguments)) {
21171         nopropagation();
21172         gesture("start");
21173       }
21174     }
21175   }
21176
21177   function touchmoved() {
21178     var touches$$1 = event.changedTouches,
21179         n = touches$$1.length, i, gesture;
21180
21181     for (i = 0; i < n; ++i) {
21182       if (gesture = gestures[touches$$1[i].identifier]) {
21183         noevent();
21184         gesture("drag");
21185       }
21186     }
21187   }
21188
21189   function touchended() {
21190     var touches$$1 = event.changedTouches,
21191         n = touches$$1.length, i, gesture;
21192
21193     if (touchending) clearTimeout(touchending);
21194     touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
21195     for (i = 0; i < n; ++i) {
21196       if (gesture = gestures[touches$$1[i].identifier]) {
21197         nopropagation();
21198         gesture("end");
21199       }
21200     }
21201   }
21202
21203   function beforestart(id, container, point, that, args) {
21204     var p = point(container, id), s, dx, dy,
21205         sublisteners = listeners.copy();
21206
21207     if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() {
21208       if ((event.subject = s = subject.apply(that, args)) == null) return false;
21209       dx = s.x - p[0] || 0;
21210       dy = s.y - p[1] || 0;
21211       return true;
21212     })) return;
21213
21214     return function gesture(type) {
21215       var p0 = p, n;
21216       switch (type) {
21217         case "start": gestures[id] = gesture, n = active++; break;
21218         case "end": delete gestures[id], --active; // nobreak
21219         case "drag": p = point(container, id), n = active; break;
21220       }
21221       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]);
21222     };
21223   }
21224
21225   drag.filter = function(_) {
21226     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter;
21227   };
21228
21229   drag.container = function(_) {
21230     return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container;
21231   };
21232
21233   drag.subject = function(_) {
21234     return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject;
21235   };
21236
21237   drag.on = function() {
21238     var value = listeners.on.apply(listeners, arguments);
21239     return value === listeners ? drag : value;
21240   };
21241
21242   drag.clickDistance = function(_) {
21243     return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
21244   };
21245
21246   return drag;
21247 };
21248
21249 var define = function(constructor, factory, prototype) {
21250   constructor.prototype = factory.prototype = prototype;
21251   prototype.constructor = constructor;
21252 };
21253
21254 function extend(parent, definition) {
21255   var prototype = Object.create(parent.prototype);
21256   for (var key in definition) prototype[key] = definition[key];
21257   return prototype;
21258 }
21259
21260 function Color() {}
21261
21262 var darker = 0.7;
21263 var brighter = 1 / darker;
21264
21265 var reI = "\\s*([+-]?\\d+)\\s*";
21266 var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*";
21267 var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
21268 var reHex3 = /^#([0-9a-f]{3})$/;
21269 var reHex6 = /^#([0-9a-f]{6})$/;
21270 var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$");
21271 var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$");
21272 var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$");
21273 var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$");
21274 var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$");
21275 var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
21276
21277 var named = {
21278   aliceblue: 0xf0f8ff,
21279   antiquewhite: 0xfaebd7,
21280   aqua: 0x00ffff,
21281   aquamarine: 0x7fffd4,
21282   azure: 0xf0ffff,
21283   beige: 0xf5f5dc,
21284   bisque: 0xffe4c4,
21285   black: 0x000000,
21286   blanchedalmond: 0xffebcd,
21287   blue: 0x0000ff,
21288   blueviolet: 0x8a2be2,
21289   brown: 0xa52a2a,
21290   burlywood: 0xdeb887,
21291   cadetblue: 0x5f9ea0,
21292   chartreuse: 0x7fff00,
21293   chocolate: 0xd2691e,
21294   coral: 0xff7f50,
21295   cornflowerblue: 0x6495ed,
21296   cornsilk: 0xfff8dc,
21297   crimson: 0xdc143c,
21298   cyan: 0x00ffff,
21299   darkblue: 0x00008b,
21300   darkcyan: 0x008b8b,
21301   darkgoldenrod: 0xb8860b,
21302   darkgray: 0xa9a9a9,
21303   darkgreen: 0x006400,
21304   darkgrey: 0xa9a9a9,
21305   darkkhaki: 0xbdb76b,
21306   darkmagenta: 0x8b008b,
21307   darkolivegreen: 0x556b2f,
21308   darkorange: 0xff8c00,
21309   darkorchid: 0x9932cc,
21310   darkred: 0x8b0000,
21311   darksalmon: 0xe9967a,
21312   darkseagreen: 0x8fbc8f,
21313   darkslateblue: 0x483d8b,
21314   darkslategray: 0x2f4f4f,
21315   darkslategrey: 0x2f4f4f,
21316   darkturquoise: 0x00ced1,
21317   darkviolet: 0x9400d3,
21318   deeppink: 0xff1493,
21319   deepskyblue: 0x00bfff,
21320   dimgray: 0x696969,
21321   dimgrey: 0x696969,
21322   dodgerblue: 0x1e90ff,
21323   firebrick: 0xb22222,
21324   floralwhite: 0xfffaf0,
21325   forestgreen: 0x228b22,
21326   fuchsia: 0xff00ff,
21327   gainsboro: 0xdcdcdc,
21328   ghostwhite: 0xf8f8ff,
21329   gold: 0xffd700,
21330   goldenrod: 0xdaa520,
21331   gray: 0x808080,
21332   green: 0x008000,
21333   greenyellow: 0xadff2f,
21334   grey: 0x808080,
21335   honeydew: 0xf0fff0,
21336   hotpink: 0xff69b4,
21337   indianred: 0xcd5c5c,
21338   indigo: 0x4b0082,
21339   ivory: 0xfffff0,
21340   khaki: 0xf0e68c,
21341   lavender: 0xe6e6fa,
21342   lavenderblush: 0xfff0f5,
21343   lawngreen: 0x7cfc00,
21344   lemonchiffon: 0xfffacd,
21345   lightblue: 0xadd8e6,
21346   lightcoral: 0xf08080,
21347   lightcyan: 0xe0ffff,
21348   lightgoldenrodyellow: 0xfafad2,
21349   lightgray: 0xd3d3d3,
21350   lightgreen: 0x90ee90,
21351   lightgrey: 0xd3d3d3,
21352   lightpink: 0xffb6c1,
21353   lightsalmon: 0xffa07a,
21354   lightseagreen: 0x20b2aa,
21355   lightskyblue: 0x87cefa,
21356   lightslategray: 0x778899,
21357   lightslategrey: 0x778899,
21358   lightsteelblue: 0xb0c4de,
21359   lightyellow: 0xffffe0,
21360   lime: 0x00ff00,
21361   limegreen: 0x32cd32,
21362   linen: 0xfaf0e6,
21363   magenta: 0xff00ff,
21364   maroon: 0x800000,
21365   mediumaquamarine: 0x66cdaa,
21366   mediumblue: 0x0000cd,
21367   mediumorchid: 0xba55d3,
21368   mediumpurple: 0x9370db,
21369   mediumseagreen: 0x3cb371,
21370   mediumslateblue: 0x7b68ee,
21371   mediumspringgreen: 0x00fa9a,
21372   mediumturquoise: 0x48d1cc,
21373   mediumvioletred: 0xc71585,
21374   midnightblue: 0x191970,
21375   mintcream: 0xf5fffa,
21376   mistyrose: 0xffe4e1,
21377   moccasin: 0xffe4b5,
21378   navajowhite: 0xffdead,
21379   navy: 0x000080,
21380   oldlace: 0xfdf5e6,
21381   olive: 0x808000,
21382   olivedrab: 0x6b8e23,
21383   orange: 0xffa500,
21384   orangered: 0xff4500,
21385   orchid: 0xda70d6,
21386   palegoldenrod: 0xeee8aa,
21387   palegreen: 0x98fb98,
21388   paleturquoise: 0xafeeee,
21389   palevioletred: 0xdb7093,
21390   papayawhip: 0xffefd5,
21391   peachpuff: 0xffdab9,
21392   peru: 0xcd853f,
21393   pink: 0xffc0cb,
21394   plum: 0xdda0dd,
21395   powderblue: 0xb0e0e6,
21396   purple: 0x800080,
21397   rebeccapurple: 0x663399,
21398   red: 0xff0000,
21399   rosybrown: 0xbc8f8f,
21400   royalblue: 0x4169e1,
21401   saddlebrown: 0x8b4513,
21402   salmon: 0xfa8072,
21403   sandybrown: 0xf4a460,
21404   seagreen: 0x2e8b57,
21405   seashell: 0xfff5ee,
21406   sienna: 0xa0522d,
21407   silver: 0xc0c0c0,
21408   skyblue: 0x87ceeb,
21409   slateblue: 0x6a5acd,
21410   slategray: 0x708090,
21411   slategrey: 0x708090,
21412   snow: 0xfffafa,
21413   springgreen: 0x00ff7f,
21414   steelblue: 0x4682b4,
21415   tan: 0xd2b48c,
21416   teal: 0x008080,
21417   thistle: 0xd8bfd8,
21418   tomato: 0xff6347,
21419   turquoise: 0x40e0d0,
21420   violet: 0xee82ee,
21421   wheat: 0xf5deb3,
21422   white: 0xffffff,
21423   whitesmoke: 0xf5f5f5,
21424   yellow: 0xffff00,
21425   yellowgreen: 0x9acd32
21426 };
21427
21428 define(Color, color, {
21429   displayable: function() {
21430     return this.rgb().displayable();
21431   },
21432   toString: function() {
21433     return this.rgb() + "";
21434   }
21435 });
21436
21437 function color(format) {
21438   var m;
21439   format = (format + "").trim().toLowerCase();
21440   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
21441       : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
21442       : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
21443       : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
21444       : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
21445       : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
21446       : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
21447       : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
21448       : named.hasOwnProperty(format) ? rgbn(named[format])
21449       : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
21450       : null;
21451 }
21452
21453 function rgbn(n) {
21454   return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
21455 }
21456
21457 function rgba(r, g, b, a) {
21458   if (a <= 0) r = g = b = NaN;
21459   return new Rgb(r, g, b, a);
21460 }
21461
21462 function rgbConvert(o) {
21463   if (!(o instanceof Color)) o = color(o);
21464   if (!o) return new Rgb;
21465   o = o.rgb();
21466   return new Rgb(o.r, o.g, o.b, o.opacity);
21467 }
21468
21469 function rgb(r, g, b, opacity) {
21470   return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
21471 }
21472
21473 function Rgb(r, g, b, opacity) {
21474   this.r = +r;
21475   this.g = +g;
21476   this.b = +b;
21477   this.opacity = +opacity;
21478 }
21479
21480 define(Rgb, rgb, extend(Color, {
21481   brighter: function(k) {
21482     k = k == null ? brighter : Math.pow(brighter, k);
21483     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21484   },
21485   darker: function(k) {
21486     k = k == null ? darker : Math.pow(darker, k);
21487     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21488   },
21489   rgb: function() {
21490     return this;
21491   },
21492   displayable: function() {
21493     return (0 <= this.r && this.r <= 255)
21494         && (0 <= this.g && this.g <= 255)
21495         && (0 <= this.b && this.b <= 255)
21496         && (0 <= this.opacity && this.opacity <= 1);
21497   },
21498   toString: function() {
21499     var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
21500     return (a === 1 ? "rgb(" : "rgba(")
21501         + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
21502         + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
21503         + Math.max(0, Math.min(255, Math.round(this.b) || 0))
21504         + (a === 1 ? ")" : ", " + a + ")");
21505   }
21506 }));
21507
21508 function hsla(h, s, l, a) {
21509   if (a <= 0) h = s = l = NaN;
21510   else if (l <= 0 || l >= 1) h = s = NaN;
21511   else if (s <= 0) h = NaN;
21512   return new Hsl(h, s, l, a);
21513 }
21514
21515 function hslConvert(o) {
21516   if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
21517   if (!(o instanceof Color)) o = color(o);
21518   if (!o) return new Hsl;
21519   if (o instanceof Hsl) return o;
21520   o = o.rgb();
21521   var r = o.r / 255,
21522       g = o.g / 255,
21523       b = o.b / 255,
21524       min = Math.min(r, g, b),
21525       max = Math.max(r, g, b),
21526       h = NaN,
21527       s = max - min,
21528       l = (max + min) / 2;
21529   if (s) {
21530     if (r === max) h = (g - b) / s + (g < b) * 6;
21531     else if (g === max) h = (b - r) / s + 2;
21532     else h = (r - g) / s + 4;
21533     s /= l < 0.5 ? max + min : 2 - max - min;
21534     h *= 60;
21535   } else {
21536     s = l > 0 && l < 1 ? 0 : h;
21537   }
21538   return new Hsl(h, s, l, o.opacity);
21539 }
21540
21541 function hsl(h, s, l, opacity) {
21542   return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
21543 }
21544
21545 function Hsl(h, s, l, opacity) {
21546   this.h = +h;
21547   this.s = +s;
21548   this.l = +l;
21549   this.opacity = +opacity;
21550 }
21551
21552 define(Hsl, hsl, extend(Color, {
21553   brighter: function(k) {
21554     k = k == null ? brighter : Math.pow(brighter, k);
21555     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21556   },
21557   darker: function(k) {
21558     k = k == null ? darker : Math.pow(darker, k);
21559     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21560   },
21561   rgb: function() {
21562     var h = this.h % 360 + (this.h < 0) * 360,
21563         s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
21564         l = this.l,
21565         m2 = l + (l < 0.5 ? l : 1 - l) * s,
21566         m1 = 2 * l - m2;
21567     return new Rgb(
21568       hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
21569       hsl2rgb(h, m1, m2),
21570       hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
21571       this.opacity
21572     );
21573   },
21574   displayable: function() {
21575     return (0 <= this.s && this.s <= 1 || isNaN(this.s))
21576         && (0 <= this.l && this.l <= 1)
21577         && (0 <= this.opacity && this.opacity <= 1);
21578   }
21579 }));
21580
21581 /* From FvD 13.37, CSS Color Module Level 3 */
21582 function hsl2rgb(h, m1, m2) {
21583   return (h < 60 ? m1 + (m2 - m1) * h / 60
21584       : h < 180 ? m2
21585       : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
21586       : m1) * 255;
21587 }
21588
21589 var deg2rad = Math.PI / 180;
21590 var rad2deg = 180 / Math.PI;
21591
21592 var Kn = 18;
21593 var Xn = 0.950470;
21594 var Yn = 1;
21595 var Zn = 1.088830;
21596 var t0 = 4 / 29;
21597 var t1 = 6 / 29;
21598 var t2 = 3 * t1 * t1;
21599 var t3 = t1 * t1 * t1;
21600
21601 function labConvert(o) {
21602   if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
21603   if (o instanceof Hcl) {
21604     var h = o.h * deg2rad;
21605     return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
21606   }
21607   if (!(o instanceof Rgb)) o = rgbConvert(o);
21608   var b = rgb2xyz(o.r),
21609       a = rgb2xyz(o.g),
21610       l = rgb2xyz(o.b),
21611       x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
21612       y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
21613       z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
21614   return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
21615 }
21616
21617 function lab(l, a, b, opacity) {
21618   return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
21619 }
21620
21621 function Lab(l, a, b, opacity) {
21622   this.l = +l;
21623   this.a = +a;
21624   this.b = +b;
21625   this.opacity = +opacity;
21626 }
21627
21628 define(Lab, lab, extend(Color, {
21629   brighter: function(k) {
21630     return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21631   },
21632   darker: function(k) {
21633     return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21634   },
21635   rgb: function() {
21636     var y = (this.l + 16) / 116,
21637         x = isNaN(this.a) ? y : y + this.a / 500,
21638         z = isNaN(this.b) ? y : y - this.b / 200;
21639     y = Yn * lab2xyz(y);
21640     x = Xn * lab2xyz(x);
21641     z = Zn * lab2xyz(z);
21642     return new Rgb(
21643       xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
21644       xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
21645       xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
21646       this.opacity
21647     );
21648   }
21649 }));
21650
21651 function xyz2lab(t) {
21652   return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
21653 }
21654
21655 function lab2xyz(t) {
21656   return t > t1 ? t * t * t : t2 * (t - t0);
21657 }
21658
21659 function xyz2rgb(x) {
21660   return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
21661 }
21662
21663 function rgb2xyz(x) {
21664   return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
21665 }
21666
21667 function hclConvert(o) {
21668   if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
21669   if (!(o instanceof Lab)) o = labConvert(o);
21670   var h = Math.atan2(o.b, o.a) * rad2deg;
21671   return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
21672 }
21673
21674 function hcl(h, c, l, opacity) {
21675   return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
21676 }
21677
21678 function Hcl(h, c, l, opacity) {
21679   this.h = +h;
21680   this.c = +c;
21681   this.l = +l;
21682   this.opacity = +opacity;
21683 }
21684
21685 define(Hcl, hcl, extend(Color, {
21686   brighter: function(k) {
21687     return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
21688   },
21689   darker: function(k) {
21690     return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
21691   },
21692   rgb: function() {
21693     return labConvert(this).rgb();
21694   }
21695 }));
21696
21697 var A = -0.14861;
21698 var B = +1.78277;
21699 var C = -0.29227;
21700 var D = -0.90649;
21701 var E = +1.97294;
21702 var ED = E * D;
21703 var EB = E * B;
21704 var BC_DA = B * C - D * A;
21705
21706 function cubehelixConvert(o) {
21707   if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
21708   if (!(o instanceof Rgb)) o = rgbConvert(o);
21709   var r = o.r / 255,
21710       g = o.g / 255,
21711       b = o.b / 255,
21712       l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
21713       bl = b - l,
21714       k = (E * (g - l) - C * bl) / D,
21715       s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
21716       h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
21717   return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
21718 }
21719
21720 function cubehelix(h, s, l, opacity) {
21721   return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
21722 }
21723
21724 function Cubehelix(h, s, l, opacity) {
21725   this.h = +h;
21726   this.s = +s;
21727   this.l = +l;
21728   this.opacity = +opacity;
21729 }
21730
21731 define(Cubehelix, cubehelix, extend(Color, {
21732   brighter: function(k) {
21733     k = k == null ? brighter : Math.pow(brighter, k);
21734     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21735   },
21736   darker: function(k) {
21737     k = k == null ? darker : Math.pow(darker, k);
21738     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21739   },
21740   rgb: function() {
21741     var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
21742         l = +this.l,
21743         a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
21744         cosh = Math.cos(h),
21745         sinh = Math.sin(h);
21746     return new Rgb(
21747       255 * (l + a * (A * cosh + B * sinh)),
21748       255 * (l + a * (C * cosh + D * sinh)),
21749       255 * (l + a * (E * cosh)),
21750       this.opacity
21751     );
21752   }
21753 }));
21754
21755 function basis(t1, v0, v1, v2, v3) {
21756   var t2 = t1 * t1, t3 = t2 * t1;
21757   return ((1 - 3 * t1 + 3 * t2 - t3) * v0
21758       + (4 - 6 * t2 + 3 * t3) * v1
21759       + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
21760       + t3 * v3) / 6;
21761 }
21762
21763 var basis$1 = function(values) {
21764   var n = values.length - 1;
21765   return function(t) {
21766     var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
21767         v1 = values[i],
21768         v2 = values[i + 1],
21769         v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
21770         v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
21771     return basis((t - i / n) * n, v0, v1, v2, v3);
21772   };
21773 };
21774
21775 var basisClosed = function(values) {
21776   var n = values.length;
21777   return function(t) {
21778     var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
21779         v0 = values[(i + n - 1) % n],
21780         v1 = values[i % n],
21781         v2 = values[(i + 1) % n],
21782         v3 = values[(i + 2) % n];
21783     return basis((t - i / n) * n, v0, v1, v2, v3);
21784   };
21785 };
21786
21787 var constant$3 = function(x) {
21788   return function() {
21789     return x;
21790   };
21791 };
21792
21793 function linear(a, d) {
21794   return function(t) {
21795     return a + t * d;
21796   };
21797 }
21798
21799 function exponential(a, b, y) {
21800   return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
21801     return Math.pow(a + t * b, y);
21802   };
21803 }
21804
21805 function hue(a, b) {
21806   var d = b - a;
21807   return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$3(isNaN(a) ? b : a);
21808 }
21809
21810 function gamma(y) {
21811   return (y = +y) === 1 ? nogamma : function(a, b) {
21812     return b - a ? exponential(a, b, y) : constant$3(isNaN(a) ? b : a);
21813   };
21814 }
21815
21816 function nogamma(a, b) {
21817   var d = b - a;
21818   return d ? linear(a, d) : constant$3(isNaN(a) ? b : a);
21819 }
21820
21821 var interpolateRgb = (function rgbGamma(y) {
21822   var color$$1 = gamma(y);
21823
21824   function rgb$$1(start, end) {
21825     var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r),
21826         g = color$$1(start.g, end.g),
21827         b = color$$1(start.b, end.b),
21828         opacity = nogamma(start.opacity, end.opacity);
21829     return function(t) {
21830       start.r = r(t);
21831       start.g = g(t);
21832       start.b = b(t);
21833       start.opacity = opacity(t);
21834       return start + "";
21835     };
21836   }
21837
21838   rgb$$1.gamma = rgbGamma;
21839
21840   return rgb$$1;
21841 })(1);
21842
21843 function rgbSpline(spline) {
21844   return function(colors) {
21845     var n = colors.length,
21846         r = new Array(n),
21847         g = new Array(n),
21848         b = new Array(n),
21849         i, color$$1;
21850     for (i = 0; i < n; ++i) {
21851       color$$1 = rgb(colors[i]);
21852       r[i] = color$$1.r || 0;
21853       g[i] = color$$1.g || 0;
21854       b[i] = color$$1.b || 0;
21855     }
21856     r = spline(r);
21857     g = spline(g);
21858     b = spline(b);
21859     color$$1.opacity = 1;
21860     return function(t) {
21861       color$$1.r = r(t);
21862       color$$1.g = g(t);
21863       color$$1.b = b(t);
21864       return color$$1 + "";
21865     };
21866   };
21867 }
21868
21869 var rgbBasis = rgbSpline(basis$1);
21870 var rgbBasisClosed = rgbSpline(basisClosed);
21871
21872 var array$1 = function(a, b) {
21873   var nb = b ? b.length : 0,
21874       na = a ? Math.min(nb, a.length) : 0,
21875       x = new Array(nb),
21876       c = new Array(nb),
21877       i;
21878
21879   for (i = 0; i < na; ++i) x[i] = interpolateValue(a[i], b[i]);
21880   for (; i < nb; ++i) c[i] = b[i];
21881
21882   return function(t) {
21883     for (i = 0; i < na; ++i) c[i] = x[i](t);
21884     return c;
21885   };
21886 };
21887
21888 var date = function(a, b) {
21889   var d = new Date;
21890   return a = +a, b -= a, function(t) {
21891     return d.setTime(a + b * t), d;
21892   };
21893 };
21894
21895 var reinterpolate = function(a, b) {
21896   return a = +a, b -= a, function(t) {
21897     return a + b * t;
21898   };
21899 };
21900
21901 var object = function(a, b) {
21902   var i = {},
21903       c = {},
21904       k;
21905
21906   if (a === null || typeof a !== "object") a = {};
21907   if (b === null || typeof b !== "object") b = {};
21908
21909   for (k in b) {
21910     if (k in a) {
21911       i[k] = interpolateValue(a[k], b[k]);
21912     } else {
21913       c[k] = b[k];
21914     }
21915   }
21916
21917   return function(t) {
21918     for (k in i) c[k] = i[k](t);
21919     return c;
21920   };
21921 };
21922
21923 var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
21924 var reB = new RegExp(reA.source, "g");
21925
21926 function zero(b) {
21927   return function() {
21928     return b;
21929   };
21930 }
21931
21932 function one(b) {
21933   return function(t) {
21934     return b(t) + "";
21935   };
21936 }
21937
21938 var interpolateString = function(a, b) {
21939   var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
21940       am, // current match in a
21941       bm, // current match in b
21942       bs, // string preceding current number in b, if any
21943       i = -1, // index in s
21944       s = [], // string constants and placeholders
21945       q = []; // number interpolators
21946
21947   // Coerce inputs to strings.
21948   a = a + "", b = b + "";
21949
21950   // Interpolate pairs of numbers in a & b.
21951   while ((am = reA.exec(a))
21952       && (bm = reB.exec(b))) {
21953     if ((bs = bm.index) > bi) { // a string precedes the next number in b
21954       bs = b.slice(bi, bs);
21955       if (s[i]) s[i] += bs; // coalesce with previous string
21956       else s[++i] = bs;
21957     }
21958     if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
21959       if (s[i]) s[i] += bm; // coalesce with previous string
21960       else s[++i] = bm;
21961     } else { // interpolate non-matching numbers
21962       s[++i] = null;
21963       q.push({i: i, x: reinterpolate(am, bm)});
21964     }
21965     bi = reB.lastIndex;
21966   }
21967
21968   // Add remains of b.
21969   if (bi < b.length) {
21970     bs = b.slice(bi);
21971     if (s[i]) s[i] += bs; // coalesce with previous string
21972     else s[++i] = bs;
21973   }
21974
21975   // Special optimization for only a single match.
21976   // Otherwise, interpolate each of the numbers and rejoin the string.
21977   return s.length < 2 ? (q[0]
21978       ? one(q[0].x)
21979       : zero(b))
21980       : (b = q.length, function(t) {
21981           for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
21982           return s.join("");
21983         });
21984 };
21985
21986 var interpolateValue = function(a, b) {
21987   var t = typeof b, c;
21988   return b == null || t === "boolean" ? constant$3(b)
21989       : (t === "number" ? reinterpolate
21990       : t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString)
21991       : b instanceof color ? interpolateRgb
21992       : b instanceof Date ? date
21993       : Array.isArray(b) ? array$1
21994       : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
21995       : reinterpolate)(a, b);
21996 };
21997
21998 var interpolateRound = function(a, b) {
21999   return a = +a, b -= a, function(t) {
22000     return Math.round(a + b * t);
22001   };
22002 };
22003
22004 var degrees = 180 / Math.PI;
22005
22006 var identity$2 = {
22007   translateX: 0,
22008   translateY: 0,
22009   rotate: 0,
22010   skewX: 0,
22011   scaleX: 1,
22012   scaleY: 1
22013 };
22014
22015 var decompose = function(a, b, c, d, e, f) {
22016   var scaleX, scaleY, skewX;
22017   if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
22018   if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
22019   if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
22020   if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
22021   return {
22022     translateX: e,
22023     translateY: f,
22024     rotate: Math.atan2(b, a) * degrees,
22025     skewX: Math.atan(skewX) * degrees,
22026     scaleX: scaleX,
22027     scaleY: scaleY
22028   };
22029 };
22030
22031 var cssNode;
22032 var cssRoot;
22033 var cssView;
22034 var svgNode;
22035
22036 function parseCss(value) {
22037   if (value === "none") return identity$2;
22038   if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
22039   cssNode.style.transform = value;
22040   value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
22041   cssRoot.removeChild(cssNode);
22042   value = value.slice(7, -1).split(",");
22043   return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
22044 }
22045
22046 function parseSvg(value) {
22047   if (value == null) return identity$2;
22048   if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
22049   svgNode.setAttribute("transform", value);
22050   if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2;
22051   value = value.matrix;
22052   return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
22053 }
22054
22055 function interpolateTransform(parse, pxComma, pxParen, degParen) {
22056
22057   function pop(s) {
22058     return s.length ? s.pop() + " " : "";
22059   }
22060
22061   function translate(xa, ya, xb, yb, s, q) {
22062     if (xa !== xb || ya !== yb) {
22063       var i = s.push("translate(", null, pxComma, null, pxParen);
22064       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22065     } else if (xb || yb) {
22066       s.push("translate(" + xb + pxComma + yb + pxParen);
22067     }
22068   }
22069
22070   function rotate(a, b, s, q) {
22071     if (a !== b) {
22072       if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
22073       q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: reinterpolate(a, b)});
22074     } else if (b) {
22075       s.push(pop(s) + "rotate(" + b + degParen);
22076     }
22077   }
22078
22079   function skewX(a, b, s, q) {
22080     if (a !== b) {
22081       q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: reinterpolate(a, b)});
22082     } else if (b) {
22083       s.push(pop(s) + "skewX(" + b + degParen);
22084     }
22085   }
22086
22087   function scale(xa, ya, xb, yb, s, q) {
22088     if (xa !== xb || ya !== yb) {
22089       var i = s.push(pop(s) + "scale(", null, ",", null, ")");
22090       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22091     } else if (xb !== 1 || yb !== 1) {
22092       s.push(pop(s) + "scale(" + xb + "," + yb + ")");
22093     }
22094   }
22095
22096   return function(a, b) {
22097     var s = [], // string constants and placeholders
22098         q = []; // number interpolators
22099     a = parse(a), b = parse(b);
22100     translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
22101     rotate(a.rotate, b.rotate, s, q);
22102     skewX(a.skewX, b.skewX, s, q);
22103     scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
22104     a = b = null; // gc
22105     return function(t) {
22106       var i = -1, n = q.length, o;
22107       while (++i < n) s[(o = q[i]).i] = o.x(t);
22108       return s.join("");
22109     };
22110   };
22111 }
22112
22113 var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
22114 var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
22115
22116 var rho = Math.SQRT2;
22117 var rho2 = 2;
22118 var rho4 = 4;
22119 var epsilon2 = 1e-12;
22120
22121 function cosh(x) {
22122   return ((x = Math.exp(x)) + 1 / x) / 2;
22123 }
22124
22125 function sinh(x) {
22126   return ((x = Math.exp(x)) - 1 / x) / 2;
22127 }
22128
22129 function tanh(x) {
22130   return ((x = Math.exp(2 * x)) - 1) / (x + 1);
22131 }
22132
22133 // p0 = [ux0, uy0, w0]
22134 // p1 = [ux1, uy1, w1]
22135 var interpolateZoom = function(p0, p1) {
22136   var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
22137       ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
22138       dx = ux1 - ux0,
22139       dy = uy1 - uy0,
22140       d2 = dx * dx + dy * dy,
22141       i,
22142       S;
22143
22144   // Special case for u0 ≅ u1.
22145   if (d2 < epsilon2) {
22146     S = Math.log(w1 / w0) / rho;
22147     i = function(t) {
22148       return [
22149         ux0 + t * dx,
22150         uy0 + t * dy,
22151         w0 * Math.exp(rho * t * S)
22152       ];
22153     };
22154   }
22155
22156   // General case.
22157   else {
22158     var d1 = Math.sqrt(d2),
22159         b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
22160         b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
22161         r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
22162         r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
22163     S = (r1 - r0) / rho;
22164     i = function(t) {
22165       var s = t * S,
22166           coshr0 = cosh(r0),
22167           u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
22168       return [
22169         ux0 + u * dx,
22170         uy0 + u * dy,
22171         w0 * coshr0 / cosh(rho * s + r0)
22172       ];
22173     };
22174   }
22175
22176   i.duration = S * 1000;
22177
22178   return i;
22179 };
22180
22181 function hsl$1(hue$$1) {
22182   return function(start, end) {
22183     var h = hue$$1((start = hsl(start)).h, (end = hsl(end)).h),
22184         s = nogamma(start.s, end.s),
22185         l = nogamma(start.l, end.l),
22186         opacity = nogamma(start.opacity, end.opacity);
22187     return function(t) {
22188       start.h = h(t);
22189       start.s = s(t);
22190       start.l = l(t);
22191       start.opacity = opacity(t);
22192       return start + "";
22193     };
22194   }
22195 }
22196
22197 var hsl$2 = hsl$1(hue);
22198 var hslLong = hsl$1(nogamma);
22199
22200 function lab$1(start, end) {
22201   var l = nogamma((start = lab(start)).l, (end = lab(end)).l),
22202       a = nogamma(start.a, end.a),
22203       b = nogamma(start.b, end.b),
22204       opacity = nogamma(start.opacity, end.opacity);
22205   return function(t) {
22206     start.l = l(t);
22207     start.a = a(t);
22208     start.b = b(t);
22209     start.opacity = opacity(t);
22210     return start + "";
22211   };
22212 }
22213
22214 function hcl$1(hue$$1) {
22215   return function(start, end) {
22216     var h = hue$$1((start = hcl(start)).h, (end = hcl(end)).h),
22217         c = nogamma(start.c, end.c),
22218         l = nogamma(start.l, end.l),
22219         opacity = nogamma(start.opacity, end.opacity);
22220     return function(t) {
22221       start.h = h(t);
22222       start.c = c(t);
22223       start.l = l(t);
22224       start.opacity = opacity(t);
22225       return start + "";
22226     };
22227   }
22228 }
22229
22230 var hcl$2 = hcl$1(hue);
22231 var hclLong = hcl$1(nogamma);
22232
22233 function cubehelix$1(hue$$1) {
22234   return (function cubehelixGamma(y) {
22235     y = +y;
22236
22237     function cubehelix$$1(start, end) {
22238       var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h),
22239           s = nogamma(start.s, end.s),
22240           l = nogamma(start.l, end.l),
22241           opacity = nogamma(start.opacity, end.opacity);
22242       return function(t) {
22243         start.h = h(t);
22244         start.s = s(t);
22245         start.l = l(Math.pow(t, y));
22246         start.opacity = opacity(t);
22247         return start + "";
22248       };
22249     }
22250
22251     cubehelix$$1.gamma = cubehelixGamma;
22252
22253     return cubehelix$$1;
22254   })(1);
22255 }
22256
22257 var cubehelix$2 = cubehelix$1(hue);
22258 var cubehelixLong = cubehelix$1(nogamma);
22259
22260 var quantize = function(interpolator, n) {
22261   var samples = new Array(n);
22262   for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
22263   return samples;
22264 };
22265
22266 var frame = 0;
22267 var timeout = 0;
22268 var interval = 0;
22269 var pokeDelay = 1000;
22270 var taskHead;
22271 var taskTail;
22272 var clockLast = 0;
22273 var clockNow = 0;
22274 var clockSkew = 0;
22275 var clock = typeof performance === "object" && performance.now ? performance : Date;
22276 var setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) { setTimeout(f, 17); };
22277
22278 function now() {
22279   return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
22280 }
22281
22282 function clearNow() {
22283   clockNow = 0;
22284 }
22285
22286 function Timer() {
22287   this._call =
22288   this._time =
22289   this._next = null;
22290 }
22291
22292 Timer.prototype = timer.prototype = {
22293   constructor: Timer,
22294   restart: function(callback, delay, time) {
22295     if (typeof callback !== "function") throw new TypeError("callback is not a function");
22296     time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
22297     if (!this._next && taskTail !== this) {
22298       if (taskTail) taskTail._next = this;
22299       else taskHead = this;
22300       taskTail = this;
22301     }
22302     this._call = callback;
22303     this._time = time;
22304     sleep();
22305   },
22306   stop: function() {
22307     if (this._call) {
22308       this._call = null;
22309       this._time = Infinity;
22310       sleep();
22311     }
22312   }
22313 };
22314
22315 function timer(callback, delay, time) {
22316   var t = new Timer;
22317   t.restart(callback, delay, time);
22318   return t;
22319 }
22320
22321 function timerFlush() {
22322   now(); // Get the current time, if not already set.
22323   ++frame; // Pretend we’ve set an alarm, if we haven’t already.
22324   var t = taskHead, e;
22325   while (t) {
22326     if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
22327     t = t._next;
22328   }
22329   --frame;
22330 }
22331
22332 function wake() {
22333   clockNow = (clockLast = clock.now()) + clockSkew;
22334   frame = timeout = 0;
22335   try {
22336     timerFlush();
22337   } finally {
22338     frame = 0;
22339     nap();
22340     clockNow = 0;
22341   }
22342 }
22343
22344 function poke() {
22345   var now = clock.now(), delay = now - clockLast;
22346   if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
22347 }
22348
22349 function nap() {
22350   var t0, t1 = taskHead, t2, time = Infinity;
22351   while (t1) {
22352     if (t1._call) {
22353       if (time > t1._time) time = t1._time;
22354       t0 = t1, t1 = t1._next;
22355     } else {
22356       t2 = t1._next, t1._next = null;
22357       t1 = t0 ? t0._next = t2 : taskHead = t2;
22358     }
22359   }
22360   taskTail = t0;
22361   sleep(time);
22362 }
22363
22364 function sleep(time) {
22365   if (frame) return; // Soonest alarm already set, or will be.
22366   if (timeout) timeout = clearTimeout(timeout);
22367   var delay = time - clockNow;
22368   if (delay > 24) {
22369     if (time < Infinity) timeout = setTimeout(wake, delay);
22370     if (interval) interval = clearInterval(interval);
22371   } else {
22372     if (!interval) clockLast = clockNow, interval = setInterval(poke, pokeDelay);
22373     frame = 1, setFrame(wake);
22374   }
22375 }
22376
22377 var timeout$1 = function(callback, delay, time) {
22378   var t = new Timer;
22379   delay = delay == null ? 0 : +delay;
22380   t.restart(function(elapsed) {
22381     t.stop();
22382     callback(elapsed + delay);
22383   }, delay, time);
22384   return t;
22385 };
22386
22387 var interval$1 = function(callback, delay, time) {
22388   var t = new Timer, total = delay;
22389   if (delay == null) return t.restart(callback, delay, time), t;
22390   delay = +delay, time = time == null ? now() : +time;
22391   t.restart(function tick(elapsed) {
22392     elapsed += total;
22393     t.restart(tick, total += delay, time);
22394     callback(elapsed);
22395   }, delay, time);
22396   return t;
22397 };
22398
22399 var emptyOn = dispatch("start", "end", "interrupt");
22400 var emptyTween = [];
22401
22402 var CREATED = 0;
22403 var SCHEDULED = 1;
22404 var STARTING = 2;
22405 var STARTED = 3;
22406 var RUNNING = 4;
22407 var ENDING = 5;
22408 var ENDED = 6;
22409
22410 var schedule = function(node, name, id, index, group, timing) {
22411   var schedules = node.__transition;
22412   if (!schedules) node.__transition = {};
22413   else if (id in schedules) return;
22414   create(node, id, {
22415     name: name,
22416     index: index, // For context during callback.
22417     group: group, // For context during callback.
22418     on: emptyOn,
22419     tween: emptyTween,
22420     time: timing.time,
22421     delay: timing.delay,
22422     duration: timing.duration,
22423     ease: timing.ease,
22424     timer: null,
22425     state: CREATED
22426   });
22427 };
22428
22429 function init(node, id) {
22430   var schedule = node.__transition;
22431   if (!schedule || !(schedule = schedule[id]) || schedule.state > CREATED) throw new Error("too late");
22432   return schedule;
22433 }
22434
22435 function set$1(node, id) {
22436   var schedule = node.__transition;
22437   if (!schedule || !(schedule = schedule[id]) || schedule.state > STARTING) throw new Error("too late");
22438   return schedule;
22439 }
22440
22441 function get$1(node, id) {
22442   var schedule = node.__transition;
22443   if (!schedule || !(schedule = schedule[id])) throw new Error("too late");
22444   return schedule;
22445 }
22446
22447 function create(node, id, self) {
22448   var schedules = node.__transition,
22449       tween;
22450
22451   // Initialize the self timer when the transition is created.
22452   // Note the actual delay is not known until the first callback!
22453   schedules[id] = self;
22454   self.timer = timer(schedule, 0, self.time);
22455
22456   function schedule(elapsed) {
22457     self.state = SCHEDULED;
22458     self.timer.restart(start, self.delay, self.time);
22459
22460     // If the elapsed delay is less than our first sleep, start immediately.
22461     if (self.delay <= elapsed) start(elapsed - self.delay);
22462   }
22463
22464   function start(elapsed) {
22465     var i, j, n, o;
22466
22467     // If the state is not SCHEDULED, then we previously errored on start.
22468     if (self.state !== SCHEDULED) return stop();
22469
22470     for (i in schedules) {
22471       o = schedules[i];
22472       if (o.name !== self.name) continue;
22473
22474       // While this element already has a starting transition during this frame,
22475       // defer starting an interrupting transition until that transition has a
22476       // chance to tick (and possibly end); see d3/d3-transition#54!
22477       if (o.state === STARTED) return timeout$1(start);
22478
22479       // Interrupt the active transition, if any.
22480       // Dispatch the interrupt event.
22481       if (o.state === RUNNING) {
22482         o.state = ENDED;
22483         o.timer.stop();
22484         o.on.call("interrupt", node, node.__data__, o.index, o.group);
22485         delete schedules[i];
22486       }
22487
22488       // Cancel any pre-empted transitions. No interrupt event is dispatched
22489       // because the cancelled transitions never started. Note that this also
22490       // removes this transition from the pending list!
22491       else if (+i < id) {
22492         o.state = ENDED;
22493         o.timer.stop();
22494         delete schedules[i];
22495       }
22496     }
22497
22498     // Defer the first tick to end of the current frame; see d3/d3#1576.
22499     // Note the transition may be canceled after start and before the first tick!
22500     // Note this must be scheduled before the start event; see d3/d3-transition#16!
22501     // Assuming this is successful, subsequent callbacks go straight to tick.
22502     timeout$1(function() {
22503       if (self.state === STARTED) {
22504         self.state = RUNNING;
22505         self.timer.restart(tick, self.delay, self.time);
22506         tick(elapsed);
22507       }
22508     });
22509
22510     // Dispatch the start event.
22511     // Note this must be done before the tween are initialized.
22512     self.state = STARTING;
22513     self.on.call("start", node, node.__data__, self.index, self.group);
22514     if (self.state !== STARTING) return; // interrupted
22515     self.state = STARTED;
22516
22517     // Initialize the tween, deleting null tween.
22518     tween = new Array(n = self.tween.length);
22519     for (i = 0, j = -1; i < n; ++i) {
22520       if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
22521         tween[++j] = o;
22522       }
22523     }
22524     tween.length = j + 1;
22525   }
22526
22527   function tick(elapsed) {
22528     var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
22529         i = -1,
22530         n = tween.length;
22531
22532     while (++i < n) {
22533       tween[i].call(null, t);
22534     }
22535
22536     // Dispatch the end event.
22537     if (self.state === ENDING) {
22538       self.on.call("end", node, node.__data__, self.index, self.group);
22539       stop();
22540     }
22541   }
22542
22543   function stop() {
22544     self.state = ENDED;
22545     self.timer.stop();
22546     delete schedules[id];
22547     for (var i in schedules) return; // eslint-disable-line no-unused-vars
22548     delete node.__transition;
22549   }
22550 }
22551
22552 var interrupt = function(node, name) {
22553   var schedules = node.__transition,
22554       schedule$$1,
22555       active,
22556       empty = true,
22557       i;
22558
22559   if (!schedules) return;
22560
22561   name = name == null ? null : name + "";
22562
22563   for (i in schedules) {
22564     if ((schedule$$1 = schedules[i]).name !== name) { empty = false; continue; }
22565     active = schedule$$1.state > STARTING && schedule$$1.state < ENDING;
22566     schedule$$1.state = ENDED;
22567     schedule$$1.timer.stop();
22568     if (active) schedule$$1.on.call("interrupt", node, node.__data__, schedule$$1.index, schedule$$1.group);
22569     delete schedules[i];
22570   }
22571
22572   if (empty) delete node.__transition;
22573 };
22574
22575 var selection_interrupt = function(name) {
22576   return this.each(function() {
22577     interrupt(this, name);
22578   });
22579 };
22580
22581 function tweenRemove(id, name) {
22582   var tween0, tween1;
22583   return function() {
22584     var schedule$$1 = set$1(this, id),
22585         tween = schedule$$1.tween;
22586
22587     // If this node shared tween with the previous node,
22588     // just assign the updated shared tween and we’re done!
22589     // Otherwise, copy-on-write.
22590     if (tween !== tween0) {
22591       tween1 = tween0 = tween;
22592       for (var i = 0, n = tween1.length; i < n; ++i) {
22593         if (tween1[i].name === name) {
22594           tween1 = tween1.slice();
22595           tween1.splice(i, 1);
22596           break;
22597         }
22598       }
22599     }
22600
22601     schedule$$1.tween = tween1;
22602   };
22603 }
22604
22605 function tweenFunction(id, name, value) {
22606   var tween0, tween1;
22607   if (typeof value !== "function") throw new Error;
22608   return function() {
22609     var schedule$$1 = set$1(this, id),
22610         tween = schedule$$1.tween;
22611
22612     // If this node shared tween with the previous node,
22613     // just assign the updated shared tween and we’re done!
22614     // Otherwise, copy-on-write.
22615     if (tween !== tween0) {
22616       tween1 = (tween0 = tween).slice();
22617       for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {
22618         if (tween1[i].name === name) {
22619           tween1[i] = t;
22620           break;
22621         }
22622       }
22623       if (i === n) tween1.push(t);
22624     }
22625
22626     schedule$$1.tween = tween1;
22627   };
22628 }
22629
22630 var transition_tween = function(name, value) {
22631   var id = this._id;
22632
22633   name += "";
22634
22635   if (arguments.length < 2) {
22636     var tween = get$1(this.node(), id).tween;
22637     for (var i = 0, n = tween.length, t; i < n; ++i) {
22638       if ((t = tween[i]).name === name) {
22639         return t.value;
22640       }
22641     }
22642     return null;
22643   }
22644
22645   return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
22646 };
22647
22648 function tweenValue(transition, name, value) {
22649   var id = transition._id;
22650
22651   transition.each(function() {
22652     var schedule$$1 = set$1(this, id);
22653     (schedule$$1.value || (schedule$$1.value = {}))[name] = value.apply(this, arguments);
22654   });
22655
22656   return function(node) {
22657     return get$1(node, id).value[name];
22658   };
22659 }
22660
22661 var interpolate = function(a, b) {
22662   var c;
22663   return (typeof b === "number" ? reinterpolate
22664       : b instanceof color ? interpolateRgb
22665       : (c = color(b)) ? (b = c, interpolateRgb)
22666       : interpolateString)(a, b);
22667 };
22668
22669 function attrRemove$1(name) {
22670   return function() {
22671     this.removeAttribute(name);
22672   };
22673 }
22674
22675 function attrRemoveNS$1(fullname) {
22676   return function() {
22677     this.removeAttributeNS(fullname.space, fullname.local);
22678   };
22679 }
22680
22681 function attrConstant$1(name, interpolate$$1, value1) {
22682   var value00,
22683       interpolate0;
22684   return function() {
22685     var value0 = this.getAttribute(name);
22686     return value0 === value1 ? null
22687         : value0 === value00 ? interpolate0
22688         : interpolate0 = interpolate$$1(value00 = value0, value1);
22689   };
22690 }
22691
22692 function attrConstantNS$1(fullname, interpolate$$1, value1) {
22693   var value00,
22694       interpolate0;
22695   return function() {
22696     var value0 = this.getAttributeNS(fullname.space, fullname.local);
22697     return value0 === value1 ? null
22698         : value0 === value00 ? interpolate0
22699         : interpolate0 = interpolate$$1(value00 = value0, value1);
22700   };
22701 }
22702
22703 function attrFunction$1(name, interpolate$$1, value) {
22704   var value00,
22705       value10,
22706       interpolate0;
22707   return function() {
22708     var value0, value1 = value(this);
22709     if (value1 == null) return void this.removeAttribute(name);
22710     value0 = this.getAttribute(name);
22711     return value0 === value1 ? null
22712         : value0 === value00 && value1 === value10 ? interpolate0
22713         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22714   };
22715 }
22716
22717 function attrFunctionNS$1(fullname, interpolate$$1, value) {
22718   var value00,
22719       value10,
22720       interpolate0;
22721   return function() {
22722     var value0, value1 = value(this);
22723     if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
22724     value0 = this.getAttributeNS(fullname.space, fullname.local);
22725     return value0 === value1 ? null
22726         : value0 === value00 && value1 === value10 ? interpolate0
22727         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22728   };
22729 }
22730
22731 var transition_attr = function(name, value) {
22732   var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate;
22733   return this.attrTween(name, typeof value === "function"
22734       ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value))
22735       : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname)
22736       : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value + ""));
22737 };
22738
22739 function attrTweenNS(fullname, value) {
22740   function tween() {
22741     var node = this, i = value.apply(node, arguments);
22742     return i && function(t) {
22743       node.setAttributeNS(fullname.space, fullname.local, i(t));
22744     };
22745   }
22746   tween._value = value;
22747   return tween;
22748 }
22749
22750 function attrTween(name, value) {
22751   function tween() {
22752     var node = this, i = value.apply(node, arguments);
22753     return i && function(t) {
22754       node.setAttribute(name, i(t));
22755     };
22756   }
22757   tween._value = value;
22758   return tween;
22759 }
22760
22761 var transition_attrTween = function(name, value) {
22762   var key = "attr." + name;
22763   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
22764   if (value == null) return this.tween(key, null);
22765   if (typeof value !== "function") throw new Error;
22766   var fullname = namespace(name);
22767   return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
22768 };
22769
22770 function delayFunction(id, value) {
22771   return function() {
22772     init(this, id).delay = +value.apply(this, arguments);
22773   };
22774 }
22775
22776 function delayConstant(id, value) {
22777   return value = +value, function() {
22778     init(this, id).delay = value;
22779   };
22780 }
22781
22782 var transition_delay = function(value) {
22783   var id = this._id;
22784
22785   return arguments.length
22786       ? this.each((typeof value === "function"
22787           ? delayFunction
22788           : delayConstant)(id, value))
22789       : get$1(this.node(), id).delay;
22790 };
22791
22792 function durationFunction(id, value) {
22793   return function() {
22794     set$1(this, id).duration = +value.apply(this, arguments);
22795   };
22796 }
22797
22798 function durationConstant(id, value) {
22799   return value = +value, function() {
22800     set$1(this, id).duration = value;
22801   };
22802 }
22803
22804 var transition_duration = function(value) {
22805   var id = this._id;
22806
22807   return arguments.length
22808       ? this.each((typeof value === "function"
22809           ? durationFunction
22810           : durationConstant)(id, value))
22811       : get$1(this.node(), id).duration;
22812 };
22813
22814 function easeConstant(id, value) {
22815   if (typeof value !== "function") throw new Error;
22816   return function() {
22817     set$1(this, id).ease = value;
22818   };
22819 }
22820
22821 var transition_ease = function(value) {
22822   var id = this._id;
22823
22824   return arguments.length
22825       ? this.each(easeConstant(id, value))
22826       : get$1(this.node(), id).ease;
22827 };
22828
22829 var transition_filter = function(match) {
22830   if (typeof match !== "function") match = matcher$1(match);
22831
22832   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22833     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
22834       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
22835         subgroup.push(node);
22836       }
22837     }
22838   }
22839
22840   return new Transition(subgroups, this._parents, this._name, this._id);
22841 };
22842
22843 var transition_merge = function(transition$$1) {
22844   if (transition$$1._id !== this._id) throw new Error;
22845
22846   for (var groups0 = this._groups, groups1 = transition$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
22847     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
22848       if (node = group0[i] || group1[i]) {
22849         merge[i] = node;
22850       }
22851     }
22852   }
22853
22854   for (; j < m0; ++j) {
22855     merges[j] = groups0[j];
22856   }
22857
22858   return new Transition(merges, this._parents, this._name, this._id);
22859 };
22860
22861 function start(name) {
22862   return (name + "").trim().split(/^|\s+/).every(function(t) {
22863     var i = t.indexOf(".");
22864     if (i >= 0) t = t.slice(0, i);
22865     return !t || t === "start";
22866   });
22867 }
22868
22869 function onFunction(id, name, listener) {
22870   var on0, on1, sit = start(name) ? init : set$1;
22871   return function() {
22872     var schedule$$1 = sit(this, id),
22873         on = schedule$$1.on;
22874
22875     // If this node shared a dispatch with the previous node,
22876     // just assign the updated shared dispatch and we’re done!
22877     // Otherwise, copy-on-write.
22878     if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
22879
22880     schedule$$1.on = on1;
22881   };
22882 }
22883
22884 var transition_on = function(name, listener) {
22885   var id = this._id;
22886
22887   return arguments.length < 2
22888       ? get$1(this.node(), id).on.on(name)
22889       : this.each(onFunction(id, name, listener));
22890 };
22891
22892 function removeFunction(id) {
22893   return function() {
22894     var parent = this.parentNode;
22895     for (var i in this.__transition) if (+i !== id) return;
22896     if (parent) parent.removeChild(this);
22897   };
22898 }
22899
22900 var transition_remove = function() {
22901   return this.on("end.remove", removeFunction(this._id));
22902 };
22903
22904 var transition_select = function(select$$1) {
22905   var name = this._name,
22906       id = this._id;
22907
22908   if (typeof select$$1 !== "function") select$$1 = selector(select$$1);
22909
22910   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22911     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
22912       if ((node = group[i]) && (subnode = select$$1.call(node, node.__data__, i, group))) {
22913         if ("__data__" in node) subnode.__data__ = node.__data__;
22914         subgroup[i] = subnode;
22915         schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
22916       }
22917     }
22918   }
22919
22920   return new Transition(subgroups, this._parents, name, id);
22921 };
22922
22923 var transition_selectAll = function(select$$1) {
22924   var name = this._name,
22925       id = this._id;
22926
22927   if (typeof select$$1 !== "function") select$$1 = selectorAll(select$$1);
22928
22929   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
22930     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
22931       if (node = group[i]) {
22932         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) {
22933           if (child = children[k]) {
22934             schedule(child, name, id, k, children, inherit);
22935           }
22936         }
22937         subgroups.push(children);
22938         parents.push(node);
22939       }
22940     }
22941   }
22942
22943   return new Transition(subgroups, parents, name, id);
22944 };
22945
22946 var Selection$1 = selection.prototype.constructor;
22947
22948 var transition_selection = function() {
22949   return new Selection$1(this._groups, this._parents);
22950 };
22951
22952 function styleRemove$1(name, interpolate$$1) {
22953   var value00,
22954       value10,
22955       interpolate0;
22956   return function() {
22957     var value0 = styleValue(this, name),
22958         value1 = (this.style.removeProperty(name), styleValue(this, name));
22959     return value0 === value1 ? null
22960         : value0 === value00 && value1 === value10 ? interpolate0
22961         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22962   };
22963 }
22964
22965 function styleRemoveEnd(name) {
22966   return function() {
22967     this.style.removeProperty(name);
22968   };
22969 }
22970
22971 function styleConstant$1(name, interpolate$$1, value1) {
22972   var value00,
22973       interpolate0;
22974   return function() {
22975     var value0 = styleValue(this, name);
22976     return value0 === value1 ? null
22977         : value0 === value00 ? interpolate0
22978         : interpolate0 = interpolate$$1(value00 = value0, value1);
22979   };
22980 }
22981
22982 function styleFunction$1(name, interpolate$$1, value) {
22983   var value00,
22984       value10,
22985       interpolate0;
22986   return function() {
22987     var value0 = styleValue(this, name),
22988         value1 = value(this);
22989     if (value1 == null) value1 = (this.style.removeProperty(name), styleValue(this, name));
22990     return value0 === value1 ? null
22991         : value0 === value00 && value1 === value10 ? interpolate0
22992         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22993   };
22994 }
22995
22996 var transition_style = function(name, value, priority) {
22997   var i = (name += "") === "transform" ? interpolateTransformCss : interpolate;
22998   return value == null ? this
22999           .styleTween(name, styleRemove$1(name, i))
23000           .on("end.style." + name, styleRemoveEnd(name))
23001       : this.styleTween(name, typeof value === "function"
23002           ? styleFunction$1(name, i, tweenValue(this, "style." + name, value))
23003           : styleConstant$1(name, i, value + ""), priority);
23004 };
23005
23006 function styleTween(name, value, priority) {
23007   function tween() {
23008     var node = this, i = value.apply(node, arguments);
23009     return i && function(t) {
23010       node.style.setProperty(name, i(t), priority);
23011     };
23012   }
23013   tween._value = value;
23014   return tween;
23015 }
23016
23017 var transition_styleTween = function(name, value, priority) {
23018   var key = "style." + (name += "");
23019   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
23020   if (value == null) return this.tween(key, null);
23021   if (typeof value !== "function") throw new Error;
23022   return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
23023 };
23024
23025 function textConstant$1(value) {
23026   return function() {
23027     this.textContent = value;
23028   };
23029 }
23030
23031 function textFunction$1(value) {
23032   return function() {
23033     var value1 = value(this);
23034     this.textContent = value1 == null ? "" : value1;
23035   };
23036 }
23037
23038 var transition_text = function(value) {
23039   return this.tween("text", typeof value === "function"
23040       ? textFunction$1(tweenValue(this, "text", value))
23041       : textConstant$1(value == null ? "" : value + ""));
23042 };
23043
23044 var transition_transition = function() {
23045   var name = this._name,
23046       id0 = this._id,
23047       id1 = newId();
23048
23049   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23050     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23051       if (node = group[i]) {
23052         var inherit = get$1(node, id0);
23053         schedule(node, name, id1, i, group, {
23054           time: inherit.time + inherit.delay + inherit.duration,
23055           delay: 0,
23056           duration: inherit.duration,
23057           ease: inherit.ease
23058         });
23059       }
23060     }
23061   }
23062
23063   return new Transition(groups, this._parents, name, id1);
23064 };
23065
23066 var id = 0;
23067
23068 function Transition(groups, parents, name, id) {
23069   this._groups = groups;
23070   this._parents = parents;
23071   this._name = name;
23072   this._id = id;
23073 }
23074
23075 function transition(name) {
23076   return selection().transition(name);
23077 }
23078
23079 function newId() {
23080   return ++id;
23081 }
23082
23083 var selection_prototype = selection.prototype;
23084
23085 Transition.prototype = transition.prototype = {
23086   constructor: Transition,
23087   select: transition_select,
23088   selectAll: transition_selectAll,
23089   filter: transition_filter,
23090   merge: transition_merge,
23091   selection: transition_selection,
23092   transition: transition_transition,
23093   call: selection_prototype.call,
23094   nodes: selection_prototype.nodes,
23095   node: selection_prototype.node,
23096   size: selection_prototype.size,
23097   empty: selection_prototype.empty,
23098   each: selection_prototype.each,
23099   on: transition_on,
23100   attr: transition_attr,
23101   attrTween: transition_attrTween,
23102   style: transition_style,
23103   styleTween: transition_styleTween,
23104   text: transition_text,
23105   remove: transition_remove,
23106   tween: transition_tween,
23107   delay: transition_delay,
23108   duration: transition_duration,
23109   ease: transition_ease
23110 };
23111
23112 function linear$1(t) {
23113   return +t;
23114 }
23115
23116 function quadIn(t) {
23117   return t * t;
23118 }
23119
23120 function quadOut(t) {
23121   return t * (2 - t);
23122 }
23123
23124 function quadInOut(t) {
23125   return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
23126 }
23127
23128 function cubicIn(t) {
23129   return t * t * t;
23130 }
23131
23132 function cubicOut(t) {
23133   return --t * t * t + 1;
23134 }
23135
23136 function cubicInOut(t) {
23137   return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
23138 }
23139
23140 var exponent = 3;
23141
23142 var polyIn = (function custom(e) {
23143   e = +e;
23144
23145   function polyIn(t) {
23146     return Math.pow(t, e);
23147   }
23148
23149   polyIn.exponent = custom;
23150
23151   return polyIn;
23152 })(exponent);
23153
23154 var polyOut = (function custom(e) {
23155   e = +e;
23156
23157   function polyOut(t) {
23158     return 1 - Math.pow(1 - t, e);
23159   }
23160
23161   polyOut.exponent = custom;
23162
23163   return polyOut;
23164 })(exponent);
23165
23166 var polyInOut = (function custom(e) {
23167   e = +e;
23168
23169   function polyInOut(t) {
23170     return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
23171   }
23172
23173   polyInOut.exponent = custom;
23174
23175   return polyInOut;
23176 })(exponent);
23177
23178 var pi = Math.PI;
23179 var halfPi = pi / 2;
23180
23181 function sinIn(t) {
23182   return 1 - Math.cos(t * halfPi);
23183 }
23184
23185 function sinOut(t) {
23186   return Math.sin(t * halfPi);
23187 }
23188
23189 function sinInOut(t) {
23190   return (1 - Math.cos(pi * t)) / 2;
23191 }
23192
23193 function expIn(t) {
23194   return Math.pow(2, 10 * t - 10);
23195 }
23196
23197 function expOut(t) {
23198   return 1 - Math.pow(2, -10 * t);
23199 }
23200
23201 function expInOut(t) {
23202   return ((t *= 2) <= 1 ? Math.pow(2, 10 * t - 10) : 2 - Math.pow(2, 10 - 10 * t)) / 2;
23203 }
23204
23205 function circleIn(t) {
23206   return 1 - Math.sqrt(1 - t * t);
23207 }
23208
23209 function circleOut(t) {
23210   return Math.sqrt(1 - --t * t);
23211 }
23212
23213 function circleInOut(t) {
23214   return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
23215 }
23216
23217 var b1 = 4 / 11;
23218 var b2 = 6 / 11;
23219 var b3 = 8 / 11;
23220 var b4 = 3 / 4;
23221 var b5 = 9 / 11;
23222 var b6 = 10 / 11;
23223 var b7 = 15 / 16;
23224 var b8 = 21 / 22;
23225 var b9 = 63 / 64;
23226 var b0 = 1 / b1 / b1;
23227
23228 function bounceIn(t) {
23229   return 1 - bounceOut(1 - t);
23230 }
23231
23232 function bounceOut(t) {
23233   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;
23234 }
23235
23236 function bounceInOut(t) {
23237   return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
23238 }
23239
23240 var overshoot = 1.70158;
23241
23242 var backIn = (function custom(s) {
23243   s = +s;
23244
23245   function backIn(t) {
23246     return t * t * ((s + 1) * t - s);
23247   }
23248
23249   backIn.overshoot = custom;
23250
23251   return backIn;
23252 })(overshoot);
23253
23254 var backOut = (function custom(s) {
23255   s = +s;
23256
23257   function backOut(t) {
23258     return --t * t * ((s + 1) * t + s) + 1;
23259   }
23260
23261   backOut.overshoot = custom;
23262
23263   return backOut;
23264 })(overshoot);
23265
23266 var backInOut = (function custom(s) {
23267   s = +s;
23268
23269   function backInOut(t) {
23270     return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
23271   }
23272
23273   backInOut.overshoot = custom;
23274
23275   return backInOut;
23276 })(overshoot);
23277
23278 var tau = 2 * Math.PI;
23279 var amplitude = 1;
23280 var period = 0.3;
23281
23282 var elasticIn = (function custom(a, p) {
23283   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23284
23285   function elasticIn(t) {
23286     return a * Math.pow(2, 10 * --t) * Math.sin((s - t) / p);
23287   }
23288
23289   elasticIn.amplitude = function(a) { return custom(a, p * tau); };
23290   elasticIn.period = function(p) { return custom(a, p); };
23291
23292   return elasticIn;
23293 })(amplitude, period);
23294
23295 var elasticOut = (function custom(a, p) {
23296   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23297
23298   function elasticOut(t) {
23299     return 1 - a * Math.pow(2, -10 * (t = +t)) * Math.sin((t + s) / p);
23300   }
23301
23302   elasticOut.amplitude = function(a) { return custom(a, p * tau); };
23303   elasticOut.period = function(p) { return custom(a, p); };
23304
23305   return elasticOut;
23306 })(amplitude, period);
23307
23308 var elasticInOut = (function custom(a, p) {
23309   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23310
23311   function elasticInOut(t) {
23312     return ((t = t * 2 - 1) < 0
23313         ? a * Math.pow(2, 10 * t) * Math.sin((s - t) / p)
23314         : 2 - a * Math.pow(2, -10 * t) * Math.sin((s + t) / p)) / 2;
23315   }
23316
23317   elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
23318   elasticInOut.period = function(p) { return custom(a, p); };
23319
23320   return elasticInOut;
23321 })(amplitude, period);
23322
23323 var defaultTiming = {
23324   time: null, // Set on use.
23325   delay: 0,
23326   duration: 250,
23327   ease: cubicInOut
23328 };
23329
23330 function inherit(node, id) {
23331   var timing;
23332   while (!(timing = node.__transition) || !(timing = timing[id])) {
23333     if (!(node = node.parentNode)) {
23334       return defaultTiming.time = now(), defaultTiming;
23335     }
23336   }
23337   return timing;
23338 }
23339
23340 var selection_transition = function(name) {
23341   var id,
23342       timing;
23343
23344   if (name instanceof Transition) {
23345     id = name._id, name = name._name;
23346   } else {
23347     id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
23348   }
23349
23350   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23351     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23352       if (node = group[i]) {
23353         schedule(node, name, id, i, group, timing || inherit(node, id));
23354       }
23355     }
23356   }
23357
23358   return new Transition(groups, this._parents, name, id);
23359 };
23360
23361 selection.prototype.interrupt = selection_interrupt;
23362 selection.prototype.transition = selection_transition;
23363
23364 var root$1 = [null];
23365
23366 var active = function(node, name) {
23367   var schedules = node.__transition,
23368       schedule$$1,
23369       i;
23370
23371   if (schedules) {
23372     name = name == null ? null : name + "";
23373     for (i in schedules) {
23374       if ((schedule$$1 = schedules[i]).state > SCHEDULED && schedule$$1.name === name) {
23375         return new Transition([[node]], root$1, name, +i);
23376       }
23377     }
23378   }
23379
23380   return null;
23381 };
23382
23383 var constant$4 = function(x) {
23384   return function() {
23385     return x;
23386   };
23387 };
23388
23389 var BrushEvent = function(target, type, selection) {
23390   this.target = target;
23391   this.type = type;
23392   this.selection = selection;
23393 };
23394
23395 function nopropagation$1() {
23396   event.stopImmediatePropagation();
23397 }
23398
23399 var noevent$1 = function() {
23400   event.preventDefault();
23401   event.stopImmediatePropagation();
23402 };
23403
23404 var MODE_DRAG = {name: "drag"};
23405 var MODE_SPACE = {name: "space"};
23406 var MODE_HANDLE = {name: "handle"};
23407 var MODE_CENTER = {name: "center"};
23408
23409 var X = {
23410   name: "x",
23411   handles: ["e", "w"].map(type$2),
23412   input: function(x, e) { return x && [[x[0], e[0][1]], [x[1], e[1][1]]]; },
23413   output: function(xy) { return xy && [xy[0][0], xy[1][0]]; }
23414 };
23415
23416 var Y = {
23417   name: "y",
23418   handles: ["n", "s"].map(type$2),
23419   input: function(y, e) { return y && [[e[0][0], y[0]], [e[1][0], y[1]]]; },
23420   output: function(xy) { return xy && [xy[0][1], xy[1][1]]; }
23421 };
23422
23423 var XY = {
23424   name: "xy",
23425   handles: ["n", "e", "s", "w", "nw", "ne", "se", "sw"].map(type$2),
23426   input: function(xy) { return xy; },
23427   output: function(xy) { return xy; }
23428 };
23429
23430 var cursors = {
23431   overlay: "crosshair",
23432   selection: "move",
23433   n: "ns-resize",
23434   e: "ew-resize",
23435   s: "ns-resize",
23436   w: "ew-resize",
23437   nw: "nwse-resize",
23438   ne: "nesw-resize",
23439   se: "nwse-resize",
23440   sw: "nesw-resize"
23441 };
23442
23443 var flipX = {
23444   e: "w",
23445   w: "e",
23446   nw: "ne",
23447   ne: "nw",
23448   se: "sw",
23449   sw: "se"
23450 };
23451
23452 var flipY = {
23453   n: "s",
23454   s: "n",
23455   nw: "sw",
23456   ne: "se",
23457   se: "ne",
23458   sw: "nw"
23459 };
23460
23461 var signsX = {
23462   overlay: +1,
23463   selection: +1,
23464   n: null,
23465   e: +1,
23466   s: null,
23467   w: -1,
23468   nw: -1,
23469   ne: +1,
23470   se: +1,
23471   sw: -1
23472 };
23473
23474 var signsY = {
23475   overlay: +1,
23476   selection: +1,
23477   n: -1,
23478   e: null,
23479   s: +1,
23480   w: null,
23481   nw: -1,
23482   ne: -1,
23483   se: +1,
23484   sw: +1
23485 };
23486
23487 function type$2(t) {
23488   return {type: t};
23489 }
23490
23491 // Ignore right-click, since that should open the context menu.
23492 function defaultFilter() {
23493   return !event.button;
23494 }
23495
23496 function defaultExtent() {
23497   var svg = this.ownerSVGElement || this;
23498   return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]];
23499 }
23500
23501 // Like d3.local, but with the name “__brush” rather than auto-generated.
23502 function local$$1(node) {
23503   while (!node.__brush) if (!(node = node.parentNode)) return;
23504   return node.__brush;
23505 }
23506
23507 function empty(extent) {
23508   return extent[0][0] === extent[1][0]
23509       || extent[0][1] === extent[1][1];
23510 }
23511
23512 function brushSelection(node) {
23513   var state = node.__brush;
23514   return state ? state.dim.output(state.selection) : null;
23515 }
23516
23517 function brushX() {
23518   return brush$1(X);
23519 }
23520
23521 function brushY() {
23522   return brush$1(Y);
23523 }
23524
23525 var brush = function() {
23526   return brush$1(XY);
23527 };
23528
23529 function brush$1(dim) {
23530   var extent = defaultExtent,
23531       filter = defaultFilter,
23532       listeners = dispatch(brush, "start", "brush", "end"),
23533       handleSize = 6,
23534       touchending;
23535
23536   function brush(group) {
23537     var overlay = group
23538         .property("__brush", initialize)
23539       .selectAll(".overlay")
23540       .data([type$2("overlay")]);
23541
23542     overlay.enter().append("rect")
23543         .attr("class", "overlay")
23544         .attr("pointer-events", "all")
23545         .attr("cursor", cursors.overlay)
23546       .merge(overlay)
23547         .each(function() {
23548           var extent = local$$1(this).extent;
23549           select(this)
23550               .attr("x", extent[0][0])
23551               .attr("y", extent[0][1])
23552               .attr("width", extent[1][0] - extent[0][0])
23553               .attr("height", extent[1][1] - extent[0][1]);
23554         });
23555
23556     group.selectAll(".selection")
23557       .data([type$2("selection")])
23558       .enter().append("rect")
23559         .attr("class", "selection")
23560         .attr("cursor", cursors.selection)
23561         .attr("fill", "#777")
23562         .attr("fill-opacity", 0.3)
23563         .attr("stroke", "#fff")
23564         .attr("shape-rendering", "crispEdges");
23565
23566     var handle = group.selectAll(".handle")
23567       .data(dim.handles, function(d) { return d.type; });
23568
23569     handle.exit().remove();
23570
23571     handle.enter().append("rect")
23572         .attr("class", function(d) { return "handle handle--" + d.type; })
23573         .attr("cursor", function(d) { return cursors[d.type]; });
23574
23575     group
23576         .each(redraw)
23577         .attr("fill", "none")
23578         .attr("pointer-events", "all")
23579         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
23580         .on("mousedown.brush touchstart.brush", started);
23581   }
23582
23583   brush.move = function(group, selection) {
23584     if (group.selection) {
23585       group
23586           .on("start.brush", function() { emitter(this, arguments).beforestart().start(); })
23587           .on("interrupt.brush end.brush", function() { emitter(this, arguments).end(); })
23588           .tween("brush", function() {
23589             var that = this,
23590                 state = that.__brush,
23591                 emit = emitter(that, arguments),
23592                 selection0 = state.selection,
23593                 selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent),
23594                 i = interpolateValue(selection0, selection1);
23595
23596             function tween(t) {
23597               state.selection = t === 1 && empty(selection1) ? null : i(t);
23598               redraw.call(that);
23599               emit.brush();
23600             }
23601
23602             return selection0 && selection1 ? tween : tween(1);
23603           });
23604     } else {
23605       group
23606           .each(function() {
23607             var that = this,
23608                 args = arguments,
23609                 state = that.__brush,
23610                 selection1 = dim.input(typeof selection === "function" ? selection.apply(that, args) : selection, state.extent),
23611                 emit = emitter(that, args).beforestart();
23612
23613             interrupt(that);
23614             state.selection = selection1 == null || empty(selection1) ? null : selection1;
23615             redraw.call(that);
23616             emit.start().brush().end();
23617           });
23618     }
23619   };
23620
23621   function redraw() {
23622     var group = select(this),
23623         selection = local$$1(this).selection;
23624
23625     if (selection) {
23626       group.selectAll(".selection")
23627           .style("display", null)
23628           .attr("x", selection[0][0])
23629           .attr("y", selection[0][1])
23630           .attr("width", selection[1][0] - selection[0][0])
23631           .attr("height", selection[1][1] - selection[0][1]);
23632
23633       group.selectAll(".handle")
23634           .style("display", null)
23635           .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection[1][0] - handleSize / 2 : selection[0][0] - handleSize / 2; })
23636           .attr("y", function(d) { return d.type[0] === "s" ? selection[1][1] - handleSize / 2 : selection[0][1] - handleSize / 2; })
23637           .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection[1][0] - selection[0][0] + handleSize : handleSize; })
23638           .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection[1][1] - selection[0][1] + handleSize : handleSize; });
23639     }
23640
23641     else {
23642       group.selectAll(".selection,.handle")
23643           .style("display", "none")
23644           .attr("x", null)
23645           .attr("y", null)
23646           .attr("width", null)
23647           .attr("height", null);
23648     }
23649   }
23650
23651   function emitter(that, args) {
23652     return that.__brush.emitter || new Emitter(that, args);
23653   }
23654
23655   function Emitter(that, args) {
23656     this.that = that;
23657     this.args = args;
23658     this.state = that.__brush;
23659     this.active = 0;
23660   }
23661
23662   Emitter.prototype = {
23663     beforestart: function() {
23664       if (++this.active === 1) this.state.emitter = this, this.starting = true;
23665       return this;
23666     },
23667     start: function() {
23668       if (this.starting) this.starting = false, this.emit("start");
23669       return this;
23670     },
23671     brush: function() {
23672       this.emit("brush");
23673       return this;
23674     },
23675     end: function() {
23676       if (--this.active === 0) delete this.state.emitter, this.emit("end");
23677       return this;
23678     },
23679     emit: function(type) {
23680       customEvent(new BrushEvent(brush, type, dim.output(this.state.selection)), listeners.apply, listeners, [type, this.that, this.args]);
23681     }
23682   };
23683
23684   function started() {
23685     if (event.touches) { if (event.changedTouches.length < event.touches.length) return noevent$1(); }
23686     else if (touchending) return;
23687     if (!filter.apply(this, arguments)) return;
23688
23689     var that = this,
23690         type = event.target.__data__.type,
23691         mode = (event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (event.altKey ? MODE_CENTER : MODE_HANDLE),
23692         signX = dim === Y ? null : signsX[type],
23693         signY = dim === X ? null : signsY[type],
23694         state = local$$1(that),
23695         extent = state.extent,
23696         selection = state.selection,
23697         W = extent[0][0], w0, w1,
23698         N = extent[0][1], n0, n1,
23699         E = extent[1][0], e0, e1,
23700         S = extent[1][1], s0, s1,
23701         dx,
23702         dy,
23703         moving,
23704         shifting = signX && signY && event.shiftKey,
23705         lockX,
23706         lockY,
23707         point0 = mouse(that),
23708         point = point0,
23709         emit = emitter(that, arguments).beforestart();
23710
23711     if (type === "overlay") {
23712       state.selection = selection = [
23713         [w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]],
23714         [e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0]
23715       ];
23716     } else {
23717       w0 = selection[0][0];
23718       n0 = selection[0][1];
23719       e0 = selection[1][0];
23720       s0 = selection[1][1];
23721     }
23722
23723     w1 = w0;
23724     n1 = n0;
23725     e1 = e0;
23726     s1 = s0;
23727
23728     var group = select(that)
23729         .attr("pointer-events", "none");
23730
23731     var overlay = group.selectAll(".overlay")
23732         .attr("cursor", cursors[type]);
23733
23734     if (event.touches) {
23735       group
23736           .on("touchmove.brush", moved, true)
23737           .on("touchend.brush touchcancel.brush", ended, true);
23738     } else {
23739       var view = select(event.view)
23740           .on("keydown.brush", keydowned, true)
23741           .on("keyup.brush", keyupped, true)
23742           .on("mousemove.brush", moved, true)
23743           .on("mouseup.brush", ended, true);
23744
23745       dragDisable(event.view);
23746     }
23747
23748     nopropagation$1();
23749     interrupt(that);
23750     redraw.call(that);
23751     emit.start();
23752
23753     function moved() {
23754       var point1 = mouse(that);
23755       if (shifting && !lockX && !lockY) {
23756         if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true;
23757         else lockX = true;
23758       }
23759       point = point1;
23760       moving = true;
23761       noevent$1();
23762       move();
23763     }
23764
23765     function move() {
23766       var t;
23767
23768       dx = point[0] - point0[0];
23769       dy = point[1] - point0[1];
23770
23771       switch (mode) {
23772         case MODE_SPACE:
23773         case MODE_DRAG: {
23774           if (signX) dx = Math.max(W - w0, Math.min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
23775           if (signY) dy = Math.max(N - n0, Math.min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
23776           break;
23777         }
23778         case MODE_HANDLE: {
23779           if (signX < 0) dx = Math.max(W - w0, Math.min(E - w0, dx)), w1 = w0 + dx, e1 = e0;
23780           else if (signX > 0) dx = Math.max(W - e0, Math.min(E - e0, dx)), w1 = w0, e1 = e0 + dx;
23781           if (signY < 0) dy = Math.max(N - n0, Math.min(S - n0, dy)), n1 = n0 + dy, s1 = s0;
23782           else if (signY > 0) dy = Math.max(N - s0, Math.min(S - s0, dy)), n1 = n0, s1 = s0 + dy;
23783           break;
23784         }
23785         case MODE_CENTER: {
23786           if (signX) w1 = Math.max(W, Math.min(E, w0 - dx * signX)), e1 = Math.max(W, Math.min(E, e0 + dx * signX));
23787           if (signY) n1 = Math.max(N, Math.min(S, n0 - dy * signY)), s1 = Math.max(N, Math.min(S, s0 + dy * signY));
23788           break;
23789         }
23790       }
23791
23792       if (e1 < w1) {
23793         signX *= -1;
23794         t = w0, w0 = e0, e0 = t;
23795         t = w1, w1 = e1, e1 = t;
23796         if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]);
23797       }
23798
23799       if (s1 < n1) {
23800         signY *= -1;
23801         t = n0, n0 = s0, s0 = t;
23802         t = n1, n1 = s1, s1 = t;
23803         if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]);
23804       }
23805
23806       if (state.selection) selection = state.selection; // May be set by brush.move!
23807       if (lockX) w1 = selection[0][0], e1 = selection[1][0];
23808       if (lockY) n1 = selection[0][1], s1 = selection[1][1];
23809
23810       if (selection[0][0] !== w1
23811           || selection[0][1] !== n1
23812           || selection[1][0] !== e1
23813           || selection[1][1] !== s1) {
23814         state.selection = [[w1, n1], [e1, s1]];
23815         redraw.call(that);
23816         emit.brush();
23817       }
23818     }
23819
23820     function ended() {
23821       nopropagation$1();
23822       if (event.touches) {
23823         if (event.touches.length) return;
23824         if (touchending) clearTimeout(touchending);
23825         touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
23826         group.on("touchmove.brush touchend.brush touchcancel.brush", null);
23827       } else {
23828         yesdrag(event.view, moving);
23829         view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null);
23830       }
23831       group.attr("pointer-events", "all");
23832       overlay.attr("cursor", cursors.overlay);
23833       if (state.selection) selection = state.selection; // May be set by brush.move (on start)!
23834       if (empty(selection)) state.selection = null, redraw.call(that);
23835       emit.end();
23836     }
23837
23838     function keydowned() {
23839       switch (event.keyCode) {
23840         case 16: { // SHIFT
23841           shifting = signX && signY;
23842           break;
23843         }
23844         case 18: { // ALT
23845           if (mode === MODE_HANDLE) {
23846             if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23847             if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23848             mode = MODE_CENTER;
23849             move();
23850           }
23851           break;
23852         }
23853         case 32: { // SPACE; takes priority over ALT
23854           if (mode === MODE_HANDLE || mode === MODE_CENTER) {
23855             if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx;
23856             if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy;
23857             mode = MODE_SPACE;
23858             overlay.attr("cursor", cursors.selection);
23859             move();
23860           }
23861           break;
23862         }
23863         default: return;
23864       }
23865       noevent$1();
23866     }
23867
23868     function keyupped() {
23869       switch (event.keyCode) {
23870         case 16: { // SHIFT
23871           if (shifting) {
23872             lockX = lockY = shifting = false;
23873             move();
23874           }
23875           break;
23876         }
23877         case 18: { // ALT
23878           if (mode === MODE_CENTER) {
23879             if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23880             if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23881             mode = MODE_HANDLE;
23882             move();
23883           }
23884           break;
23885         }
23886         case 32: { // SPACE
23887           if (mode === MODE_SPACE) {
23888             if (event.altKey) {
23889               if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23890               if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23891               mode = MODE_CENTER;
23892             } else {
23893               if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23894               if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23895               mode = MODE_HANDLE;
23896             }
23897             overlay.attr("cursor", cursors[type]);
23898             move();
23899           }
23900           break;
23901         }
23902         default: return;
23903       }
23904       noevent$1();
23905     }
23906   }
23907
23908   function initialize() {
23909     var state = this.__brush || {selection: null};
23910     state.extent = extent.apply(this, arguments);
23911     state.dim = dim;
23912     return state;
23913   }
23914
23915   brush.extent = function(_) {
23916     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$4([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), brush) : extent;
23917   };
23918
23919   brush.filter = function(_) {
23920     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$4(!!_), brush) : filter;
23921   };
23922
23923   brush.handleSize = function(_) {
23924     return arguments.length ? (handleSize = +_, brush) : handleSize;
23925   };
23926
23927   brush.on = function() {
23928     var value = listeners.on.apply(listeners, arguments);
23929     return value === listeners ? brush : value;
23930   };
23931
23932   return brush;
23933 }
23934
23935 var cos = Math.cos;
23936 var sin = Math.sin;
23937 var pi$1 = Math.PI;
23938 var halfPi$1 = pi$1 / 2;
23939 var tau$1 = pi$1 * 2;
23940 var max$1 = Math.max;
23941
23942 function compareValue(compare) {
23943   return function(a, b) {
23944     return compare(
23945       a.source.value + a.target.value,
23946       b.source.value + b.target.value
23947     );
23948   };
23949 }
23950
23951 var chord = function() {
23952   var padAngle = 0,
23953       sortGroups = null,
23954       sortSubgroups = null,
23955       sortChords = null;
23956
23957   function chord(matrix) {
23958     var n = matrix.length,
23959         groupSums = [],
23960         groupIndex = sequence(n),
23961         subgroupIndex = [],
23962         chords = [],
23963         groups = chords.groups = new Array(n),
23964         subgroups = new Array(n * n),
23965         k,
23966         x,
23967         x0,
23968         dx,
23969         i,
23970         j;
23971
23972     // Compute the sum.
23973     k = 0, i = -1; while (++i < n) {
23974       x = 0, j = -1; while (++j < n) {
23975         x += matrix[i][j];
23976       }
23977       groupSums.push(x);
23978       subgroupIndex.push(sequence(n));
23979       k += x;
23980     }
23981
23982     // Sort groups…
23983     if (sortGroups) groupIndex.sort(function(a, b) {
23984       return sortGroups(groupSums[a], groupSums[b]);
23985     });
23986
23987     // Sort subgroups…
23988     if (sortSubgroups) subgroupIndex.forEach(function(d, i) {
23989       d.sort(function(a, b) {
23990         return sortSubgroups(matrix[i][a], matrix[i][b]);
23991       });
23992     });
23993
23994     // Convert the sum to scaling factor for [0, 2pi].
23995     // TODO Allow start and end angle to be specified?
23996     // TODO Allow padding to be specified as percentage?
23997     k = max$1(0, tau$1 - padAngle * n) / k;
23998     dx = k ? padAngle : tau$1 / n;
23999
24000     // Compute the start and end angle for each group and subgroup.
24001     // Note: Opera has a bug reordering object literal properties!
24002     x = 0, i = -1; while (++i < n) {
24003       x0 = x, j = -1; while (++j < n) {
24004         var di = groupIndex[i],
24005             dj = subgroupIndex[di][j],
24006             v = matrix[di][dj],
24007             a0 = x,
24008             a1 = x += v * k;
24009         subgroups[dj * n + di] = {
24010           index: di,
24011           subindex: dj,
24012           startAngle: a0,
24013           endAngle: a1,
24014           value: v
24015         };
24016       }
24017       groups[di] = {
24018         index: di,
24019         startAngle: x0,
24020         endAngle: x,
24021         value: groupSums[di]
24022       };
24023       x += dx;
24024     }
24025
24026     // Generate chords for each (non-empty) subgroup-subgroup link.
24027     i = -1; while (++i < n) {
24028       j = i - 1; while (++j < n) {
24029         var source = subgroups[j * n + i],
24030             target = subgroups[i * n + j];
24031         if (source.value || target.value) {
24032           chords.push(source.value < target.value
24033               ? {source: target, target: source}
24034               : {source: source, target: target});
24035         }
24036       }
24037     }
24038
24039     return sortChords ? chords.sort(sortChords) : chords;
24040   }
24041
24042   chord.padAngle = function(_) {
24043     return arguments.length ? (padAngle = max$1(0, _), chord) : padAngle;
24044   };
24045
24046   chord.sortGroups = function(_) {
24047     return arguments.length ? (sortGroups = _, chord) : sortGroups;
24048   };
24049
24050   chord.sortSubgroups = function(_) {
24051     return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups;
24052   };
24053
24054   chord.sortChords = function(_) {
24055     return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._;
24056   };
24057
24058   return chord;
24059 };
24060
24061 var slice$2 = Array.prototype.slice;
24062
24063 var constant$5 = function(x) {
24064   return function() {
24065     return x;
24066   };
24067 };
24068
24069 var pi$2 = Math.PI;
24070 var tau$2 = 2 * pi$2;
24071 var epsilon$1 = 1e-6;
24072 var tauEpsilon = tau$2 - epsilon$1;
24073
24074 function Path() {
24075   this._x0 = this._y0 = // start of current subpath
24076   this._x1 = this._y1 = null; // end of current subpath
24077   this._ = "";
24078 }
24079
24080 function path() {
24081   return new Path;
24082 }
24083
24084 Path.prototype = path.prototype = {
24085   constructor: Path,
24086   moveTo: function(x, y) {
24087     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y);
24088   },
24089   closePath: function() {
24090     if (this._x1 !== null) {
24091       this._x1 = this._x0, this._y1 = this._y0;
24092       this._ += "Z";
24093     }
24094   },
24095   lineTo: function(x, y) {
24096     this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y);
24097   },
24098   quadraticCurveTo: function(x1, y1, x, y) {
24099     this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24100   },
24101   bezierCurveTo: function(x1, y1, x2, y2, x, y) {
24102     this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24103   },
24104   arcTo: function(x1, y1, x2, y2, r) {
24105     x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
24106     var x0 = this._x1,
24107         y0 = this._y1,
24108         x21 = x2 - x1,
24109         y21 = y2 - y1,
24110         x01 = x0 - x1,
24111         y01 = y0 - y1,
24112         l01_2 = x01 * x01 + y01 * y01;
24113
24114     // Is the radius negative? Error.
24115     if (r < 0) throw new Error("negative radius: " + r);
24116
24117     // Is this path empty? Move to (x1,y1).
24118     if (this._x1 === null) {
24119       this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1);
24120     }
24121
24122     // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
24123     else if (!(l01_2 > epsilon$1)) {}
24124
24125     // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
24126     // Equivalently, is (x1,y1) coincident with (x2,y2)?
24127     // Or, is the radius zero? Line to (x1,y1).
24128     else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$1) || !r) {
24129       this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1);
24130     }
24131
24132     // Otherwise, draw an arc!
24133     else {
24134       var x20 = x2 - x0,
24135           y20 = y2 - y0,
24136           l21_2 = x21 * x21 + y21 * y21,
24137           l20_2 = x20 * x20 + y20 * y20,
24138           l21 = Math.sqrt(l21_2),
24139           l01 = Math.sqrt(l01_2),
24140           l = r * Math.tan((pi$2 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),
24141           t01 = l / l01,
24142           t21 = l / l21;
24143
24144       // If the start tangent is not coincident with (x0,y0), line to.
24145       if (Math.abs(t01 - 1) > epsilon$1) {
24146         this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01);
24147       }
24148
24149       this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21);
24150     }
24151   },
24152   arc: function(x, y, r, a0, a1, ccw) {
24153     x = +x, y = +y, r = +r;
24154     var dx = r * Math.cos(a0),
24155         dy = r * Math.sin(a0),
24156         x0 = x + dx,
24157         y0 = y + dy,
24158         cw = 1 ^ ccw,
24159         da = ccw ? a0 - a1 : a1 - a0;
24160
24161     // Is the radius negative? Error.
24162     if (r < 0) throw new Error("negative radius: " + r);
24163
24164     // Is this path empty? Move to (x0,y0).
24165     if (this._x1 === null) {
24166       this._ += "M" + x0 + "," + y0;
24167     }
24168
24169     // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
24170     else if (Math.abs(this._x1 - x0) > epsilon$1 || Math.abs(this._y1 - y0) > epsilon$1) {
24171       this._ += "L" + x0 + "," + y0;
24172     }
24173
24174     // Is this arc empty? We’re done.
24175     if (!r) return;
24176
24177     // Does the angle go the wrong way? Flip the direction.
24178     if (da < 0) da = da % tau$2 + tau$2;
24179
24180     // Is this a complete circle? Draw two arcs to complete the circle.
24181     if (da > tauEpsilon) {
24182       this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0);
24183     }
24184
24185     // Is this arc non-empty? Draw an arc!
24186     else if (da > epsilon$1) {
24187       this._ += "A" + r + "," + r + ",0," + (+(da >= pi$2)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1));
24188     }
24189   },
24190   rect: function(x, y, w, h) {
24191     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z";
24192   },
24193   toString: function() {
24194     return this._;
24195   }
24196 };
24197
24198 function defaultSource(d) {
24199   return d.source;
24200 }
24201
24202 function defaultTarget(d) {
24203   return d.target;
24204 }
24205
24206 function defaultRadius(d) {
24207   return d.radius;
24208 }
24209
24210 function defaultStartAngle(d) {
24211   return d.startAngle;
24212 }
24213
24214 function defaultEndAngle(d) {
24215   return d.endAngle;
24216 }
24217
24218 var ribbon = function() {
24219   var source = defaultSource,
24220       target = defaultTarget,
24221       radius = defaultRadius,
24222       startAngle = defaultStartAngle,
24223       endAngle = defaultEndAngle,
24224       context = null;
24225
24226   function ribbon() {
24227     var buffer,
24228         argv = slice$2.call(arguments),
24229         s = source.apply(this, argv),
24230         t = target.apply(this, argv),
24231         sr = +radius.apply(this, (argv[0] = s, argv)),
24232         sa0 = startAngle.apply(this, argv) - halfPi$1,
24233         sa1 = endAngle.apply(this, argv) - halfPi$1,
24234         sx0 = sr * cos(sa0),
24235         sy0 = sr * sin(sa0),
24236         tr = +radius.apply(this, (argv[0] = t, argv)),
24237         ta0 = startAngle.apply(this, argv) - halfPi$1,
24238         ta1 = endAngle.apply(this, argv) - halfPi$1;
24239
24240     if (!context) context = buffer = path();
24241
24242     context.moveTo(sx0, sy0);
24243     context.arc(0, 0, sr, sa0, sa1);
24244     if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr?
24245       context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
24246       context.arc(0, 0, tr, ta0, ta1);
24247     }
24248     context.quadraticCurveTo(0, 0, sx0, sy0);
24249     context.closePath();
24250
24251     if (buffer) return context = null, buffer + "" || null;
24252   }
24253
24254   ribbon.radius = function(_) {
24255     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$5(+_), ribbon) : radius;
24256   };
24257
24258   ribbon.startAngle = function(_) {
24259     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : startAngle;
24260   };
24261
24262   ribbon.endAngle = function(_) {
24263     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : endAngle;
24264   };
24265
24266   ribbon.source = function(_) {
24267     return arguments.length ? (source = _, ribbon) : source;
24268   };
24269
24270   ribbon.target = function(_) {
24271     return arguments.length ? (target = _, ribbon) : target;
24272   };
24273
24274   ribbon.context = function(_) {
24275     return arguments.length ? ((context = _ == null ? null : _), ribbon) : context;
24276   };
24277
24278   return ribbon;
24279 };
24280
24281 var prefix = "$";
24282
24283 function Map() {}
24284
24285 Map.prototype = map$1.prototype = {
24286   constructor: Map,
24287   has: function(key) {
24288     return (prefix + key) in this;
24289   },
24290   get: function(key) {
24291     return this[prefix + key];
24292   },
24293   set: function(key, value) {
24294     this[prefix + key] = value;
24295     return this;
24296   },
24297   remove: function(key) {
24298     var property = prefix + key;
24299     return property in this && delete this[property];
24300   },
24301   clear: function() {
24302     for (var property in this) if (property[0] === prefix) delete this[property];
24303   },
24304   keys: function() {
24305     var keys = [];
24306     for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
24307     return keys;
24308   },
24309   values: function() {
24310     var values = [];
24311     for (var property in this) if (property[0] === prefix) values.push(this[property]);
24312     return values;
24313   },
24314   entries: function() {
24315     var entries = [];
24316     for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
24317     return entries;
24318   },
24319   size: function() {
24320     var size = 0;
24321     for (var property in this) if (property[0] === prefix) ++size;
24322     return size;
24323   },
24324   empty: function() {
24325     for (var property in this) if (property[0] === prefix) return false;
24326     return true;
24327   },
24328   each: function(f) {
24329     for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
24330   }
24331 };
24332
24333 function map$1(object, f) {
24334   var map = new Map;
24335
24336   // Copy constructor.
24337   if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
24338
24339   // Index array by numeric index or specified key function.
24340   else if (Array.isArray(object)) {
24341     var i = -1,
24342         n = object.length,
24343         o;
24344
24345     if (f == null) while (++i < n) map.set(i, object[i]);
24346     else while (++i < n) map.set(f(o = object[i], i, object), o);
24347   }
24348
24349   // Convert object to map.
24350   else if (object) for (var key in object) map.set(key, object[key]);
24351
24352   return map;
24353 }
24354
24355 var nest = function() {
24356   var keys = [],
24357       sortKeys = [],
24358       sortValues,
24359       rollup,
24360       nest;
24361
24362   function apply(array, depth, createResult, setResult) {
24363     if (depth >= keys.length) {
24364       if (sortValues != null) array.sort(sortValues);
24365       return rollup != null ? rollup(array) : array;
24366     }
24367
24368     var i = -1,
24369         n = array.length,
24370         key = keys[depth++],
24371         keyValue,
24372         value,
24373         valuesByKey = map$1(),
24374         values,
24375         result = createResult();
24376
24377     while (++i < n) {
24378       if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
24379         values.push(value);
24380       } else {
24381         valuesByKey.set(keyValue, [value]);
24382       }
24383     }
24384
24385     valuesByKey.each(function(values, key) {
24386       setResult(result, key, apply(values, depth, createResult, setResult));
24387     });
24388
24389     return result;
24390   }
24391
24392   function entries(map, depth) {
24393     if (++depth > keys.length) return map;
24394     var array, sortKey = sortKeys[depth - 1];
24395     if (rollup != null && depth >= keys.length) array = map.entries();
24396     else array = [], map.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
24397     return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
24398   }
24399
24400   return nest = {
24401     object: function(array) { return apply(array, 0, createObject, setObject); },
24402     map: function(array) { return apply(array, 0, createMap, setMap); },
24403     entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
24404     key: function(d) { keys.push(d); return nest; },
24405     sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
24406     sortValues: function(order) { sortValues = order; return nest; },
24407     rollup: function(f) { rollup = f; return nest; }
24408   };
24409 };
24410
24411 function createObject() {
24412   return {};
24413 }
24414
24415 function setObject(object, key, value) {
24416   object[key] = value;
24417 }
24418
24419 function createMap() {
24420   return map$1();
24421 }
24422
24423 function setMap(map, key, value) {
24424   map.set(key, value);
24425 }
24426
24427 function Set() {}
24428
24429 var proto = map$1.prototype;
24430
24431 Set.prototype = set$2.prototype = {
24432   constructor: Set,
24433   has: proto.has,
24434   add: function(value) {
24435     value += "";
24436     this[prefix + value] = value;
24437     return this;
24438   },
24439   remove: proto.remove,
24440   clear: proto.clear,
24441   values: proto.keys,
24442   size: proto.size,
24443   empty: proto.empty,
24444   each: proto.each
24445 };
24446
24447 function set$2(object, f) {
24448   var set = new Set;
24449
24450   // Copy constructor.
24451   if (object instanceof Set) object.each(function(value) { set.add(value); });
24452
24453   // Otherwise, assume it’s an array.
24454   else if (object) {
24455     var i = -1, n = object.length;
24456     if (f == null) while (++i < n) set.add(object[i]);
24457     else while (++i < n) set.add(f(object[i], i, object));
24458   }
24459
24460   return set;
24461 }
24462
24463 var keys = function(map) {
24464   var keys = [];
24465   for (var key in map) keys.push(key);
24466   return keys;
24467 };
24468
24469 var values = function(map) {
24470   var values = [];
24471   for (var key in map) values.push(map[key]);
24472   return values;
24473 };
24474
24475 var entries = function(map) {
24476   var entries = [];
24477   for (var key in map) entries.push({key: key, value: map[key]});
24478   return entries;
24479 };
24480
24481 function objectConverter(columns) {
24482   return new Function("d", "return {" + columns.map(function(name, i) {
24483     return JSON.stringify(name) + ": d[" + i + "]";
24484   }).join(",") + "}");
24485 }
24486
24487 function customConverter(columns, f) {
24488   var object = objectConverter(columns);
24489   return function(row, i) {
24490     return f(object(row), i, columns);
24491   };
24492 }
24493
24494 // Compute unique columns in order of discovery.
24495 function inferColumns(rows) {
24496   var columnSet = Object.create(null),
24497       columns = [];
24498
24499   rows.forEach(function(row) {
24500     for (var column in row) {
24501       if (!(column in columnSet)) {
24502         columns.push(columnSet[column] = column);
24503       }
24504     }
24505   });
24506
24507   return columns;
24508 }
24509
24510 var dsv = function(delimiter) {
24511   var reFormat = new RegExp("[\"" + delimiter + "\n\r]"),
24512       delimiterCode = delimiter.charCodeAt(0);
24513
24514   function parse(text, f) {
24515     var convert, columns, rows = parseRows(text, function(row, i) {
24516       if (convert) return convert(row, i - 1);
24517       columns = row, convert = f ? customConverter(row, f) : objectConverter(row);
24518     });
24519     rows.columns = columns;
24520     return rows;
24521   }
24522
24523   function parseRows(text, f) {
24524     var EOL = {}, // sentinel value for end-of-line
24525         EOF = {}, // sentinel value for end-of-file
24526         rows = [], // output rows
24527         N = text.length,
24528         I = 0, // current character index
24529         n = 0, // the current line number
24530         t, // the current token
24531         eol; // is the current token followed by EOL?
24532
24533     function token() {
24534       if (I >= N) return EOF; // special case: end of file
24535       if (eol) return eol = false, EOL; // special case: end of line
24536
24537       // special case: quotes
24538       var j = I, c;
24539       if (text.charCodeAt(j) === 34) {
24540         var i = j;
24541         while (i++ < N) {
24542           if (text.charCodeAt(i) === 34) {
24543             if (text.charCodeAt(i + 1) !== 34) break;
24544             ++i;
24545           }
24546         }
24547         I = i + 2;
24548         c = text.charCodeAt(i + 1);
24549         if (c === 13) {
24550           eol = true;
24551           if (text.charCodeAt(i + 2) === 10) ++I;
24552         } else if (c === 10) {
24553           eol = true;
24554         }
24555         return text.slice(j + 1, i).replace(/""/g, "\"");
24556       }
24557
24558       // common case: find next delimiter or newline
24559       while (I < N) {
24560         var k = 1;
24561         c = text.charCodeAt(I++);
24562         if (c === 10) eol = true; // \n
24563         else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \r|\r\n
24564         else if (c !== delimiterCode) continue;
24565         return text.slice(j, I - k);
24566       }
24567
24568       // special case: last token before EOF
24569       return text.slice(j);
24570     }
24571
24572     while ((t = token()) !== EOF) {
24573       var a = [];
24574       while (t !== EOL && t !== EOF) {
24575         a.push(t);
24576         t = token();
24577       }
24578       if (f && (a = f(a, n++)) == null) continue;
24579       rows.push(a);
24580     }
24581
24582     return rows;
24583   }
24584
24585   function format(rows, columns) {
24586     if (columns == null) columns = inferColumns(rows);
24587     return [columns.map(formatValue).join(delimiter)].concat(rows.map(function(row) {
24588       return columns.map(function(column) {
24589         return formatValue(row[column]);
24590       }).join(delimiter);
24591     })).join("\n");
24592   }
24593
24594   function formatRows(rows) {
24595     return rows.map(formatRow).join("\n");
24596   }
24597
24598   function formatRow(row) {
24599     return row.map(formatValue).join(delimiter);
24600   }
24601
24602   function formatValue(text) {
24603     return text == null ? ""
24604         : reFormat.test(text += "") ? "\"" + text.replace(/\"/g, "\"\"") + "\""
24605         : text;
24606   }
24607
24608   return {
24609     parse: parse,
24610     parseRows: parseRows,
24611     format: format,
24612     formatRows: formatRows
24613   };
24614 };
24615
24616 var csv = dsv(",");
24617
24618 var csvParse = csv.parse;
24619 var csvParseRows = csv.parseRows;
24620 var csvFormat = csv.format;
24621 var csvFormatRows = csv.formatRows;
24622
24623 var tsv = dsv("\t");
24624
24625 var tsvParse = tsv.parse;
24626 var tsvParseRows = tsv.parseRows;
24627 var tsvFormat = tsv.format;
24628 var tsvFormatRows = tsv.formatRows;
24629
24630 var center$1 = function(x, y) {
24631   var nodes;
24632
24633   if (x == null) x = 0;
24634   if (y == null) y = 0;
24635
24636   function force() {
24637     var i,
24638         n = nodes.length,
24639         node,
24640         sx = 0,
24641         sy = 0;
24642
24643     for (i = 0; i < n; ++i) {
24644       node = nodes[i], sx += node.x, sy += node.y;
24645     }
24646
24647     for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
24648       node = nodes[i], node.x -= sx, node.y -= sy;
24649     }
24650   }
24651
24652   force.initialize = function(_) {
24653     nodes = _;
24654   };
24655
24656   force.x = function(_) {
24657     return arguments.length ? (x = +_, force) : x;
24658   };
24659
24660   force.y = function(_) {
24661     return arguments.length ? (y = +_, force) : y;
24662   };
24663
24664   return force;
24665 };
24666
24667 var constant$6 = function(x) {
24668   return function() {
24669     return x;
24670   };
24671 };
24672
24673 var jiggle = function() {
24674   return (Math.random() - 0.5) * 1e-6;
24675 };
24676
24677 var tree_add = function(d) {
24678   var x = +this._x.call(null, d),
24679       y = +this._y.call(null, d);
24680   return add(this.cover(x, y), x, y, d);
24681 };
24682
24683 function add(tree, x, y, d) {
24684   if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
24685
24686   var parent,
24687       node = tree._root,
24688       leaf = {data: d},
24689       x0 = tree._x0,
24690       y0 = tree._y0,
24691       x1 = tree._x1,
24692       y1 = tree._y1,
24693       xm,
24694       ym,
24695       xp,
24696       yp,
24697       right,
24698       bottom,
24699       i,
24700       j;
24701
24702   // If the tree is empty, initialize the root as a leaf.
24703   if (!node) return tree._root = leaf, tree;
24704
24705   // Find the existing leaf for the new point, or add it.
24706   while (node.length) {
24707     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24708     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24709     if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
24710   }
24711
24712   // Is the new point is exactly coincident with the existing point?
24713   xp = +tree._x.call(null, node.data);
24714   yp = +tree._y.call(null, node.data);
24715   if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
24716
24717   // Otherwise, split the leaf node until the old and new point are separated.
24718   do {
24719     parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
24720     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24721     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24722   } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
24723   return parent[j] = node, parent[i] = leaf, tree;
24724 }
24725
24726 function addAll(data) {
24727   var d, i, n = data.length,
24728       x,
24729       y,
24730       xz = new Array(n),
24731       yz = new Array(n),
24732       x0 = Infinity,
24733       y0 = Infinity,
24734       x1 = -Infinity,
24735       y1 = -Infinity;
24736
24737   // Compute the points and their extent.
24738   for (i = 0; i < n; ++i) {
24739     if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
24740     xz[i] = x;
24741     yz[i] = y;
24742     if (x < x0) x0 = x;
24743     if (x > x1) x1 = x;
24744     if (y < y0) y0 = y;
24745     if (y > y1) y1 = y;
24746   }
24747
24748   // If there were no (valid) points, inherit the existing extent.
24749   if (x1 < x0) x0 = this._x0, x1 = this._x1;
24750   if (y1 < y0) y0 = this._y0, y1 = this._y1;
24751
24752   // Expand the tree to cover the new points.
24753   this.cover(x0, y0).cover(x1, y1);
24754
24755   // Add the new points.
24756   for (i = 0; i < n; ++i) {
24757     add(this, xz[i], yz[i], data[i]);
24758   }
24759
24760   return this;
24761 }
24762
24763 var tree_cover = function(x, y) {
24764   if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points
24765
24766   var x0 = this._x0,
24767       y0 = this._y0,
24768       x1 = this._x1,
24769       y1 = this._y1;
24770
24771   // If the quadtree has no extent, initialize them.
24772   // Integer extent are necessary so that if we later double the extent,
24773   // the existing quadrant boundaries don’t change due to floating point error!
24774   if (isNaN(x0)) {
24775     x1 = (x0 = Math.floor(x)) + 1;
24776     y1 = (y0 = Math.floor(y)) + 1;
24777   }
24778
24779   // Otherwise, double repeatedly to cover.
24780   else if (x0 > x || x > x1 || y0 > y || y > y1) {
24781     var z = x1 - x0,
24782         node = this._root,
24783         parent,
24784         i;
24785
24786     switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
24787       case 0: {
24788         do parent = new Array(4), parent[i] = node, node = parent;
24789         while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1);
24790         break;
24791       }
24792       case 1: {
24793         do parent = new Array(4), parent[i] = node, node = parent;
24794         while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1);
24795         break;
24796       }
24797       case 2: {
24798         do parent = new Array(4), parent[i] = node, node = parent;
24799         while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y);
24800         break;
24801       }
24802       case 3: {
24803         do parent = new Array(4), parent[i] = node, node = parent;
24804         while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y);
24805         break;
24806       }
24807     }
24808
24809     if (this._root && this._root.length) this._root = node;
24810   }
24811
24812   // If the quadtree covers the point already, just return.
24813   else return this;
24814
24815   this._x0 = x0;
24816   this._y0 = y0;
24817   this._x1 = x1;
24818   this._y1 = y1;
24819   return this;
24820 };
24821
24822 var tree_data = function() {
24823   var data = [];
24824   this.visit(function(node) {
24825     if (!node.length) do data.push(node.data); while (node = node.next)
24826   });
24827   return data;
24828 };
24829
24830 var tree_extent = function(_) {
24831   return arguments.length
24832       ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1])
24833       : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]];
24834 };
24835
24836 var Quad = function(node, x0, y0, x1, y1) {
24837   this.node = node;
24838   this.x0 = x0;
24839   this.y0 = y0;
24840   this.x1 = x1;
24841   this.y1 = y1;
24842 };
24843
24844 var tree_find = function(x, y, radius) {
24845   var data,
24846       x0 = this._x0,
24847       y0 = this._y0,
24848       x1,
24849       y1,
24850       x2,
24851       y2,
24852       x3 = this._x1,
24853       y3 = this._y1,
24854       quads = [],
24855       node = this._root,
24856       q,
24857       i;
24858
24859   if (node) quads.push(new Quad(node, x0, y0, x3, y3));
24860   if (radius == null) radius = Infinity;
24861   else {
24862     x0 = x - radius, y0 = y - radius;
24863     x3 = x + radius, y3 = y + radius;
24864     radius *= radius;
24865   }
24866
24867   while (q = quads.pop()) {
24868
24869     // Stop searching if this quadrant can’t contain a closer node.
24870     if (!(node = q.node)
24871         || (x1 = q.x0) > x3
24872         || (y1 = q.y0) > y3
24873         || (x2 = q.x1) < x0
24874         || (y2 = q.y1) < y0) continue;
24875
24876     // Bisect the current quadrant.
24877     if (node.length) {
24878       var xm = (x1 + x2) / 2,
24879           ym = (y1 + y2) / 2;
24880
24881       quads.push(
24882         new Quad(node[3], xm, ym, x2, y2),
24883         new Quad(node[2], x1, ym, xm, y2),
24884         new Quad(node[1], xm, y1, x2, ym),
24885         new Quad(node[0], x1, y1, xm, ym)
24886       );
24887
24888       // Visit the closest quadrant first.
24889       if (i = (y >= ym) << 1 | (x >= xm)) {
24890         q = quads[quads.length - 1];
24891         quads[quads.length - 1] = quads[quads.length - 1 - i];
24892         quads[quads.length - 1 - i] = q;
24893       }
24894     }
24895
24896     // Visit this point. (Visiting coincident points isn’t necessary!)
24897     else {
24898       var dx = x - +this._x.call(null, node.data),
24899           dy = y - +this._y.call(null, node.data),
24900           d2 = dx * dx + dy * dy;
24901       if (d2 < radius) {
24902         var d = Math.sqrt(radius = d2);
24903         x0 = x - d, y0 = y - d;
24904         x3 = x + d, y3 = y + d;
24905         data = node.data;
24906       }
24907     }
24908   }
24909
24910   return data;
24911 };
24912
24913 var tree_remove = function(d) {
24914   if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
24915
24916   var parent,
24917       node = this._root,
24918       retainer,
24919       previous,
24920       next,
24921       x0 = this._x0,
24922       y0 = this._y0,
24923       x1 = this._x1,
24924       y1 = this._y1,
24925       x,
24926       y,
24927       xm,
24928       ym,
24929       right,
24930       bottom,
24931       i,
24932       j;
24933
24934   // If the tree is empty, initialize the root as a leaf.
24935   if (!node) return this;
24936
24937   // Find the leaf node for the point.
24938   // While descending, also retain the deepest parent with a non-removed sibling.
24939   if (node.length) while (true) {
24940     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24941     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24942     if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
24943     if (!node.length) break;
24944     if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
24945   }
24946
24947   // Find the point to remove.
24948   while (node.data !== d) if (!(previous = node, node = node.next)) return this;
24949   if (next = node.next) delete node.next;
24950
24951   // If there are multiple coincident points, remove just the point.
24952   if (previous) return (next ? previous.next = next : delete previous.next), this;
24953
24954   // If this is the root point, remove it.
24955   if (!parent) return this._root = next, this;
24956
24957   // Remove this leaf.
24958   next ? parent[i] = next : delete parent[i];
24959
24960   // If the parent now contains exactly one leaf, collapse superfluous parents.
24961   if ((node = parent[0] || parent[1] || parent[2] || parent[3])
24962       && node === (parent[3] || parent[2] || parent[1] || parent[0])
24963       && !node.length) {
24964     if (retainer) retainer[j] = node;
24965     else this._root = node;
24966   }
24967
24968   return this;
24969 };
24970
24971 function removeAll(data) {
24972   for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
24973   return this;
24974 }
24975
24976 var tree_root = function() {
24977   return this._root;
24978 };
24979
24980 var tree_size = function() {
24981   var size = 0;
24982   this.visit(function(node) {
24983     if (!node.length) do ++size; while (node = node.next)
24984   });
24985   return size;
24986 };
24987
24988 var tree_visit = function(callback) {
24989   var quads = [], q, node = this._root, child, x0, y0, x1, y1;
24990   if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1));
24991   while (q = quads.pop()) {
24992     if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
24993       var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
24994       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
24995       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
24996       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
24997       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
24998     }
24999   }
25000   return this;
25001 };
25002
25003 var tree_visitAfter = function(callback) {
25004   var quads = [], next = [], q;
25005   if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1));
25006   while (q = quads.pop()) {
25007     var node = q.node;
25008     if (node.length) {
25009       var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
25010       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
25011       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
25012       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
25013       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
25014     }
25015     next.push(q);
25016   }
25017   while (q = next.pop()) {
25018     callback(q.node, q.x0, q.y0, q.x1, q.y1);
25019   }
25020   return this;
25021 };
25022
25023 function defaultX(d) {
25024   return d[0];
25025 }
25026
25027 var tree_x = function(_) {
25028   return arguments.length ? (this._x = _, this) : this._x;
25029 };
25030
25031 function defaultY(d) {
25032   return d[1];
25033 }
25034
25035 var tree_y = function(_) {
25036   return arguments.length ? (this._y = _, this) : this._y;
25037 };
25038
25039 function quadtree(nodes, x, y) {
25040   var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
25041   return nodes == null ? tree : tree.addAll(nodes);
25042 }
25043
25044 function Quadtree(x, y, x0, y0, x1, y1) {
25045   this._x = x;
25046   this._y = y;
25047   this._x0 = x0;
25048   this._y0 = y0;
25049   this._x1 = x1;
25050   this._y1 = y1;
25051   this._root = undefined;
25052 }
25053
25054 function leaf_copy(leaf) {
25055   var copy = {data: leaf.data}, next = copy;
25056   while (leaf = leaf.next) next = next.next = {data: leaf.data};
25057   return copy;
25058 }
25059
25060 var treeProto = quadtree.prototype = Quadtree.prototype;
25061
25062 treeProto.copy = function() {
25063   var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1),
25064       node = this._root,
25065       nodes,
25066       child;
25067
25068   if (!node) return copy;
25069
25070   if (!node.length) return copy._root = leaf_copy(node), copy;
25071
25072   nodes = [{source: node, target: copy._root = new Array(4)}];
25073   while (node = nodes.pop()) {
25074     for (var i = 0; i < 4; ++i) {
25075       if (child = node.source[i]) {
25076         if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)});
25077         else node.target[i] = leaf_copy(child);
25078       }
25079     }
25080   }
25081
25082   return copy;
25083 };
25084
25085 treeProto.add = tree_add;
25086 treeProto.addAll = addAll;
25087 treeProto.cover = tree_cover;
25088 treeProto.data = tree_data;
25089 treeProto.extent = tree_extent;
25090 treeProto.find = tree_find;
25091 treeProto.remove = tree_remove;
25092 treeProto.removeAll = removeAll;
25093 treeProto.root = tree_root;
25094 treeProto.size = tree_size;
25095 treeProto.visit = tree_visit;
25096 treeProto.visitAfter = tree_visitAfter;
25097 treeProto.x = tree_x;
25098 treeProto.y = tree_y;
25099
25100 function x(d) {
25101   return d.x + d.vx;
25102 }
25103
25104 function y(d) {
25105   return d.y + d.vy;
25106 }
25107
25108 var collide = function(radius) {
25109   var nodes,
25110       radii,
25111       strength = 1,
25112       iterations = 1;
25113
25114   if (typeof radius !== "function") radius = constant$6(radius == null ? 1 : +radius);
25115
25116   function force() {
25117     var i, n = nodes.length,
25118         tree,
25119         node,
25120         xi,
25121         yi,
25122         ri,
25123         ri2;
25124
25125     for (var k = 0; k < iterations; ++k) {
25126       tree = quadtree(nodes, x, y).visitAfter(prepare);
25127       for (i = 0; i < n; ++i) {
25128         node = nodes[i];
25129         ri = radii[node.index], ri2 = ri * ri;
25130         xi = node.x + node.vx;
25131         yi = node.y + node.vy;
25132         tree.visit(apply);
25133       }
25134     }
25135
25136     function apply(quad, x0, y0, x1, y1) {
25137       var data = quad.data, rj = quad.r, r = ri + rj;
25138       if (data) {
25139         if (data.index > node.index) {
25140           var x = xi - data.x - data.vx,
25141               y = yi - data.y - data.vy,
25142               l = x * x + y * y;
25143           if (l < r * r) {
25144             if (x === 0) x = jiggle(), l += x * x;
25145             if (y === 0) y = jiggle(), l += y * y;
25146             l = (r - (l = Math.sqrt(l))) / l * strength;
25147             node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
25148             node.vy += (y *= l) * r;
25149             data.vx -= x * (r = 1 - r);
25150             data.vy -= y * r;
25151           }
25152         }
25153         return;
25154       }
25155       return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
25156     }
25157   }
25158
25159   function prepare(quad) {
25160     if (quad.data) return quad.r = radii[quad.data.index];
25161     for (var i = quad.r = 0; i < 4; ++i) {
25162       if (quad[i] && quad[i].r > quad.r) {
25163         quad.r = quad[i].r;
25164       }
25165     }
25166   }
25167
25168   function initialize() {
25169     if (!nodes) return;
25170     var i, n = nodes.length, node;
25171     radii = new Array(n);
25172     for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
25173   }
25174
25175   force.initialize = function(_) {
25176     nodes = _;
25177     initialize();
25178   };
25179
25180   force.iterations = function(_) {
25181     return arguments.length ? (iterations = +_, force) : iterations;
25182   };
25183
25184   force.strength = function(_) {
25185     return arguments.length ? (strength = +_, force) : strength;
25186   };
25187
25188   force.radius = function(_) {
25189     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : radius;
25190   };
25191
25192   return force;
25193 };
25194
25195 function index$3(d) {
25196   return d.index;
25197 }
25198
25199 function find(nodeById, nodeId) {
25200   var node = nodeById.get(nodeId);
25201   if (!node) throw new Error("missing: " + nodeId);
25202   return node;
25203 }
25204
25205 var link = function(links) {
25206   var id = index$3,
25207       strength = defaultStrength,
25208       strengths,
25209       distance = constant$6(30),
25210       distances,
25211       nodes,
25212       count,
25213       bias,
25214       iterations = 1;
25215
25216   if (links == null) links = [];
25217
25218   function defaultStrength(link) {
25219     return 1 / Math.min(count[link.source.index], count[link.target.index]);
25220   }
25221
25222   function force(alpha) {
25223     for (var k = 0, n = links.length; k < iterations; ++k) {
25224       for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
25225         link = links[i], source = link.source, target = link.target;
25226         x = target.x + target.vx - source.x - source.vx || jiggle();
25227         y = target.y + target.vy - source.y - source.vy || jiggle();
25228         l = Math.sqrt(x * x + y * y);
25229         l = (l - distances[i]) / l * alpha * strengths[i];
25230         x *= l, y *= l;
25231         target.vx -= x * (b = bias[i]);
25232         target.vy -= y * b;
25233         source.vx += x * (b = 1 - b);
25234         source.vy += y * b;
25235       }
25236     }
25237   }
25238
25239   function initialize() {
25240     if (!nodes) return;
25241
25242     var i,
25243         n = nodes.length,
25244         m = links.length,
25245         nodeById = map$1(nodes, id),
25246         link;
25247
25248     for (i = 0, count = new Array(n); i < m; ++i) {
25249       link = links[i], link.index = i;
25250       if (typeof link.source !== "object") link.source = find(nodeById, link.source);
25251       if (typeof link.target !== "object") link.target = find(nodeById, link.target);
25252       count[link.source.index] = (count[link.source.index] || 0) + 1;
25253       count[link.target.index] = (count[link.target.index] || 0) + 1;
25254     }
25255
25256     for (i = 0, bias = new Array(m); i < m; ++i) {
25257       link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
25258     }
25259
25260     strengths = new Array(m), initializeStrength();
25261     distances = new Array(m), initializeDistance();
25262   }
25263
25264   function initializeStrength() {
25265     if (!nodes) return;
25266
25267     for (var i = 0, n = links.length; i < n; ++i) {
25268       strengths[i] = +strength(links[i], i, links);
25269     }
25270   }
25271
25272   function initializeDistance() {
25273     if (!nodes) return;
25274
25275     for (var i = 0, n = links.length; i < n; ++i) {
25276       distances[i] = +distance(links[i], i, links);
25277     }
25278   }
25279
25280   force.initialize = function(_) {
25281     nodes = _;
25282     initialize();
25283   };
25284
25285   force.links = function(_) {
25286     return arguments.length ? (links = _, initialize(), force) : links;
25287   };
25288
25289   force.id = function(_) {
25290     return arguments.length ? (id = _, force) : id;
25291   };
25292
25293   force.iterations = function(_) {
25294     return arguments.length ? (iterations = +_, force) : iterations;
25295   };
25296
25297   force.strength = function(_) {
25298     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initializeStrength(), force) : strength;
25299   };
25300
25301   force.distance = function(_) {
25302     return arguments.length ? (distance = typeof _ === "function" ? _ : constant$6(+_), initializeDistance(), force) : distance;
25303   };
25304
25305   return force;
25306 };
25307
25308 function x$1(d) {
25309   return d.x;
25310 }
25311
25312 function y$1(d) {
25313   return d.y;
25314 }
25315
25316 var initialRadius = 10;
25317 var initialAngle = Math.PI * (3 - Math.sqrt(5));
25318
25319 var simulation = function(nodes) {
25320   var simulation,
25321       alpha = 1,
25322       alphaMin = 0.001,
25323       alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
25324       alphaTarget = 0,
25325       velocityDecay = 0.6,
25326       forces = map$1(),
25327       stepper = timer(step),
25328       event = dispatch("tick", "end");
25329
25330   if (nodes == null) nodes = [];
25331
25332   function step() {
25333     tick();
25334     event.call("tick", simulation);
25335     if (alpha < alphaMin) {
25336       stepper.stop();
25337       event.call("end", simulation);
25338     }
25339   }
25340
25341   function tick() {
25342     var i, n = nodes.length, node;
25343
25344     alpha += (alphaTarget - alpha) * alphaDecay;
25345
25346     forces.each(function(force) {
25347       force(alpha);
25348     });
25349
25350     for (i = 0; i < n; ++i) {
25351       node = nodes[i];
25352       if (node.fx == null) node.x += node.vx *= velocityDecay;
25353       else node.x = node.fx, node.vx = 0;
25354       if (node.fy == null) node.y += node.vy *= velocityDecay;
25355       else node.y = node.fy, node.vy = 0;
25356     }
25357   }
25358
25359   function initializeNodes() {
25360     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25361       node = nodes[i], node.index = i;
25362       if (isNaN(node.x) || isNaN(node.y)) {
25363         var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
25364         node.x = radius * Math.cos(angle);
25365         node.y = radius * Math.sin(angle);
25366       }
25367       if (isNaN(node.vx) || isNaN(node.vy)) {
25368         node.vx = node.vy = 0;
25369       }
25370     }
25371   }
25372
25373   function initializeForce(force) {
25374     if (force.initialize) force.initialize(nodes);
25375     return force;
25376   }
25377
25378   initializeNodes();
25379
25380   return simulation = {
25381     tick: tick,
25382
25383     restart: function() {
25384       return stepper.restart(step), simulation;
25385     },
25386
25387     stop: function() {
25388       return stepper.stop(), simulation;
25389     },
25390
25391     nodes: function(_) {
25392       return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes;
25393     },
25394
25395     alpha: function(_) {
25396       return arguments.length ? (alpha = +_, simulation) : alpha;
25397     },
25398
25399     alphaMin: function(_) {
25400       return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
25401     },
25402
25403     alphaDecay: function(_) {
25404       return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
25405     },
25406
25407     alphaTarget: function(_) {
25408       return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
25409     },
25410
25411     velocityDecay: function(_) {
25412       return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
25413     },
25414
25415     force: function(name, _) {
25416       return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
25417     },
25418
25419     find: function(x, y, radius) {
25420       var i = 0,
25421           n = nodes.length,
25422           dx,
25423           dy,
25424           d2,
25425           node,
25426           closest;
25427
25428       if (radius == null) radius = Infinity;
25429       else radius *= radius;
25430
25431       for (i = 0; i < n; ++i) {
25432         node = nodes[i];
25433         dx = x - node.x;
25434         dy = y - node.y;
25435         d2 = dx * dx + dy * dy;
25436         if (d2 < radius) closest = node, radius = d2;
25437       }
25438
25439       return closest;
25440     },
25441
25442     on: function(name, _) {
25443       return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
25444     }
25445   };
25446 };
25447
25448 var manyBody = function() {
25449   var nodes,
25450       node,
25451       alpha,
25452       strength = constant$6(-30),
25453       strengths,
25454       distanceMin2 = 1,
25455       distanceMax2 = Infinity,
25456       theta2 = 0.81;
25457
25458   function force(_) {
25459     var i, n = nodes.length, tree = quadtree(nodes, x$1, y$1).visitAfter(accumulate);
25460     for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
25461   }
25462
25463   function initialize() {
25464     if (!nodes) return;
25465     var i, n = nodes.length, node;
25466     strengths = new Array(n);
25467     for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
25468   }
25469
25470   function accumulate(quad) {
25471     var strength = 0, q, c, x, y, i;
25472
25473     // For internal nodes, accumulate forces from child quadrants.
25474     if (quad.length) {
25475       for (x = y = i = 0; i < 4; ++i) {
25476         if ((q = quad[i]) && (c = q.value)) {
25477           strength += c, x += c * q.x, y += c * q.y;
25478         }
25479       }
25480       quad.x = x / strength;
25481       quad.y = y / strength;
25482     }
25483
25484     // For leaf nodes, accumulate forces from coincident quadrants.
25485     else {
25486       q = quad;
25487       q.x = q.data.x;
25488       q.y = q.data.y;
25489       do strength += strengths[q.data.index];
25490       while (q = q.next);
25491     }
25492
25493     quad.value = strength;
25494   }
25495
25496   function apply(quad, x1, _, x2) {
25497     if (!quad.value) return true;
25498
25499     var x = quad.x - node.x,
25500         y = quad.y - node.y,
25501         w = x2 - x1,
25502         l = x * x + y * y;
25503
25504     // Apply the Barnes-Hut approximation if possible.
25505     // Limit forces for very close nodes; randomize direction if coincident.
25506     if (w * w / theta2 < l) {
25507       if (l < distanceMax2) {
25508         if (x === 0) x = jiggle(), l += x * x;
25509         if (y === 0) y = jiggle(), l += y * y;
25510         if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25511         node.vx += x * quad.value * alpha / l;
25512         node.vy += y * quad.value * alpha / l;
25513       }
25514       return true;
25515     }
25516
25517     // Otherwise, process points directly.
25518     else if (quad.length || l >= distanceMax2) return;
25519
25520     // Limit forces for very close nodes; randomize direction if coincident.
25521     if (quad.data !== node || quad.next) {
25522       if (x === 0) x = jiggle(), l += x * x;
25523       if (y === 0) y = jiggle(), l += y * y;
25524       if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25525     }
25526
25527     do if (quad.data !== node) {
25528       w = strengths[quad.data.index] * alpha / l;
25529       node.vx += x * w;
25530       node.vy += y * w;
25531     } while (quad = quad.next);
25532   }
25533
25534   force.initialize = function(_) {
25535     nodes = _;
25536     initialize();
25537   };
25538
25539   force.strength = function(_) {
25540     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25541   };
25542
25543   force.distanceMin = function(_) {
25544     return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
25545   };
25546
25547   force.distanceMax = function(_) {
25548     return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
25549   };
25550
25551   force.theta = function(_) {
25552     return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
25553   };
25554
25555   return force;
25556 };
25557
25558 var x$2 = function(x) {
25559   var strength = constant$6(0.1),
25560       nodes,
25561       strengths,
25562       xz;
25563
25564   if (typeof x !== "function") x = constant$6(x == null ? 0 : +x);
25565
25566   function force(alpha) {
25567     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25568       node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
25569     }
25570   }
25571
25572   function initialize() {
25573     if (!nodes) return;
25574     var i, n = nodes.length;
25575     strengths = new Array(n);
25576     xz = new Array(n);
25577     for (i = 0; i < n; ++i) {
25578       strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25579     }
25580   }
25581
25582   force.initialize = function(_) {
25583     nodes = _;
25584     initialize();
25585   };
25586
25587   force.strength = function(_) {
25588     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25589   };
25590
25591   force.x = function(_) {
25592     return arguments.length ? (x = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : x;
25593   };
25594
25595   return force;
25596 };
25597
25598 var y$2 = function(y) {
25599   var strength = constant$6(0.1),
25600       nodes,
25601       strengths,
25602       yz;
25603
25604   if (typeof y !== "function") y = constant$6(y == null ? 0 : +y);
25605
25606   function force(alpha) {
25607     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25608       node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
25609     }
25610   }
25611
25612   function initialize() {
25613     if (!nodes) return;
25614     var i, n = nodes.length;
25615     strengths = new Array(n);
25616     yz = new Array(n);
25617     for (i = 0; i < n; ++i) {
25618       strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25619     }
25620   }
25621
25622   force.initialize = function(_) {
25623     nodes = _;
25624     initialize();
25625   };
25626
25627   force.strength = function(_) {
25628     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25629   };
25630
25631   force.y = function(_) {
25632     return arguments.length ? (y = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : y;
25633   };
25634
25635   return force;
25636 };
25637
25638 // Computes the decimal coefficient and exponent of the specified number x with
25639 // significant digits p, where x is positive and p is in [1, 21] or undefined.
25640 // For example, formatDecimal(1.23) returns ["123", 0].
25641 var formatDecimal = function(x, p) {
25642   if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
25643   var i, coefficient = x.slice(0, i);
25644
25645   // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
25646   // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
25647   return [
25648     coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
25649     +x.slice(i + 1)
25650   ];
25651 };
25652
25653 var exponent$1 = function(x) {
25654   return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
25655 };
25656
25657 var formatGroup = function(grouping, thousands) {
25658   return function(value, width) {
25659     var i = value.length,
25660         t = [],
25661         j = 0,
25662         g = grouping[0],
25663         length = 0;
25664
25665     while (i > 0 && g > 0) {
25666       if (length + g + 1 > width) g = Math.max(1, width - length);
25667       t.push(value.substring(i -= g, i + g));
25668       if ((length += g + 1) > width) break;
25669       g = grouping[j = (j + 1) % grouping.length];
25670     }
25671
25672     return t.reverse().join(thousands);
25673   };
25674 };
25675
25676 var formatNumerals = function(numerals) {
25677   return function(value) {
25678     return value.replace(/[0-9]/g, function(i) {
25679       return numerals[+i];
25680     });
25681   };
25682 };
25683
25684 var formatDefault = function(x, p) {
25685   x = x.toPrecision(p);
25686
25687   out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
25688     switch (x[i]) {
25689       case ".": i0 = i1 = i; break;
25690       case "0": if (i0 === 0) i0 = i; i1 = i; break;
25691       case "e": break out;
25692       default: if (i0 > 0) i0 = 0; break;
25693     }
25694   }
25695
25696   return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
25697 };
25698
25699 var prefixExponent;
25700
25701 var formatPrefixAuto = function(x, p) {
25702   var d = formatDecimal(x, p);
25703   if (!d) return x + "";
25704   var coefficient = d[0],
25705       exponent = d[1],
25706       i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
25707       n = coefficient.length;
25708   return i === n ? coefficient
25709       : i > n ? coefficient + new Array(i - n + 1).join("0")
25710       : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
25711       : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
25712 };
25713
25714 var formatRounded = function(x, p) {
25715   var d = formatDecimal(x, p);
25716   if (!d) return x + "";
25717   var coefficient = d[0],
25718       exponent = d[1];
25719   return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
25720       : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
25721       : coefficient + new Array(exponent - coefficient.length + 2).join("0");
25722 };
25723
25724 var formatTypes = {
25725   "": formatDefault,
25726   "%": function(x, p) { return (x * 100).toFixed(p); },
25727   "b": function(x) { return Math.round(x).toString(2); },
25728   "c": function(x) { return x + ""; },
25729   "d": function(x) { return Math.round(x).toString(10); },
25730   "e": function(x, p) { return x.toExponential(p); },
25731   "f": function(x, p) { return x.toFixed(p); },
25732   "g": function(x, p) { return x.toPrecision(p); },
25733   "o": function(x) { return Math.round(x).toString(8); },
25734   "p": function(x, p) { return formatRounded(x * 100, p); },
25735   "r": formatRounded,
25736   "s": formatPrefixAuto,
25737   "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
25738   "x": function(x) { return Math.round(x).toString(16); }
25739 };
25740
25741 // [[fill]align][sign][symbol][0][width][,][.precision][type]
25742 var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
25743
25744 function formatSpecifier(specifier) {
25745   return new FormatSpecifier(specifier);
25746 }
25747
25748 formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
25749
25750 function FormatSpecifier(specifier) {
25751   if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
25752
25753   var match,
25754       fill = match[1] || " ",
25755       align = match[2] || ">",
25756       sign = match[3] || "-",
25757       symbol = match[4] || "",
25758       zero = !!match[5],
25759       width = match[6] && +match[6],
25760       comma = !!match[7],
25761       precision = match[8] && +match[8].slice(1),
25762       type = match[9] || "";
25763
25764   // The "n" type is an alias for ",g".
25765   if (type === "n") comma = true, type = "g";
25766
25767   // Map invalid types to the default format.
25768   else if (!formatTypes[type]) type = "";
25769
25770   // If zero fill is specified, padding goes after sign and before digits.
25771   if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
25772
25773   this.fill = fill;
25774   this.align = align;
25775   this.sign = sign;
25776   this.symbol = symbol;
25777   this.zero = zero;
25778   this.width = width;
25779   this.comma = comma;
25780   this.precision = precision;
25781   this.type = type;
25782 }
25783
25784 FormatSpecifier.prototype.toString = function() {
25785   return this.fill
25786       + this.align
25787       + this.sign
25788       + this.symbol
25789       + (this.zero ? "0" : "")
25790       + (this.width == null ? "" : Math.max(1, this.width | 0))
25791       + (this.comma ? "," : "")
25792       + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
25793       + this.type;
25794 };
25795
25796 var identity$3 = function(x) {
25797   return x;
25798 };
25799
25800 var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
25801
25802 var formatLocale = function(locale) {
25803   var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3,
25804       currency = locale.currency,
25805       decimal = locale.decimal,
25806       numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$3,
25807       percent = locale.percent || "%";
25808
25809   function newFormat(specifier) {
25810     specifier = formatSpecifier(specifier);
25811
25812     var fill = specifier.fill,
25813         align = specifier.align,
25814         sign = specifier.sign,
25815         symbol = specifier.symbol,
25816         zero = specifier.zero,
25817         width = specifier.width,
25818         comma = specifier.comma,
25819         precision = specifier.precision,
25820         type = specifier.type;
25821
25822     // Compute the prefix and suffix.
25823     // For SI-prefix, the suffix is lazily computed.
25824     var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
25825         suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : "";
25826
25827     // What format function should we use?
25828     // Is this an integer type?
25829     // Can this type generate exponential notation?
25830     var formatType = formatTypes[type],
25831         maybeSuffix = !type || /[defgprs%]/.test(type);
25832
25833     // Set the default precision if not specified,
25834     // or clamp the specified precision to the supported range.
25835     // For significant precision, it must be in [1, 21].
25836     // For fixed precision, it must be in [0, 20].
25837     precision = precision == null ? (type ? 6 : 12)
25838         : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
25839         : Math.max(0, Math.min(20, precision));
25840
25841     function format(value) {
25842       var valuePrefix = prefix,
25843           valueSuffix = suffix,
25844           i, n, c;
25845
25846       if (type === "c") {
25847         valueSuffix = formatType(value) + valueSuffix;
25848         value = "";
25849       } else {
25850         value = +value;
25851
25852         // Perform the initial formatting.
25853         var valueNegative = value < 0;
25854         value = formatType(Math.abs(value), precision);
25855
25856         // If a negative value rounds to zero during formatting, treat as positive.
25857         if (valueNegative && +value === 0) valueNegative = false;
25858
25859         // Compute the prefix and suffix.
25860         valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
25861         valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
25862
25863         // Break the formatted value into the integer “value” part that can be
25864         // grouped, and fractional or exponential “suffix” part that is not.
25865         if (maybeSuffix) {
25866           i = -1, n = value.length;
25867           while (++i < n) {
25868             if (c = value.charCodeAt(i), 48 > c || c > 57) {
25869               valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
25870               value = value.slice(0, i);
25871               break;
25872             }
25873           }
25874         }
25875       }
25876
25877       // If the fill character is not "0", grouping is applied before padding.
25878       if (comma && !zero) value = group(value, Infinity);
25879
25880       // Compute the padding.
25881       var length = valuePrefix.length + value.length + valueSuffix.length,
25882           padding = length < width ? new Array(width - length + 1).join(fill) : "";
25883
25884       // If the fill character is "0", grouping is applied after padding.
25885       if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
25886
25887       // Reconstruct the final output based on the desired alignment.
25888       switch (align) {
25889         case "<": value = valuePrefix + value + valueSuffix + padding; break;
25890         case "=": value = valuePrefix + padding + value + valueSuffix; break;
25891         case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
25892         default: value = padding + valuePrefix + value + valueSuffix; break;
25893       }
25894
25895       return numerals(value);
25896     }
25897
25898     format.toString = function() {
25899       return specifier + "";
25900     };
25901
25902     return format;
25903   }
25904
25905   function formatPrefix(specifier, value) {
25906     var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
25907         e = Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3,
25908         k = Math.pow(10, -e),
25909         prefix = prefixes[8 + e / 3];
25910     return function(value) {
25911       return f(k * value) + prefix;
25912     };
25913   }
25914
25915   return {
25916     format: newFormat,
25917     formatPrefix: formatPrefix
25918   };
25919 };
25920
25921 var locale$1;
25922 var format;
25923 var formatPrefix;
25924
25925 defaultLocale({
25926   decimal: ".",
25927   thousands: ",",
25928   grouping: [3],
25929   currency: ["$", ""]
25930 });
25931
25932 function defaultLocale(definition) {
25933   locale$1 = formatLocale(definition);
25934   format = locale$1.format;
25935   formatPrefix = locale$1.formatPrefix;
25936   return locale$1;
25937 }
25938
25939 var precisionFixed = function(step) {
25940   return Math.max(0, -exponent$1(Math.abs(step)));
25941 };
25942
25943 var precisionPrefix = function(step, value) {
25944   return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3 - exponent$1(Math.abs(step)));
25945 };
25946
25947 var precisionRound = function(step, max) {
25948   step = Math.abs(step), max = Math.abs(max) - step;
25949   return Math.max(0, exponent$1(max) - exponent$1(step)) + 1;
25950 };
25951
25952 // Adds floating point numbers with twice the normal precision.
25953 // Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
25954 // Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
25955 // 305–363 (1997).
25956 // Code adapted from GeographicLib by Charles F. F. Karney,
25957 // http://geographiclib.sourceforge.net/
25958
25959 var adder = function() {
25960   return new Adder;
25961 };
25962
25963 function Adder() {
25964   this.reset();
25965 }
25966
25967 Adder.prototype = {
25968   constructor: Adder,
25969   reset: function() {
25970     this.s = // rounded value
25971     this.t = 0; // exact error
25972   },
25973   add: function(y) {
25974     add$1(temp, y, this.t);
25975     add$1(this, temp.s, this.s);
25976     if (this.s) this.t += temp.t;
25977     else this.s = temp.t;
25978   },
25979   valueOf: function() {
25980     return this.s;
25981   }
25982 };
25983
25984 var temp = new Adder;
25985
25986 function add$1(adder, a, b) {
25987   var x = adder.s = a + b,
25988       bv = x - a,
25989       av = x - bv;
25990   adder.t = (a - av) + (b - bv);
25991 }
25992
25993 var epsilon$2 = 1e-6;
25994 var epsilon2$1 = 1e-12;
25995 var pi$3 = Math.PI;
25996 var halfPi$2 = pi$3 / 2;
25997 var quarterPi = pi$3 / 4;
25998 var tau$3 = pi$3 * 2;
25999
26000 var degrees$1 = 180 / pi$3;
26001 var radians = pi$3 / 180;
26002
26003 var abs = Math.abs;
26004 var atan = Math.atan;
26005 var atan2 = Math.atan2;
26006 var cos$1 = Math.cos;
26007 var ceil = Math.ceil;
26008 var exp = Math.exp;
26009
26010 var log = Math.log;
26011 var pow = Math.pow;
26012 var sin$1 = Math.sin;
26013 var sign = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
26014 var sqrt = Math.sqrt;
26015 var tan = Math.tan;
26016
26017 function acos(x) {
26018   return x > 1 ? 0 : x < -1 ? pi$3 : Math.acos(x);
26019 }
26020
26021 function asin(x) {
26022   return x > 1 ? halfPi$2 : x < -1 ? -halfPi$2 : Math.asin(x);
26023 }
26024
26025 function haversin(x) {
26026   return (x = sin$1(x / 2)) * x;
26027 }
26028
26029 function noop$1() {}
26030
26031 function streamGeometry(geometry, stream) {
26032   if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
26033     streamGeometryType[geometry.type](geometry, stream);
26034   }
26035 }
26036
26037 var streamObjectType = {
26038   Feature: function(object, stream) {
26039     streamGeometry(object.geometry, stream);
26040   },
26041   FeatureCollection: function(object, stream) {
26042     var features = object.features, i = -1, n = features.length;
26043     while (++i < n) streamGeometry(features[i].geometry, stream);
26044   }
26045 };
26046
26047 var streamGeometryType = {
26048   Sphere: function(object, stream) {
26049     stream.sphere();
26050   },
26051   Point: function(object, stream) {
26052     object = object.coordinates;
26053     stream.point(object[0], object[1], object[2]);
26054   },
26055   MultiPoint: function(object, stream) {
26056     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26057     while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
26058   },
26059   LineString: function(object, stream) {
26060     streamLine(object.coordinates, stream, 0);
26061   },
26062   MultiLineString: function(object, stream) {
26063     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26064     while (++i < n) streamLine(coordinates[i], stream, 0);
26065   },
26066   Polygon: function(object, stream) {
26067     streamPolygon(object.coordinates, stream);
26068   },
26069   MultiPolygon: function(object, stream) {
26070     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26071     while (++i < n) streamPolygon(coordinates[i], stream);
26072   },
26073   GeometryCollection: function(object, stream) {
26074     var geometries = object.geometries, i = -1, n = geometries.length;
26075     while (++i < n) streamGeometry(geometries[i], stream);
26076   }
26077 };
26078
26079 function streamLine(coordinates, stream, closed) {
26080   var i = -1, n = coordinates.length - closed, coordinate;
26081   stream.lineStart();
26082   while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
26083   stream.lineEnd();
26084 }
26085
26086 function streamPolygon(coordinates, stream) {
26087   var i = -1, n = coordinates.length;
26088   stream.polygonStart();
26089   while (++i < n) streamLine(coordinates[i], stream, 1);
26090   stream.polygonEnd();
26091 }
26092
26093 var geoStream = function(object, stream) {
26094   if (object && streamObjectType.hasOwnProperty(object.type)) {
26095     streamObjectType[object.type](object, stream);
26096   } else {
26097     streamGeometry(object, stream);
26098   }
26099 };
26100
26101 var areaRingSum = adder();
26102
26103 var areaSum = adder();
26104 var lambda00;
26105 var phi00;
26106 var lambda0;
26107 var cosPhi0;
26108 var sinPhi0;
26109
26110 var areaStream = {
26111   point: noop$1,
26112   lineStart: noop$1,
26113   lineEnd: noop$1,
26114   polygonStart: function() {
26115     areaRingSum.reset();
26116     areaStream.lineStart = areaRingStart;
26117     areaStream.lineEnd = areaRingEnd;
26118   },
26119   polygonEnd: function() {
26120     var areaRing = +areaRingSum;
26121     areaSum.add(areaRing < 0 ? tau$3 + areaRing : areaRing);
26122     this.lineStart = this.lineEnd = this.point = noop$1;
26123   },
26124   sphere: function() {
26125     areaSum.add(tau$3);
26126   }
26127 };
26128
26129 function areaRingStart() {
26130   areaStream.point = areaPointFirst;
26131 }
26132
26133 function areaRingEnd() {
26134   areaPoint(lambda00, phi00);
26135 }
26136
26137 function areaPointFirst(lambda, phi) {
26138   areaStream.point = areaPoint;
26139   lambda00 = lambda, phi00 = phi;
26140   lambda *= radians, phi *= radians;
26141   lambda0 = lambda, cosPhi0 = cos$1(phi = phi / 2 + quarterPi), sinPhi0 = sin$1(phi);
26142 }
26143
26144 function areaPoint(lambda, phi) {
26145   lambda *= radians, phi *= radians;
26146   phi = phi / 2 + quarterPi; // half the angular distance from south pole
26147
26148   // Spherical excess E for a spherical triangle with vertices: south pole,
26149   // previous point, current point.  Uses a formula derived from Cagnoli’s
26150   // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
26151   var dLambda = lambda - lambda0,
26152       sdLambda = dLambda >= 0 ? 1 : -1,
26153       adLambda = sdLambda * dLambda,
26154       cosPhi = cos$1(phi),
26155       sinPhi = sin$1(phi),
26156       k = sinPhi0 * sinPhi,
26157       u = cosPhi0 * cosPhi + k * cos$1(adLambda),
26158       v = k * sdLambda * sin$1(adLambda);
26159   areaRingSum.add(atan2(v, u));
26160
26161   // Advance the previous points.
26162   lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
26163 }
26164
26165 var area = function(object) {
26166   areaSum.reset();
26167   geoStream(object, areaStream);
26168   return areaSum * 2;
26169 };
26170
26171 function spherical(cartesian) {
26172   return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
26173 }
26174
26175 function cartesian(spherical) {
26176   var lambda = spherical[0], phi = spherical[1], cosPhi = cos$1(phi);
26177   return [cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi)];
26178 }
26179
26180 function cartesianDot(a, b) {
26181   return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
26182 }
26183
26184 function cartesianCross(a, b) {
26185   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]];
26186 }
26187
26188 // TODO return a
26189 function cartesianAddInPlace(a, b) {
26190   a[0] += b[0], a[1] += b[1], a[2] += b[2];
26191 }
26192
26193 function cartesianScale(vector, k) {
26194   return [vector[0] * k, vector[1] * k, vector[2] * k];
26195 }
26196
26197 // TODO return d
26198 function cartesianNormalizeInPlace(d) {
26199   var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
26200   d[0] /= l, d[1] /= l, d[2] /= l;
26201 }
26202
26203 var lambda0$1;
26204 var phi0;
26205 var lambda1;
26206 var phi1;
26207 var lambda2;
26208 var lambda00$1;
26209 var phi00$1;
26210 var p0;
26211 var deltaSum = adder();
26212 var ranges;
26213 var range;
26214
26215 var boundsStream = {
26216   point: boundsPoint,
26217   lineStart: boundsLineStart,
26218   lineEnd: boundsLineEnd,
26219   polygonStart: function() {
26220     boundsStream.point = boundsRingPoint;
26221     boundsStream.lineStart = boundsRingStart;
26222     boundsStream.lineEnd = boundsRingEnd;
26223     deltaSum.reset();
26224     areaStream.polygonStart();
26225   },
26226   polygonEnd: function() {
26227     areaStream.polygonEnd();
26228     boundsStream.point = boundsPoint;
26229     boundsStream.lineStart = boundsLineStart;
26230     boundsStream.lineEnd = boundsLineEnd;
26231     if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
26232     else if (deltaSum > epsilon$2) phi1 = 90;
26233     else if (deltaSum < -epsilon$2) phi0 = -90;
26234     range[0] = lambda0$1, range[1] = lambda1;
26235   }
26236 };
26237
26238 function boundsPoint(lambda, phi) {
26239   ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26240   if (phi < phi0) phi0 = phi;
26241   if (phi > phi1) phi1 = phi;
26242 }
26243
26244 function linePoint(lambda, phi) {
26245   var p = cartesian([lambda * radians, phi * radians]);
26246   if (p0) {
26247     var normal = cartesianCross(p0, p),
26248         equatorial = [normal[1], -normal[0], 0],
26249         inflection = cartesianCross(equatorial, normal);
26250     cartesianNormalizeInPlace(inflection);
26251     inflection = spherical(inflection);
26252     var delta = lambda - lambda2,
26253         sign$$1 = delta > 0 ? 1 : -1,
26254         lambdai = inflection[0] * degrees$1 * sign$$1,
26255         phii,
26256         antimeridian = abs(delta) > 180;
26257     if (antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26258       phii = inflection[1] * degrees$1;
26259       if (phii > phi1) phi1 = phii;
26260     } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26261       phii = -inflection[1] * degrees$1;
26262       if (phii < phi0) phi0 = phii;
26263     } else {
26264       if (phi < phi0) phi0 = phi;
26265       if (phi > phi1) phi1 = phi;
26266     }
26267     if (antimeridian) {
26268       if (lambda < lambda2) {
26269         if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26270       } else {
26271         if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26272       }
26273     } else {
26274       if (lambda1 >= lambda0$1) {
26275         if (lambda < lambda0$1) lambda0$1 = lambda;
26276         if (lambda > lambda1) lambda1 = lambda;
26277       } else {
26278         if (lambda > lambda2) {
26279           if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26280         } else {
26281           if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26282         }
26283       }
26284     }
26285   } else {
26286     ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26287   }
26288   if (phi < phi0) phi0 = phi;
26289   if (phi > phi1) phi1 = phi;
26290   p0 = p, lambda2 = lambda;
26291 }
26292
26293 function boundsLineStart() {
26294   boundsStream.point = linePoint;
26295 }
26296
26297 function boundsLineEnd() {
26298   range[0] = lambda0$1, range[1] = lambda1;
26299   boundsStream.point = boundsPoint;
26300   p0 = null;
26301 }
26302
26303 function boundsRingPoint(lambda, phi) {
26304   if (p0) {
26305     var delta = lambda - lambda2;
26306     deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
26307   } else {
26308     lambda00$1 = lambda, phi00$1 = phi;
26309   }
26310   areaStream.point(lambda, phi);
26311   linePoint(lambda, phi);
26312 }
26313
26314 function boundsRingStart() {
26315   areaStream.lineStart();
26316 }
26317
26318 function boundsRingEnd() {
26319   boundsRingPoint(lambda00$1, phi00$1);
26320   areaStream.lineEnd();
26321   if (abs(deltaSum) > epsilon$2) lambda0$1 = -(lambda1 = 180);
26322   range[0] = lambda0$1, range[1] = lambda1;
26323   p0 = null;
26324 }
26325
26326 // Finds the left-right distance between two longitudes.
26327 // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
26328 // the distance between ±180° to be 360°.
26329 function angle(lambda0, lambda1) {
26330   return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
26331 }
26332
26333 function rangeCompare(a, b) {
26334   return a[0] - b[0];
26335 }
26336
26337 function rangeContains(range, x) {
26338   return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
26339 }
26340
26341 var bounds = function(feature) {
26342   var i, n, a, b, merged, deltaMax, delta;
26343
26344   phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
26345   ranges = [];
26346   geoStream(feature, boundsStream);
26347
26348   // First, sort ranges by their minimum longitudes.
26349   if (n = ranges.length) {
26350     ranges.sort(rangeCompare);
26351
26352     // Then, merge any ranges that overlap.
26353     for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
26354       b = ranges[i];
26355       if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
26356         if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
26357         if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
26358       } else {
26359         merged.push(a = b);
26360       }
26361     }
26362
26363     // Finally, find the largest gap between the merged ranges.
26364     // The final bounding box will be the inverse of this gap.
26365     for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
26366       b = merged[i];
26367       if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
26368     }
26369   }
26370
26371   ranges = range = null;
26372
26373   return lambda0$1 === Infinity || phi0 === Infinity
26374       ? [[NaN, NaN], [NaN, NaN]]
26375       : [[lambda0$1, phi0], [lambda1, phi1]];
26376 };
26377
26378 var W0;
26379 var W1;
26380 var X0;
26381 var Y0;
26382 var Z0;
26383 var X1;
26384 var Y1;
26385 var Z1;
26386 var X2;
26387 var Y2;
26388 var Z2;
26389 var lambda00$2;
26390 var phi00$2;
26391 var x0;
26392 var y0;
26393 var z0; // previous point
26394
26395 var centroidStream = {
26396   sphere: noop$1,
26397   point: centroidPoint,
26398   lineStart: centroidLineStart,
26399   lineEnd: centroidLineEnd,
26400   polygonStart: function() {
26401     centroidStream.lineStart = centroidRingStart;
26402     centroidStream.lineEnd = centroidRingEnd;
26403   },
26404   polygonEnd: function() {
26405     centroidStream.lineStart = centroidLineStart;
26406     centroidStream.lineEnd = centroidLineEnd;
26407   }
26408 };
26409
26410 // Arithmetic mean of Cartesian vectors.
26411 function centroidPoint(lambda, phi) {
26412   lambda *= radians, phi *= radians;
26413   var cosPhi = cos$1(phi);
26414   centroidPointCartesian(cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi));
26415 }
26416
26417 function centroidPointCartesian(x, y, z) {
26418   ++W0;
26419   X0 += (x - X0) / W0;
26420   Y0 += (y - Y0) / W0;
26421   Z0 += (z - Z0) / W0;
26422 }
26423
26424 function centroidLineStart() {
26425   centroidStream.point = centroidLinePointFirst;
26426 }
26427
26428 function centroidLinePointFirst(lambda, phi) {
26429   lambda *= radians, phi *= radians;
26430   var cosPhi = cos$1(phi);
26431   x0 = cosPhi * cos$1(lambda);
26432   y0 = cosPhi * sin$1(lambda);
26433   z0 = sin$1(phi);
26434   centroidStream.point = centroidLinePoint;
26435   centroidPointCartesian(x0, y0, z0);
26436 }
26437
26438 function centroidLinePoint(lambda, phi) {
26439   lambda *= radians, phi *= radians;
26440   var cosPhi = cos$1(phi),
26441       x = cosPhi * cos$1(lambda),
26442       y = cosPhi * sin$1(lambda),
26443       z = sin$1(phi),
26444       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);
26445   W1 += w;
26446   X1 += w * (x0 + (x0 = x));
26447   Y1 += w * (y0 + (y0 = y));
26448   Z1 += w * (z0 + (z0 = z));
26449   centroidPointCartesian(x0, y0, z0);
26450 }
26451
26452 function centroidLineEnd() {
26453   centroidStream.point = centroidPoint;
26454 }
26455
26456 // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
26457 // J. Applied Mechanics 42, 239 (1975).
26458 function centroidRingStart() {
26459   centroidStream.point = centroidRingPointFirst;
26460 }
26461
26462 function centroidRingEnd() {
26463   centroidRingPoint(lambda00$2, phi00$2);
26464   centroidStream.point = centroidPoint;
26465 }
26466
26467 function centroidRingPointFirst(lambda, phi) {
26468   lambda00$2 = lambda, phi00$2 = phi;
26469   lambda *= radians, phi *= radians;
26470   centroidStream.point = centroidRingPoint;
26471   var cosPhi = cos$1(phi);
26472   x0 = cosPhi * cos$1(lambda);
26473   y0 = cosPhi * sin$1(lambda);
26474   z0 = sin$1(phi);
26475   centroidPointCartesian(x0, y0, z0);
26476 }
26477
26478 function centroidRingPoint(lambda, phi) {
26479   lambda *= radians, phi *= radians;
26480   var cosPhi = cos$1(phi),
26481       x = cosPhi * cos$1(lambda),
26482       y = cosPhi * sin$1(lambda),
26483       z = sin$1(phi),
26484       cx = y0 * z - z0 * y,
26485       cy = z0 * x - x0 * z,
26486       cz = x0 * y - y0 * x,
26487       m = sqrt(cx * cx + cy * cy + cz * cz),
26488       w = asin(m), // line weight = angle
26489       v = m && -w / m; // area weight multiplier
26490   X2 += v * cx;
26491   Y2 += v * cy;
26492   Z2 += v * cz;
26493   W1 += w;
26494   X1 += w * (x0 + (x0 = x));
26495   Y1 += w * (y0 + (y0 = y));
26496   Z1 += w * (z0 + (z0 = z));
26497   centroidPointCartesian(x0, y0, z0);
26498 }
26499
26500 var d3GeoCentroid = function(object) {
26501   W0 = W1 =
26502   X0 = Y0 = Z0 =
26503   X1 = Y1 = Z1 =
26504   X2 = Y2 = Z2 = 0;
26505   geoStream(object, centroidStream);
26506
26507   var x = X2,
26508       y = Y2,
26509       z = Z2,
26510       m = x * x + y * y + z * z;
26511
26512   // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
26513   if (m < epsilon2$1) {
26514     x = X1, y = Y1, z = Z1;
26515     // If the feature has zero length, fall back to arithmetic mean of point vectors.
26516     if (W1 < epsilon$2) x = X0, y = Y0, z = Z0;
26517     m = x * x + y * y + z * z;
26518     // If the feature still has an undefined ccentroid, then return.
26519     if (m < epsilon2$1) return [NaN, NaN];
26520   }
26521
26522   return [atan2(y, x) * degrees$1, asin(z / sqrt(m)) * degrees$1];
26523 };
26524
26525 var constant$7 = function(x) {
26526   return function() {
26527     return x;
26528   };
26529 };
26530
26531 var compose = function(a, b) {
26532
26533   function compose(x, y) {
26534     return x = a(x, y), b(x[0], x[1]);
26535   }
26536
26537   if (a.invert && b.invert) compose.invert = function(x, y) {
26538     return x = b.invert(x, y), x && a.invert(x[0], x[1]);
26539   };
26540
26541   return compose;
26542 };
26543
26544 function rotationIdentity(lambda, phi) {
26545   return [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26546 }
26547
26548 rotationIdentity.invert = rotationIdentity;
26549
26550 function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
26551   return (deltaLambda %= tau$3) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
26552     : rotationLambda(deltaLambda))
26553     : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
26554     : rotationIdentity);
26555 }
26556
26557 function forwardRotationLambda(deltaLambda) {
26558   return function(lambda, phi) {
26559     return lambda += deltaLambda, [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26560   };
26561 }
26562
26563 function rotationLambda(deltaLambda) {
26564   var rotation = forwardRotationLambda(deltaLambda);
26565   rotation.invert = forwardRotationLambda(-deltaLambda);
26566   return rotation;
26567 }
26568
26569 function rotationPhiGamma(deltaPhi, deltaGamma) {
26570   var cosDeltaPhi = cos$1(deltaPhi),
26571       sinDeltaPhi = sin$1(deltaPhi),
26572       cosDeltaGamma = cos$1(deltaGamma),
26573       sinDeltaGamma = sin$1(deltaGamma);
26574
26575   function rotation(lambda, phi) {
26576     var cosPhi = cos$1(phi),
26577         x = cos$1(lambda) * cosPhi,
26578         y = sin$1(lambda) * cosPhi,
26579         z = sin$1(phi),
26580         k = z * cosDeltaPhi + x * sinDeltaPhi;
26581     return [
26582       atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
26583       asin(k * cosDeltaGamma + y * sinDeltaGamma)
26584     ];
26585   }
26586
26587   rotation.invert = function(lambda, phi) {
26588     var cosPhi = cos$1(phi),
26589         x = cos$1(lambda) * cosPhi,
26590         y = sin$1(lambda) * cosPhi,
26591         z = sin$1(phi),
26592         k = z * cosDeltaGamma - y * sinDeltaGamma;
26593     return [
26594       atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
26595       asin(k * cosDeltaPhi - x * sinDeltaPhi)
26596     ];
26597   };
26598
26599   return rotation;
26600 }
26601
26602 var rotation = function(rotate) {
26603   rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
26604
26605   function forward(coordinates) {
26606     coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
26607     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26608   }
26609
26610   forward.invert = function(coordinates) {
26611     coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
26612     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26613   };
26614
26615   return forward;
26616 };
26617
26618 // Generates a circle centered at [0°, 0°], with a given radius and precision.
26619 function circleStream(stream, radius, delta, direction, t0, t1) {
26620   if (!delta) return;
26621   var cosRadius = cos$1(radius),
26622       sinRadius = sin$1(radius),
26623       step = direction * delta;
26624   if (t0 == null) {
26625     t0 = radius + direction * tau$3;
26626     t1 = radius - step / 2;
26627   } else {
26628     t0 = circleRadius(cosRadius, t0);
26629     t1 = circleRadius(cosRadius, t1);
26630     if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$3;
26631   }
26632   for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
26633     point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(t)]);
26634     stream.point(point[0], point[1]);
26635   }
26636 }
26637
26638 // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
26639 function circleRadius(cosRadius, point) {
26640   point = cartesian(point), point[0] -= cosRadius;
26641   cartesianNormalizeInPlace(point);
26642   var radius = acos(-point[1]);
26643   return ((-point[2] < 0 ? -radius : radius) + tau$3 - epsilon$2) % tau$3;
26644 }
26645
26646 var circle = function() {
26647   var center = constant$7([0, 0]),
26648       radius = constant$7(90),
26649       precision = constant$7(6),
26650       ring,
26651       rotate,
26652       stream = {point: point};
26653
26654   function point(x, y) {
26655     ring.push(x = rotate(x, y));
26656     x[0] *= degrees$1, x[1] *= degrees$1;
26657   }
26658
26659   function circle() {
26660     var c = center.apply(this, arguments),
26661         r = radius.apply(this, arguments) * radians,
26662         p = precision.apply(this, arguments) * radians;
26663     ring = [];
26664     rotate = rotateRadians(-c[0] * radians, -c[1] * radians, 0).invert;
26665     circleStream(stream, r, p, 1);
26666     c = {type: "Polygon", coordinates: [ring]};
26667     ring = rotate = null;
26668     return c;
26669   }
26670
26671   circle.center = function(_) {
26672     return arguments.length ? (center = typeof _ === "function" ? _ : constant$7([+_[0], +_[1]]), circle) : center;
26673   };
26674
26675   circle.radius = function(_) {
26676     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$7(+_), circle) : radius;
26677   };
26678
26679   circle.precision = function(_) {
26680     return arguments.length ? (precision = typeof _ === "function" ? _ : constant$7(+_), circle) : precision;
26681   };
26682
26683   return circle;
26684 };
26685
26686 var clipBuffer = function() {
26687   var lines = [],
26688       line;
26689   return {
26690     point: function(x, y) {
26691       line.push([x, y]);
26692     },
26693     lineStart: function() {
26694       lines.push(line = []);
26695     },
26696     lineEnd: noop$1,
26697     rejoin: function() {
26698       if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
26699     },
26700     result: function() {
26701       var result = lines;
26702       lines = [];
26703       line = null;
26704       return result;
26705     }
26706   };
26707 };
26708
26709 var clipLine = function(a, b, x0, y0, x1, y1) {
26710   var ax = a[0],
26711       ay = a[1],
26712       bx = b[0],
26713       by = b[1],
26714       t0 = 0,
26715       t1 = 1,
26716       dx = bx - ax,
26717       dy = by - ay,
26718       r;
26719
26720   r = x0 - ax;
26721   if (!dx && r > 0) return;
26722   r /= dx;
26723   if (dx < 0) {
26724     if (r < t0) return;
26725     if (r < t1) t1 = r;
26726   } else if (dx > 0) {
26727     if (r > t1) return;
26728     if (r > t0) t0 = r;
26729   }
26730
26731   r = x1 - ax;
26732   if (!dx && r < 0) return;
26733   r /= dx;
26734   if (dx < 0) {
26735     if (r > t1) return;
26736     if (r > t0) t0 = r;
26737   } else if (dx > 0) {
26738     if (r < t0) return;
26739     if (r < t1) t1 = r;
26740   }
26741
26742   r = y0 - ay;
26743   if (!dy && r > 0) return;
26744   r /= dy;
26745   if (dy < 0) {
26746     if (r < t0) return;
26747     if (r < t1) t1 = r;
26748   } else if (dy > 0) {
26749     if (r > t1) return;
26750     if (r > t0) t0 = r;
26751   }
26752
26753   r = y1 - ay;
26754   if (!dy && r < 0) return;
26755   r /= dy;
26756   if (dy < 0) {
26757     if (r > t1) return;
26758     if (r > t0) t0 = r;
26759   } else if (dy > 0) {
26760     if (r < t0) return;
26761     if (r < t1) t1 = r;
26762   }
26763
26764   if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
26765   if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
26766   return true;
26767 };
26768
26769 var pointEqual = function(a, b) {
26770   return abs(a[0] - b[0]) < epsilon$2 && abs(a[1] - b[1]) < epsilon$2;
26771 };
26772
26773 function Intersection(point, points, other, entry) {
26774   this.x = point;
26775   this.z = points;
26776   this.o = other; // another intersection
26777   this.e = entry; // is an entry?
26778   this.v = false; // visited
26779   this.n = this.p = null; // next & previous
26780 }
26781
26782 // A generalized polygon clipping algorithm: given a polygon that has been cut
26783 // into its visible line segments, and rejoins the segments by interpolating
26784 // along the clip edge.
26785 var clipPolygon = function(segments, compareIntersection, startInside, interpolate, stream) {
26786   var subject = [],
26787       clip = [],
26788       i,
26789       n;
26790
26791   segments.forEach(function(segment) {
26792     if ((n = segment.length - 1) <= 0) return;
26793     var n, p0 = segment[0], p1 = segment[n], x;
26794
26795     // If the first and last points of a segment are coincident, then treat as a
26796     // closed ring. TODO if all rings are closed, then the winding order of the
26797     // exterior ring should be checked.
26798     if (pointEqual(p0, p1)) {
26799       stream.lineStart();
26800       for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
26801       stream.lineEnd();
26802       return;
26803     }
26804
26805     subject.push(x = new Intersection(p0, segment, null, true));
26806     clip.push(x.o = new Intersection(p0, null, x, false));
26807     subject.push(x = new Intersection(p1, segment, null, false));
26808     clip.push(x.o = new Intersection(p1, null, x, true));
26809   });
26810
26811   if (!subject.length) return;
26812
26813   clip.sort(compareIntersection);
26814   link$1(subject);
26815   link$1(clip);
26816
26817   for (i = 0, n = clip.length; i < n; ++i) {
26818     clip[i].e = startInside = !startInside;
26819   }
26820
26821   var start = subject[0],
26822       points,
26823       point;
26824
26825   while (1) {
26826     // Find first unvisited intersection.
26827     var current = start,
26828         isSubject = true;
26829     while (current.v) if ((current = current.n) === start) return;
26830     points = current.z;
26831     stream.lineStart();
26832     do {
26833       current.v = current.o.v = true;
26834       if (current.e) {
26835         if (isSubject) {
26836           for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]);
26837         } else {
26838           interpolate(current.x, current.n.x, 1, stream);
26839         }
26840         current = current.n;
26841       } else {
26842         if (isSubject) {
26843           points = current.p.z;
26844           for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]);
26845         } else {
26846           interpolate(current.x, current.p.x, -1, stream);
26847         }
26848         current = current.p;
26849       }
26850       current = current.o;
26851       points = current.z;
26852       isSubject = !isSubject;
26853     } while (!current.v);
26854     stream.lineEnd();
26855   }
26856 };
26857
26858 function link$1(array) {
26859   if (!(n = array.length)) return;
26860   var n,
26861       i = 0,
26862       a = array[0],
26863       b;
26864   while (++i < n) {
26865     a.n = b = array[i];
26866     b.p = a;
26867     a = b;
26868   }
26869   a.n = b = array[0];
26870   b.p = a;
26871 }
26872
26873 var clipMax = 1e9;
26874 var clipMin = -clipMax;
26875
26876 // TODO Use d3-polygon’s polygonContains here for the ring check?
26877 // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
26878
26879 function clipExtent(x0, y0, x1, y1) {
26880
26881   function visible(x, y) {
26882     return x0 <= x && x <= x1 && y0 <= y && y <= y1;
26883   }
26884
26885   function interpolate(from, to, direction, stream) {
26886     var a = 0, a1 = 0;
26887     if (from == null
26888         || (a = corner(from, direction)) !== (a1 = corner(to, direction))
26889         || comparePoint(from, to) < 0 ^ direction > 0) {
26890       do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
26891       while ((a = (a + direction + 4) % 4) !== a1);
26892     } else {
26893       stream.point(to[0], to[1]);
26894     }
26895   }
26896
26897   function corner(p, direction) {
26898     return abs(p[0] - x0) < epsilon$2 ? direction > 0 ? 0 : 3
26899         : abs(p[0] - x1) < epsilon$2 ? direction > 0 ? 2 : 1
26900         : abs(p[1] - y0) < epsilon$2 ? direction > 0 ? 1 : 0
26901         : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
26902   }
26903
26904   function compareIntersection(a, b) {
26905     return comparePoint(a.x, b.x);
26906   }
26907
26908   function comparePoint(a, b) {
26909     var ca = corner(a, 1),
26910         cb = corner(b, 1);
26911     return ca !== cb ? ca - cb
26912         : ca === 0 ? b[1] - a[1]
26913         : ca === 1 ? a[0] - b[0]
26914         : ca === 2 ? a[1] - b[1]
26915         : b[0] - a[0];
26916   }
26917
26918   return function(stream) {
26919     var activeStream = stream,
26920         bufferStream = clipBuffer(),
26921         segments,
26922         polygon,
26923         ring,
26924         x__, y__, v__, // first point
26925         x_, y_, v_, // previous point
26926         first,
26927         clean;
26928
26929     var clipStream = {
26930       point: point,
26931       lineStart: lineStart,
26932       lineEnd: lineEnd,
26933       polygonStart: polygonStart,
26934       polygonEnd: polygonEnd
26935     };
26936
26937     function point(x, y) {
26938       if (visible(x, y)) activeStream.point(x, y);
26939     }
26940
26941     function polygonInside() {
26942       var winding = 0;
26943
26944       for (var i = 0, n = polygon.length; i < n; ++i) {
26945         for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
26946           a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
26947           if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
26948           else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
26949         }
26950       }
26951
26952       return winding;
26953     }
26954
26955     // Buffer geometry within a polygon and then clip it en masse.
26956     function polygonStart() {
26957       activeStream = bufferStream, segments = [], polygon = [], clean = true;
26958     }
26959
26960     function polygonEnd() {
26961       var startInside = polygonInside(),
26962           cleanInside = clean && startInside,
26963           visible = (segments = merge(segments)).length;
26964       if (cleanInside || visible) {
26965         stream.polygonStart();
26966         if (cleanInside) {
26967           stream.lineStart();
26968           interpolate(null, null, 1, stream);
26969           stream.lineEnd();
26970         }
26971         if (visible) {
26972           clipPolygon(segments, compareIntersection, startInside, interpolate, stream);
26973         }
26974         stream.polygonEnd();
26975       }
26976       activeStream = stream, segments = polygon = ring = null;
26977     }
26978
26979     function lineStart() {
26980       clipStream.point = linePoint;
26981       if (polygon) polygon.push(ring = []);
26982       first = true;
26983       v_ = false;
26984       x_ = y_ = NaN;
26985     }
26986
26987     // TODO rather than special-case polygons, simply handle them separately.
26988     // Ideally, coincident intersection points should be jittered to avoid
26989     // clipping issues.
26990     function lineEnd() {
26991       if (segments) {
26992         linePoint(x__, y__);
26993         if (v__ && v_) bufferStream.rejoin();
26994         segments.push(bufferStream.result());
26995       }
26996       clipStream.point = point;
26997       if (v_) activeStream.lineEnd();
26998     }
26999
27000     function linePoint(x, y) {
27001       var v = visible(x, y);
27002       if (polygon) ring.push([x, y]);
27003       if (first) {
27004         x__ = x, y__ = y, v__ = v;
27005         first = false;
27006         if (v) {
27007           activeStream.lineStart();
27008           activeStream.point(x, y);
27009         }
27010       } else {
27011         if (v && v_) activeStream.point(x, y);
27012         else {
27013           var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
27014               b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
27015           if (clipLine(a, b, x0, y0, x1, y1)) {
27016             if (!v_) {
27017               activeStream.lineStart();
27018               activeStream.point(a[0], a[1]);
27019             }
27020             activeStream.point(b[0], b[1]);
27021             if (!v) activeStream.lineEnd();
27022             clean = false;
27023           } else if (v) {
27024             activeStream.lineStart();
27025             activeStream.point(x, y);
27026             clean = false;
27027           }
27028         }
27029       }
27030       x_ = x, y_ = y, v_ = v;
27031     }
27032
27033     return clipStream;
27034   };
27035 }
27036
27037 var extent$1 = function() {
27038   var x0 = 0,
27039       y0 = 0,
27040       x1 = 960,
27041       y1 = 500,
27042       cache,
27043       cacheStream,
27044       clip;
27045
27046   return clip = {
27047     stream: function(stream) {
27048       return cache && cacheStream === stream ? cache : cache = clipExtent(x0, y0, x1, y1)(cacheStream = stream);
27049     },
27050     extent: function(_) {
27051       return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], cache = cacheStream = null, clip) : [[x0, y0], [x1, y1]];
27052     }
27053   };
27054 };
27055
27056 var sum$1 = adder();
27057
27058 var polygonContains = function(polygon, point) {
27059   var lambda = point[0],
27060       phi = point[1],
27061       normal = [sin$1(lambda), -cos$1(lambda), 0],
27062       angle = 0,
27063       winding = 0;
27064
27065   sum$1.reset();
27066
27067   for (var i = 0, n = polygon.length; i < n; ++i) {
27068     if (!(m = (ring = polygon[i]).length)) continue;
27069     var ring,
27070         m,
27071         point0 = ring[m - 1],
27072         lambda0 = point0[0],
27073         phi0 = point0[1] / 2 + quarterPi,
27074         sinPhi0 = sin$1(phi0),
27075         cosPhi0 = cos$1(phi0);
27076
27077     for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
27078       var point1 = ring[j],
27079           lambda1 = point1[0],
27080           phi1 = point1[1] / 2 + quarterPi,
27081           sinPhi1 = sin$1(phi1),
27082           cosPhi1 = cos$1(phi1),
27083           delta = lambda1 - lambda0,
27084           sign$$1 = delta >= 0 ? 1 : -1,
27085           absDelta = sign$$1 * delta,
27086           antimeridian = absDelta > pi$3,
27087           k = sinPhi0 * sinPhi1;
27088
27089       sum$1.add(atan2(k * sign$$1 * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta)));
27090       angle += antimeridian ? delta + sign$$1 * tau$3 : delta;
27091
27092       // Are the longitudes either side of the point’s meridian (lambda),
27093       // and are the latitudes smaller than the parallel (phi)?
27094       if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
27095         var arc = cartesianCross(cartesian(point0), cartesian(point1));
27096         cartesianNormalizeInPlace(arc);
27097         var intersection = cartesianCross(normal, arc);
27098         cartesianNormalizeInPlace(intersection);
27099         var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
27100         if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
27101           winding += antimeridian ^ delta >= 0 ? 1 : -1;
27102         }
27103       }
27104     }
27105   }
27106
27107   // First, determine whether the South pole is inside or outside:
27108   //
27109   // It is inside if:
27110   // * the polygon winds around it in a clockwise direction.
27111   // * the polygon does not (cumulatively) wind around it, but has a negative
27112   //   (counter-clockwise) area.
27113   //
27114   // Second, count the (signed) number of times a segment crosses a lambda
27115   // from the point to the South pole.  If it is zero, then the point is the
27116   // same side as the South pole.
27117
27118   return (angle < -epsilon$2 || angle < epsilon$2 && sum$1 < -epsilon$2) ^ (winding & 1);
27119 };
27120
27121 var lengthSum = adder();
27122 var lambda0$2;
27123 var sinPhi0$1;
27124 var cosPhi0$1;
27125
27126 var lengthStream = {
27127   sphere: noop$1,
27128   point: noop$1,
27129   lineStart: lengthLineStart,
27130   lineEnd: noop$1,
27131   polygonStart: noop$1,
27132   polygonEnd: noop$1
27133 };
27134
27135 function lengthLineStart() {
27136   lengthStream.point = lengthPointFirst;
27137   lengthStream.lineEnd = lengthLineEnd;
27138 }
27139
27140 function lengthLineEnd() {
27141   lengthStream.point = lengthStream.lineEnd = noop$1;
27142 }
27143
27144 function lengthPointFirst(lambda, phi) {
27145   lambda *= radians, phi *= radians;
27146   lambda0$2 = lambda, sinPhi0$1 = sin$1(phi), cosPhi0$1 = cos$1(phi);
27147   lengthStream.point = lengthPoint;
27148 }
27149
27150 function lengthPoint(lambda, phi) {
27151   lambda *= radians, phi *= radians;
27152   var sinPhi = sin$1(phi),
27153       cosPhi = cos$1(phi),
27154       delta = abs(lambda - lambda0$2),
27155       cosDelta = cos$1(delta),
27156       sinDelta = sin$1(delta),
27157       x = cosPhi * sinDelta,
27158       y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
27159       z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
27160   lengthSum.add(atan2(sqrt(x * x + y * y), z));
27161   lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
27162 }
27163
27164 var d3GeoLength = function(object) {
27165   lengthSum.reset();
27166   geoStream(object, lengthStream);
27167   return +lengthSum;
27168 };
27169
27170 var coordinates = [null, null];
27171 var object$1 = {type: "LineString", coordinates: coordinates};
27172
27173 var distance = function(a, b) {
27174   coordinates[0] = a;
27175   coordinates[1] = b;
27176   return d3GeoLength(object$1);
27177 };
27178
27179 var containsObjectType = {
27180   Feature: function(object, point) {
27181     return containsGeometry(object.geometry, point);
27182   },
27183   FeatureCollection: function(object, point) {
27184     var features = object.features, i = -1, n = features.length;
27185     while (++i < n) if (containsGeometry(features[i].geometry, point)) return true;
27186     return false;
27187   }
27188 };
27189
27190 var containsGeometryType = {
27191   Sphere: function() {
27192     return true;
27193   },
27194   Point: function(object, point) {
27195     return containsPoint(object.coordinates, point);
27196   },
27197   MultiPoint: function(object, point) {
27198     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27199     while (++i < n) if (containsPoint(coordinates[i], point)) return true;
27200     return false;
27201   },
27202   LineString: function(object, point) {
27203     return containsLine(object.coordinates, point);
27204   },
27205   MultiLineString: function(object, point) {
27206     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27207     while (++i < n) if (containsLine(coordinates[i], point)) return true;
27208     return false;
27209   },
27210   Polygon: function(object, point) {
27211     return containsPolygon(object.coordinates, point);
27212   },
27213   MultiPolygon: function(object, point) {
27214     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27215     while (++i < n) if (containsPolygon(coordinates[i], point)) return true;
27216     return false;
27217   },
27218   GeometryCollection: function(object, point) {
27219     var geometries = object.geometries, i = -1, n = geometries.length;
27220     while (++i < n) if (containsGeometry(geometries[i], point)) return true;
27221     return false;
27222   }
27223 };
27224
27225 function containsGeometry(geometry, point) {
27226   return geometry && containsGeometryType.hasOwnProperty(geometry.type)
27227       ? containsGeometryType[geometry.type](geometry, point)
27228       : false;
27229 }
27230
27231 function containsPoint(coordinates, point) {
27232   return distance(coordinates, point) === 0;
27233 }
27234
27235 function containsLine(coordinates, point) {
27236   var ab = distance(coordinates[0], coordinates[1]),
27237       ao = distance(coordinates[0], point),
27238       ob = distance(point, coordinates[1]);
27239   return ao + ob <= ab + epsilon$2;
27240 }
27241
27242 function containsPolygon(coordinates, point) {
27243   return !!polygonContains(coordinates.map(ringRadians), pointRadians(point));
27244 }
27245
27246 function ringRadians(ring) {
27247   return ring = ring.map(pointRadians), ring.pop(), ring;
27248 }
27249
27250 function pointRadians(point) {
27251   return [point[0] * radians, point[1] * radians];
27252 }
27253
27254 var contains = function(object, point) {
27255   return (object && containsObjectType.hasOwnProperty(object.type)
27256       ? containsObjectType[object.type]
27257       : containsGeometry)(object, point);
27258 };
27259
27260 function graticuleX(y0, y1, dy) {
27261   var y = sequence(y0, y1 - epsilon$2, dy).concat(y1);
27262   return function(x) { return y.map(function(y) { return [x, y]; }); };
27263 }
27264
27265 function graticuleY(x0, x1, dx) {
27266   var x = sequence(x0, x1 - epsilon$2, dx).concat(x1);
27267   return function(y) { return x.map(function(x) { return [x, y]; }); };
27268 }
27269
27270 function graticule() {
27271   var x1, x0, X1, X0,
27272       y1, y0, Y1, Y0,
27273       dx = 10, dy = dx, DX = 90, DY = 360,
27274       x, y, X, Y,
27275       precision = 2.5;
27276
27277   function graticule() {
27278     return {type: "MultiLineString", coordinates: lines()};
27279   }
27280
27281   function lines() {
27282     return sequence(ceil(X0 / DX) * DX, X1, DX).map(X)
27283         .concat(sequence(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
27284         .concat(sequence(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs(x % DX) > epsilon$2; }).map(x))
27285         .concat(sequence(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > epsilon$2; }).map(y));
27286   }
27287
27288   graticule.lines = function() {
27289     return lines().map(function(coordinates) { return {type: "LineString", coordinates: coordinates}; });
27290   };
27291
27292   graticule.outline = function() {
27293     return {
27294       type: "Polygon",
27295       coordinates: [
27296         X(X0).concat(
27297         Y(Y1).slice(1),
27298         X(X1).reverse().slice(1),
27299         Y(Y0).reverse().slice(1))
27300       ]
27301     };
27302   };
27303
27304   graticule.extent = function(_) {
27305     if (!arguments.length) return graticule.extentMinor();
27306     return graticule.extentMajor(_).extentMinor(_);
27307   };
27308
27309   graticule.extentMajor = function(_) {
27310     if (!arguments.length) return [[X0, Y0], [X1, Y1]];
27311     X0 = +_[0][0], X1 = +_[1][0];
27312     Y0 = +_[0][1], Y1 = +_[1][1];
27313     if (X0 > X1) _ = X0, X0 = X1, X1 = _;
27314     if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
27315     return graticule.precision(precision);
27316   };
27317
27318   graticule.extentMinor = function(_) {
27319     if (!arguments.length) return [[x0, y0], [x1, y1]];
27320     x0 = +_[0][0], x1 = +_[1][0];
27321     y0 = +_[0][1], y1 = +_[1][1];
27322     if (x0 > x1) _ = x0, x0 = x1, x1 = _;
27323     if (y0 > y1) _ = y0, y0 = y1, y1 = _;
27324     return graticule.precision(precision);
27325   };
27326
27327   graticule.step = function(_) {
27328     if (!arguments.length) return graticule.stepMinor();
27329     return graticule.stepMajor(_).stepMinor(_);
27330   };
27331
27332   graticule.stepMajor = function(_) {
27333     if (!arguments.length) return [DX, DY];
27334     DX = +_[0], DY = +_[1];
27335     return graticule;
27336   };
27337
27338   graticule.stepMinor = function(_) {
27339     if (!arguments.length) return [dx, dy];
27340     dx = +_[0], dy = +_[1];
27341     return graticule;
27342   };
27343
27344   graticule.precision = function(_) {
27345     if (!arguments.length) return precision;
27346     precision = +_;
27347     x = graticuleX(y0, y1, 90);
27348     y = graticuleY(x0, x1, precision);
27349     X = graticuleX(Y0, Y1, 90);
27350     Y = graticuleY(X0, X1, precision);
27351     return graticule;
27352   };
27353
27354   return graticule
27355       .extentMajor([[-180, -90 + epsilon$2], [180, 90 - epsilon$2]])
27356       .extentMinor([[-180, -80 - epsilon$2], [180, 80 + epsilon$2]]);
27357 }
27358
27359 function graticule10() {
27360   return graticule()();
27361 }
27362
27363 var interpolate$1 = function(a, b) {
27364   var x0 = a[0] * radians,
27365       y0 = a[1] * radians,
27366       x1 = b[0] * radians,
27367       y1 = b[1] * radians,
27368       cy0 = cos$1(y0),
27369       sy0 = sin$1(y0),
27370       cy1 = cos$1(y1),
27371       sy1 = sin$1(y1),
27372       kx0 = cy0 * cos$1(x0),
27373       ky0 = cy0 * sin$1(x0),
27374       kx1 = cy1 * cos$1(x1),
27375       ky1 = cy1 * sin$1(x1),
27376       d = 2 * asin(sqrt(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
27377       k = sin$1(d);
27378
27379   var interpolate = d ? function(t) {
27380     var B = sin$1(t *= d) / k,
27381         A = sin$1(d - t) / k,
27382         x = A * kx0 + B * kx1,
27383         y = A * ky0 + B * ky1,
27384         z = A * sy0 + B * sy1;
27385     return [
27386       atan2(y, x) * degrees$1,
27387       atan2(z, sqrt(x * x + y * y)) * degrees$1
27388     ];
27389   } : function() {
27390     return [x0 * degrees$1, y0 * degrees$1];
27391   };
27392
27393   interpolate.distance = d;
27394
27395   return interpolate;
27396 };
27397
27398 var identity$4 = function(x) {
27399   return x;
27400 };
27401
27402 var areaSum$1 = adder();
27403 var areaRingSum$1 = adder();
27404 var x00;
27405 var y00;
27406 var x0$1;
27407 var y0$1;
27408
27409 var areaStream$1 = {
27410   point: noop$1,
27411   lineStart: noop$1,
27412   lineEnd: noop$1,
27413   polygonStart: function() {
27414     areaStream$1.lineStart = areaRingStart$1;
27415     areaStream$1.lineEnd = areaRingEnd$1;
27416   },
27417   polygonEnd: function() {
27418     areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop$1;
27419     areaSum$1.add(abs(areaRingSum$1));
27420     areaRingSum$1.reset();
27421   },
27422   result: function() {
27423     var area = areaSum$1 / 2;
27424     areaSum$1.reset();
27425     return area;
27426   }
27427 };
27428
27429 function areaRingStart$1() {
27430   areaStream$1.point = areaPointFirst$1;
27431 }
27432
27433 function areaPointFirst$1(x, y) {
27434   areaStream$1.point = areaPoint$1;
27435   x00 = x0$1 = x, y00 = y0$1 = y;
27436 }
27437
27438 function areaPoint$1(x, y) {
27439   areaRingSum$1.add(y0$1 * x - x0$1 * y);
27440   x0$1 = x, y0$1 = y;
27441 }
27442
27443 function areaRingEnd$1() {
27444   areaPoint$1(x00, y00);
27445 }
27446
27447 var x0$2 = Infinity;
27448 var y0$2 = x0$2;
27449 var x1 = -x0$2;
27450 var y1 = x1;
27451
27452 var boundsStream$1 = {
27453   point: boundsPoint$1,
27454   lineStart: noop$1,
27455   lineEnd: noop$1,
27456   polygonStart: noop$1,
27457   polygonEnd: noop$1,
27458   result: function() {
27459     var bounds = [[x0$2, y0$2], [x1, y1]];
27460     x1 = y1 = -(y0$2 = x0$2 = Infinity);
27461     return bounds;
27462   }
27463 };
27464
27465 function boundsPoint$1(x, y) {
27466   if (x < x0$2) x0$2 = x;
27467   if (x > x1) x1 = x;
27468   if (y < y0$2) y0$2 = y;
27469   if (y > y1) y1 = y;
27470 }
27471
27472 // TODO Enforce positive area for exterior, negative area for interior?
27473
27474 var X0$1 = 0;
27475 var Y0$1 = 0;
27476 var Z0$1 = 0;
27477 var X1$1 = 0;
27478 var Y1$1 = 0;
27479 var Z1$1 = 0;
27480 var X2$1 = 0;
27481 var Y2$1 = 0;
27482 var Z2$1 = 0;
27483 var x00$1;
27484 var y00$1;
27485 var x0$3;
27486 var y0$3;
27487
27488 var centroidStream$1 = {
27489   point: centroidPoint$1,
27490   lineStart: centroidLineStart$1,
27491   lineEnd: centroidLineEnd$1,
27492   polygonStart: function() {
27493     centroidStream$1.lineStart = centroidRingStart$1;
27494     centroidStream$1.lineEnd = centroidRingEnd$1;
27495   },
27496   polygonEnd: function() {
27497     centroidStream$1.point = centroidPoint$1;
27498     centroidStream$1.lineStart = centroidLineStart$1;
27499     centroidStream$1.lineEnd = centroidLineEnd$1;
27500   },
27501   result: function() {
27502     var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1]
27503         : Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1]
27504         : Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1]
27505         : [NaN, NaN];
27506     X0$1 = Y0$1 = Z0$1 =
27507     X1$1 = Y1$1 = Z1$1 =
27508     X2$1 = Y2$1 = Z2$1 = 0;
27509     return centroid;
27510   }
27511 };
27512
27513 function centroidPoint$1(x, y) {
27514   X0$1 += x;
27515   Y0$1 += y;
27516   ++Z0$1;
27517 }
27518
27519 function centroidLineStart$1() {
27520   centroidStream$1.point = centroidPointFirstLine;
27521 }
27522
27523 function centroidPointFirstLine(x, y) {
27524   centroidStream$1.point = centroidPointLine;
27525   centroidPoint$1(x0$3 = x, y0$3 = y);
27526 }
27527
27528 function centroidPointLine(x, y) {
27529   var dx = x - x0$3, dy = y - y0$3, z = sqrt(dx * dx + dy * dy);
27530   X1$1 += z * (x0$3 + x) / 2;
27531   Y1$1 += z * (y0$3 + y) / 2;
27532   Z1$1 += z;
27533   centroidPoint$1(x0$3 = x, y0$3 = y);
27534 }
27535
27536 function centroidLineEnd$1() {
27537   centroidStream$1.point = centroidPoint$1;
27538 }
27539
27540 function centroidRingStart$1() {
27541   centroidStream$1.point = centroidPointFirstRing;
27542 }
27543
27544 function centroidRingEnd$1() {
27545   centroidPointRing(x00$1, y00$1);
27546 }
27547
27548 function centroidPointFirstRing(x, y) {
27549   centroidStream$1.point = centroidPointRing;
27550   centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
27551 }
27552
27553 function centroidPointRing(x, y) {
27554   var dx = x - x0$3,
27555       dy = y - y0$3,
27556       z = sqrt(dx * dx + dy * dy);
27557
27558   X1$1 += z * (x0$3 + x) / 2;
27559   Y1$1 += z * (y0$3 + y) / 2;
27560   Z1$1 += z;
27561
27562   z = y0$3 * x - x0$3 * y;
27563   X2$1 += z * (x0$3 + x);
27564   Y2$1 += z * (y0$3 + y);
27565   Z2$1 += z * 3;
27566   centroidPoint$1(x0$3 = x, y0$3 = y);
27567 }
27568
27569 function PathContext(context) {
27570   this._context = context;
27571 }
27572
27573 PathContext.prototype = {
27574   _radius: 4.5,
27575   pointRadius: function(_) {
27576     return this._radius = _, this;
27577   },
27578   polygonStart: function() {
27579     this._line = 0;
27580   },
27581   polygonEnd: function() {
27582     this._line = NaN;
27583   },
27584   lineStart: function() {
27585     this._point = 0;
27586   },
27587   lineEnd: function() {
27588     if (this._line === 0) this._context.closePath();
27589     this._point = NaN;
27590   },
27591   point: function(x, y) {
27592     switch (this._point) {
27593       case 0: {
27594         this._context.moveTo(x, y);
27595         this._point = 1;
27596         break;
27597       }
27598       case 1: {
27599         this._context.lineTo(x, y);
27600         break;
27601       }
27602       default: {
27603         this._context.moveTo(x + this._radius, y);
27604         this._context.arc(x, y, this._radius, 0, tau$3);
27605         break;
27606       }
27607     }
27608   },
27609   result: noop$1
27610 };
27611
27612 var lengthSum$1 = adder();
27613 var lengthRing;
27614 var x00$2;
27615 var y00$2;
27616 var x0$4;
27617 var y0$4;
27618
27619 var lengthStream$1 = {
27620   point: noop$1,
27621   lineStart: function() {
27622     lengthStream$1.point = lengthPointFirst$1;
27623   },
27624   lineEnd: function() {
27625     if (lengthRing) lengthPoint$1(x00$2, y00$2);
27626     lengthStream$1.point = noop$1;
27627   },
27628   polygonStart: function() {
27629     lengthRing = true;
27630   },
27631   polygonEnd: function() {
27632     lengthRing = null;
27633   },
27634   result: function() {
27635     var length = +lengthSum$1;
27636     lengthSum$1.reset();
27637     return length;
27638   }
27639 };
27640
27641 function lengthPointFirst$1(x, y) {
27642   lengthStream$1.point = lengthPoint$1;
27643   x00$2 = x0$4 = x, y00$2 = y0$4 = y;
27644 }
27645
27646 function lengthPoint$1(x, y) {
27647   x0$4 -= x, y0$4 -= y;
27648   lengthSum$1.add(sqrt(x0$4 * x0$4 + y0$4 * y0$4));
27649   x0$4 = x, y0$4 = y;
27650 }
27651
27652 function PathString() {
27653   this._string = [];
27654 }
27655
27656 PathString.prototype = {
27657   _radius: 4.5,
27658   _circle: circle$1(4.5),
27659   pointRadius: function(_) {
27660     if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
27661     return this;
27662   },
27663   polygonStart: function() {
27664     this._line = 0;
27665   },
27666   polygonEnd: function() {
27667     this._line = NaN;
27668   },
27669   lineStart: function() {
27670     this._point = 0;
27671   },
27672   lineEnd: function() {
27673     if (this._line === 0) this._string.push("Z");
27674     this._point = NaN;
27675   },
27676   point: function(x, y) {
27677     switch (this._point) {
27678       case 0: {
27679         this._string.push("M", x, ",", y);
27680         this._point = 1;
27681         break;
27682       }
27683       case 1: {
27684         this._string.push("L", x, ",", y);
27685         break;
27686       }
27687       default: {
27688         if (this._circle == null) this._circle = circle$1(this._radius);
27689         this._string.push("M", x, ",", y, this._circle);
27690         break;
27691       }
27692     }
27693   },
27694   result: function() {
27695     if (this._string.length) {
27696       var result = this._string.join("");
27697       this._string = [];
27698       return result;
27699     } else {
27700       return null;
27701     }
27702   }
27703 };
27704
27705 function circle$1(radius) {
27706   return "m0," + radius
27707       + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
27708       + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
27709       + "z";
27710 }
27711
27712 var index$4 = function(projection, context) {
27713   var pointRadius = 4.5,
27714       projectionStream,
27715       contextStream;
27716
27717   function path(object) {
27718     if (object) {
27719       if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
27720       geoStream(object, projectionStream(contextStream));
27721     }
27722     return contextStream.result();
27723   }
27724
27725   path.area = function(object) {
27726     geoStream(object, projectionStream(areaStream$1));
27727     return areaStream$1.result();
27728   };
27729
27730   path.measure = function(object) {
27731     geoStream(object, projectionStream(lengthStream$1));
27732     return lengthStream$1.result();
27733   };
27734
27735   path.bounds = function(object) {
27736     geoStream(object, projectionStream(boundsStream$1));
27737     return boundsStream$1.result();
27738   };
27739
27740   path.centroid = function(object) {
27741     geoStream(object, projectionStream(centroidStream$1));
27742     return centroidStream$1.result();
27743   };
27744
27745   path.projection = function(_) {
27746     return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$4) : (projection = _).stream, path) : projection;
27747   };
27748
27749   path.context = function(_) {
27750     if (!arguments.length) return context;
27751     contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _);
27752     if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
27753     return path;
27754   };
27755
27756   path.pointRadius = function(_) {
27757     if (!arguments.length) return pointRadius;
27758     pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
27759     return path;
27760   };
27761
27762   return path.projection(projection).context(context);
27763 };
27764
27765 var clip = function(pointVisible, clipLine, interpolate, start) {
27766   return function(rotate, sink) {
27767     var line = clipLine(sink),
27768         rotatedStart = rotate.invert(start[0], start[1]),
27769         ringBuffer = clipBuffer(),
27770         ringSink = clipLine(ringBuffer),
27771         polygonStarted = false,
27772         polygon,
27773         segments,
27774         ring;
27775
27776     var clip = {
27777       point: point,
27778       lineStart: lineStart,
27779       lineEnd: lineEnd,
27780       polygonStart: function() {
27781         clip.point = pointRing;
27782         clip.lineStart = ringStart;
27783         clip.lineEnd = ringEnd;
27784         segments = [];
27785         polygon = [];
27786       },
27787       polygonEnd: function() {
27788         clip.point = point;
27789         clip.lineStart = lineStart;
27790         clip.lineEnd = lineEnd;
27791         segments = merge(segments);
27792         var startInside = polygonContains(polygon, rotatedStart);
27793         if (segments.length) {
27794           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27795           clipPolygon(segments, compareIntersection, startInside, interpolate, sink);
27796         } else if (startInside) {
27797           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27798           sink.lineStart();
27799           interpolate(null, null, 1, sink);
27800           sink.lineEnd();
27801         }
27802         if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
27803         segments = polygon = null;
27804       },
27805       sphere: function() {
27806         sink.polygonStart();
27807         sink.lineStart();
27808         interpolate(null, null, 1, sink);
27809         sink.lineEnd();
27810         sink.polygonEnd();
27811       }
27812     };
27813
27814     function point(lambda, phi) {
27815       var point = rotate(lambda, phi);
27816       if (pointVisible(lambda = point[0], phi = point[1])) sink.point(lambda, phi);
27817     }
27818
27819     function pointLine(lambda, phi) {
27820       var point = rotate(lambda, phi);
27821       line.point(point[0], point[1]);
27822     }
27823
27824     function lineStart() {
27825       clip.point = pointLine;
27826       line.lineStart();
27827     }
27828
27829     function lineEnd() {
27830       clip.point = point;
27831       line.lineEnd();
27832     }
27833
27834     function pointRing(lambda, phi) {
27835       ring.push([lambda, phi]);
27836       var point = rotate(lambda, phi);
27837       ringSink.point(point[0], point[1]);
27838     }
27839
27840     function ringStart() {
27841       ringSink.lineStart();
27842       ring = [];
27843     }
27844
27845     function ringEnd() {
27846       pointRing(ring[0][0], ring[0][1]);
27847       ringSink.lineEnd();
27848
27849       var clean = ringSink.clean(),
27850           ringSegments = ringBuffer.result(),
27851           i, n = ringSegments.length, m,
27852           segment,
27853           point;
27854
27855       ring.pop();
27856       polygon.push(ring);
27857       ring = null;
27858
27859       if (!n) return;
27860
27861       // No intersections.
27862       if (clean & 1) {
27863         segment = ringSegments[0];
27864         if ((m = segment.length - 1) > 0) {
27865           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27866           sink.lineStart();
27867           for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]);
27868           sink.lineEnd();
27869         }
27870         return;
27871       }
27872
27873       // Rejoin connected segments.
27874       // TODO reuse ringBuffer.rejoin()?
27875       if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
27876
27877       segments.push(ringSegments.filter(validSegment));
27878     }
27879
27880     return clip;
27881   };
27882 };
27883
27884 function validSegment(segment) {
27885   return segment.length > 1;
27886 }
27887
27888 // Intersections are sorted along the clip edge. For both antimeridian cutting
27889 // and circle clipping, the same comparison is used.
27890 function compareIntersection(a, b) {
27891   return ((a = a.x)[0] < 0 ? a[1] - halfPi$2 - epsilon$2 : halfPi$2 - a[1])
27892        - ((b = b.x)[0] < 0 ? b[1] - halfPi$2 - epsilon$2 : halfPi$2 - b[1]);
27893 }
27894
27895 var clipAntimeridian = clip(
27896   function() { return true; },
27897   clipAntimeridianLine,
27898   clipAntimeridianInterpolate,
27899   [-pi$3, -halfPi$2]
27900 );
27901
27902 // Takes a line and cuts into visible segments. Return values: 0 - there were
27903 // intersections or the line was empty; 1 - no intersections; 2 - there were
27904 // intersections, and the first and last segments should be rejoined.
27905 function clipAntimeridianLine(stream) {
27906   var lambda0 = NaN,
27907       phi0 = NaN,
27908       sign0 = NaN,
27909       clean; // no intersections
27910
27911   return {
27912     lineStart: function() {
27913       stream.lineStart();
27914       clean = 1;
27915     },
27916     point: function(lambda1, phi1) {
27917       var sign1 = lambda1 > 0 ? pi$3 : -pi$3,
27918           delta = abs(lambda1 - lambda0);
27919       if (abs(delta - pi$3) < epsilon$2) { // line crosses a pole
27920         stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$2 : -halfPi$2);
27921         stream.point(sign0, phi0);
27922         stream.lineEnd();
27923         stream.lineStart();
27924         stream.point(sign1, phi0);
27925         stream.point(lambda1, phi0);
27926         clean = 0;
27927       } else if (sign0 !== sign1 && delta >= pi$3) { // line crosses antimeridian
27928         if (abs(lambda0 - sign0) < epsilon$2) lambda0 -= sign0 * epsilon$2; // handle degeneracies
27929         if (abs(lambda1 - sign1) < epsilon$2) lambda1 -= sign1 * epsilon$2;
27930         phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
27931         stream.point(sign0, phi0);
27932         stream.lineEnd();
27933         stream.lineStart();
27934         stream.point(sign1, phi0);
27935         clean = 0;
27936       }
27937       stream.point(lambda0 = lambda1, phi0 = phi1);
27938       sign0 = sign1;
27939     },
27940     lineEnd: function() {
27941       stream.lineEnd();
27942       lambda0 = phi0 = NaN;
27943     },
27944     clean: function() {
27945       return 2 - clean; // if intersections, rejoin first and last segments
27946     }
27947   };
27948 }
27949
27950 function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
27951   var cosPhi0,
27952       cosPhi1,
27953       sinLambda0Lambda1 = sin$1(lambda0 - lambda1);
27954   return abs(sinLambda0Lambda1) > epsilon$2
27955       ? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1)
27956           - sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0))
27957           / (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
27958       : (phi0 + phi1) / 2;
27959 }
27960
27961 function clipAntimeridianInterpolate(from, to, direction, stream) {
27962   var phi;
27963   if (from == null) {
27964     phi = direction * halfPi$2;
27965     stream.point(-pi$3, phi);
27966     stream.point(0, phi);
27967     stream.point(pi$3, phi);
27968     stream.point(pi$3, 0);
27969     stream.point(pi$3, -phi);
27970     stream.point(0, -phi);
27971     stream.point(-pi$3, -phi);
27972     stream.point(-pi$3, 0);
27973     stream.point(-pi$3, phi);
27974   } else if (abs(from[0] - to[0]) > epsilon$2) {
27975     var lambda = from[0] < to[0] ? pi$3 : -pi$3;
27976     phi = direction * lambda / 2;
27977     stream.point(-lambda, phi);
27978     stream.point(0, phi);
27979     stream.point(lambda, phi);
27980   } else {
27981     stream.point(to[0], to[1]);
27982   }
27983 }
27984
27985 var clipCircle = function(radius, delta) {
27986   var cr = cos$1(radius),
27987       smallRadius = cr > 0,
27988       notHemisphere = abs(cr) > epsilon$2; // TODO optimise for this common case
27989
27990   function interpolate(from, to, direction, stream) {
27991     circleStream(stream, radius, delta, direction, from, to);
27992   }
27993
27994   function visible(lambda, phi) {
27995     return cos$1(lambda) * cos$1(phi) > cr;
27996   }
27997
27998   // Takes a line and cuts into visible segments. Return values used for polygon
27999   // clipping: 0 - there were intersections or the line was empty; 1 - no
28000   // intersections 2 - there were intersections, and the first and last segments
28001   // should be rejoined.
28002   function clipLine(stream) {
28003     var point0, // previous point
28004         c0, // code for previous point
28005         v0, // visibility of previous point
28006         v00, // visibility of first point
28007         clean; // no intersections
28008     return {
28009       lineStart: function() {
28010         v00 = v0 = false;
28011         clean = 1;
28012       },
28013       point: function(lambda, phi) {
28014         var point1 = [lambda, phi],
28015             point2,
28016             v = visible(lambda, phi),
28017             c = smallRadius
28018               ? v ? 0 : code(lambda, phi)
28019               : v ? code(lambda + (lambda < 0 ? pi$3 : -pi$3), phi) : 0;
28020         if (!point0 && (v00 = v0 = v)) stream.lineStart();
28021         // Handle degeneracies.
28022         // TODO ignore if not clipping polygons.
28023         if (v !== v0) {
28024           point2 = intersect(point0, point1);
28025           if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) {
28026             point1[0] += epsilon$2;
28027             point1[1] += epsilon$2;
28028             v = visible(point1[0], point1[1]);
28029           }
28030         }
28031         if (v !== v0) {
28032           clean = 0;
28033           if (v) {
28034             // outside going in
28035             stream.lineStart();
28036             point2 = intersect(point1, point0);
28037             stream.point(point2[0], point2[1]);
28038           } else {
28039             // inside going out
28040             point2 = intersect(point0, point1);
28041             stream.point(point2[0], point2[1]);
28042             stream.lineEnd();
28043           }
28044           point0 = point2;
28045         } else if (notHemisphere && point0 && smallRadius ^ v) {
28046           var t;
28047           // If the codes for two points are different, or are both zero,
28048           // and there this segment intersects with the small circle.
28049           if (!(c & c0) && (t = intersect(point1, point0, true))) {
28050             clean = 0;
28051             if (smallRadius) {
28052               stream.lineStart();
28053               stream.point(t[0][0], t[0][1]);
28054               stream.point(t[1][0], t[1][1]);
28055               stream.lineEnd();
28056             } else {
28057               stream.point(t[1][0], t[1][1]);
28058               stream.lineEnd();
28059               stream.lineStart();
28060               stream.point(t[0][0], t[0][1]);
28061             }
28062           }
28063         }
28064         if (v && (!point0 || !pointEqual(point0, point1))) {
28065           stream.point(point1[0], point1[1]);
28066         }
28067         point0 = point1, v0 = v, c0 = c;
28068       },
28069       lineEnd: function() {
28070         if (v0) stream.lineEnd();
28071         point0 = null;
28072       },
28073       // Rejoin first and last segments if there were intersections and the first
28074       // and last points were visible.
28075       clean: function() {
28076         return clean | ((v00 && v0) << 1);
28077       }
28078     };
28079   }
28080
28081   // Intersects the great circle between a and b with the clip circle.
28082   function intersect(a, b, two) {
28083     var pa = cartesian(a),
28084         pb = cartesian(b);
28085
28086     // We have two planes, n1.p = d1 and n2.p = d2.
28087     // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
28088     var n1 = [1, 0, 0], // normal
28089         n2 = cartesianCross(pa, pb),
28090         n2n2 = cartesianDot(n2, n2),
28091         n1n2 = n2[0], // cartesianDot(n1, n2),
28092         determinant = n2n2 - n1n2 * n1n2;
28093
28094     // Two polar points.
28095     if (!determinant) return !two && a;
28096
28097     var c1 =  cr * n2n2 / determinant,
28098         c2 = -cr * n1n2 / determinant,
28099         n1xn2 = cartesianCross(n1, n2),
28100         A = cartesianScale(n1, c1),
28101         B = cartesianScale(n2, c2);
28102     cartesianAddInPlace(A, B);
28103
28104     // Solve |p(t)|^2 = 1.
28105     var u = n1xn2,
28106         w = cartesianDot(A, u),
28107         uu = cartesianDot(u, u),
28108         t2 = w * w - uu * (cartesianDot(A, A) - 1);
28109
28110     if (t2 < 0) return;
28111
28112     var t = sqrt(t2),
28113         q = cartesianScale(u, (-w - t) / uu);
28114     cartesianAddInPlace(q, A);
28115     q = spherical(q);
28116
28117     if (!two) return q;
28118
28119     // Two intersection points.
28120     var lambda0 = a[0],
28121         lambda1 = b[0],
28122         phi0 = a[1],
28123         phi1 = b[1],
28124         z;
28125
28126     if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
28127
28128     var delta = lambda1 - lambda0,
28129         polar = abs(delta - pi$3) < epsilon$2,
28130         meridian = polar || delta < epsilon$2;
28131
28132     if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
28133
28134     // Check that the first point is between a and b.
28135     if (meridian
28136         ? polar
28137           ? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon$2 ? phi0 : phi1)
28138           : phi0 <= q[1] && q[1] <= phi1
28139         : delta > pi$3 ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
28140       var q1 = cartesianScale(u, (-w + t) / uu);
28141       cartesianAddInPlace(q1, A);
28142       return [q, spherical(q1)];
28143     }
28144   }
28145
28146   // Generates a 4-bit vector representing the location of a point relative to
28147   // the small circle's bounding box.
28148   function code(lambda, phi) {
28149     var r = smallRadius ? radius : pi$3 - radius,
28150         code = 0;
28151     if (lambda < -r) code |= 1; // left
28152     else if (lambda > r) code |= 2; // right
28153     if (phi < -r) code |= 4; // below
28154     else if (phi > r) code |= 8; // above
28155     return code;
28156   }
28157
28158   return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$3, radius - pi$3]);
28159 };
28160
28161 var transform = function(methods) {
28162   return {
28163     stream: transformer(methods)
28164   };
28165 };
28166
28167 function transformer(methods) {
28168   return function(stream) {
28169     var s = new TransformStream;
28170     for (var key in methods) s[key] = methods[key];
28171     s.stream = stream;
28172     return s;
28173   };
28174 }
28175
28176 function TransformStream() {}
28177
28178 TransformStream.prototype = {
28179   constructor: TransformStream,
28180   point: function(x, y) { this.stream.point(x, y); },
28181   sphere: function() { this.stream.sphere(); },
28182   lineStart: function() { this.stream.lineStart(); },
28183   lineEnd: function() { this.stream.lineEnd(); },
28184   polygonStart: function() { this.stream.polygonStart(); },
28185   polygonEnd: function() { this.stream.polygonEnd(); }
28186 };
28187
28188 function fitExtent(projection, extent, object) {
28189   var w = extent[1][0] - extent[0][0],
28190       h = extent[1][1] - extent[0][1],
28191       clip = projection.clipExtent && projection.clipExtent();
28192
28193   projection
28194       .scale(150)
28195       .translate([0, 0]);
28196
28197   if (clip != null) projection.clipExtent(null);
28198
28199   geoStream(object, projection.stream(boundsStream$1));
28200
28201   var b = boundsStream$1.result(),
28202       k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
28203       x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
28204       y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
28205
28206   if (clip != null) projection.clipExtent(clip);
28207
28208   return projection
28209       .scale(k * 150)
28210       .translate([x, y]);
28211 }
28212
28213 function fitSize(projection, size, object) {
28214   return fitExtent(projection, [[0, 0], size], object);
28215 }
28216
28217 var maxDepth = 16;
28218 var cosMinDistance = cos$1(30 * radians); // cos(minimum angular distance)
28219
28220 var resample = function(project, delta2) {
28221   return +delta2 ? resample$1(project, delta2) : resampleNone(project);
28222 };
28223
28224 function resampleNone(project) {
28225   return transformer({
28226     point: function(x, y) {
28227       x = project(x, y);
28228       this.stream.point(x[0], x[1]);
28229     }
28230   });
28231 }
28232
28233 function resample$1(project, delta2) {
28234
28235   function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
28236     var dx = x1 - x0,
28237         dy = y1 - y0,
28238         d2 = dx * dx + dy * dy;
28239     if (d2 > 4 * delta2 && depth--) {
28240       var a = a0 + a1,
28241           b = b0 + b1,
28242           c = c0 + c1,
28243           m = sqrt(a * a + b * b + c * c),
28244           phi2 = asin(c /= m),
28245           lambda2 = abs(abs(c) - 1) < epsilon$2 || abs(lambda0 - lambda1) < epsilon$2 ? (lambda0 + lambda1) / 2 : atan2(b, a),
28246           p = project(lambda2, phi2),
28247           x2 = p[0],
28248           y2 = p[1],
28249           dx2 = x2 - x0,
28250           dy2 = y2 - y0,
28251           dz = dy * dx2 - dx * dy2;
28252       if (dz * dz / d2 > delta2 // perpendicular projected distance
28253           || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
28254           || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
28255         resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
28256         stream.point(x2, y2);
28257         resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
28258       }
28259     }
28260   }
28261   return function(stream) {
28262     var lambda00, x00, y00, a00, b00, c00, // first point
28263         lambda0, x0, y0, a0, b0, c0; // previous point
28264
28265     var resampleStream = {
28266       point: point,
28267       lineStart: lineStart,
28268       lineEnd: lineEnd,
28269       polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
28270       polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
28271     };
28272
28273     function point(x, y) {
28274       x = project(x, y);
28275       stream.point(x[0], x[1]);
28276     }
28277
28278     function lineStart() {
28279       x0 = NaN;
28280       resampleStream.point = linePoint;
28281       stream.lineStart();
28282     }
28283
28284     function linePoint(lambda, phi) {
28285       var c = cartesian([lambda, phi]), p = project(lambda, phi);
28286       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);
28287       stream.point(x0, y0);
28288     }
28289
28290     function lineEnd() {
28291       resampleStream.point = point;
28292       stream.lineEnd();
28293     }
28294
28295     function ringStart() {
28296       lineStart();
28297       resampleStream.point = ringPoint;
28298       resampleStream.lineEnd = ringEnd;
28299     }
28300
28301     function ringPoint(lambda, phi) {
28302       linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
28303       resampleStream.point = linePoint;
28304     }
28305
28306     function ringEnd() {
28307       resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
28308       resampleStream.lineEnd = lineEnd;
28309       lineEnd();
28310     }
28311
28312     return resampleStream;
28313   };
28314 }
28315
28316 var transformRadians = transformer({
28317   point: function(x, y) {
28318     this.stream.point(x * radians, y * radians);
28319   }
28320 });
28321
28322 function projection(project) {
28323   return projectionMutator(function() { return project; })();
28324 }
28325
28326 function projectionMutator(projectAt) {
28327   var project,
28328       k = 150, // scale
28329       x = 480, y = 250, // translate
28330       dx, dy, lambda = 0, phi = 0, // center
28331       deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate
28332       theta = null, preclip = clipAntimeridian, // clip angle
28333       x0 = null, y0, x1, y1, postclip = identity$4, // clip extent
28334       delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision
28335       cache,
28336       cacheStream;
28337
28338   function projection(point) {
28339     point = projectRotate(point[0] * radians, point[1] * radians);
28340     return [point[0] * k + dx, dy - point[1] * k];
28341   }
28342
28343   function invert(point) {
28344     point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k);
28345     return point && [point[0] * degrees$1, point[1] * degrees$1];
28346   }
28347
28348   function projectTransform(x, y) {
28349     return x = project(x, y), [x[0] * k + dx, dy - x[1] * k];
28350   }
28351
28352   projection.stream = function(stream) {
28353     return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream))));
28354   };
28355
28356   projection.clipAngle = function(_) {
28357     return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
28358   };
28359
28360   projection.clipExtent = function(_) {
28361     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]];
28362   };
28363
28364   projection.scale = function(_) {
28365     return arguments.length ? (k = +_, recenter()) : k;
28366   };
28367
28368   projection.translate = function(_) {
28369     return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
28370   };
28371
28372   projection.center = function(_) {
28373     return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
28374   };
28375
28376   projection.rotate = function(_) {
28377     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];
28378   };
28379
28380   projection.precision = function(_) {
28381     return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
28382   };
28383
28384   projection.fitExtent = function(extent, object) {
28385     return fitExtent(projection, extent, object);
28386   };
28387
28388   projection.fitSize = function(size, object) {
28389     return fitSize(projection, size, object);
28390   };
28391
28392   function recenter() {
28393     projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project);
28394     var center = project(lambda, phi);
28395     dx = x - center[0] * k;
28396     dy = y + center[1] * k;
28397     return reset();
28398   }
28399
28400   function reset() {
28401     cache = cacheStream = null;
28402     return projection;
28403   }
28404
28405   return function() {
28406     project = projectAt.apply(this, arguments);
28407     projection.invert = project.invert && invert;
28408     return recenter();
28409   };
28410 }
28411
28412 function conicProjection(projectAt) {
28413   var phi0 = 0,
28414       phi1 = pi$3 / 3,
28415       m = projectionMutator(projectAt),
28416       p = m(phi0, phi1);
28417
28418   p.parallels = function(_) {
28419     return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees$1, phi1 * degrees$1];
28420   };
28421
28422   return p;
28423 }
28424
28425 function cylindricalEqualAreaRaw(phi0) {
28426   var cosPhi0 = cos$1(phi0);
28427
28428   function forward(lambda, phi) {
28429     return [lambda * cosPhi0, sin$1(phi) / cosPhi0];
28430   }
28431
28432   forward.invert = function(x, y) {
28433     return [x / cosPhi0, asin(y * cosPhi0)];
28434   };
28435
28436   return forward;
28437 }
28438
28439 function conicEqualAreaRaw(y0, y1) {
28440   var sy0 = sin$1(y0), n = (sy0 + sin$1(y1)) / 2;
28441
28442   // Are the parallels symmetrical around the Equator?
28443   if (abs(n) < epsilon$2) return cylindricalEqualAreaRaw(y0);
28444
28445   var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt(c) / n;
28446
28447   function project(x, y) {
28448     var r = sqrt(c - 2 * n * sin$1(y)) / n;
28449     return [r * sin$1(x *= n), r0 - r * cos$1(x)];
28450   }
28451
28452   project.invert = function(x, y) {
28453     var r0y = r0 - y;
28454     return [atan2(x, abs(r0y)) / n * sign(r0y), asin((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
28455   };
28456
28457   return project;
28458 }
28459
28460 var conicEqualArea = function() {
28461   return conicProjection(conicEqualAreaRaw)
28462       .scale(155.424)
28463       .center([0, 33.6442]);
28464 };
28465
28466 var albers = function() {
28467   return conicEqualArea()
28468       .parallels([29.5, 45.5])
28469       .scale(1070)
28470       .translate([480, 250])
28471       .rotate([96, 0])
28472       .center([-0.6, 38.7]);
28473 };
28474
28475 // The projections must have mutually exclusive clip regions on the sphere,
28476 // as this will avoid emitting interleaving lines and polygons.
28477 function multiplex(streams) {
28478   var n = streams.length;
28479   return {
28480     point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); },
28481     sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); },
28482     lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); },
28483     lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); },
28484     polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); },
28485     polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); }
28486   };
28487 }
28488
28489 // A composite projection for the United States, configured by default for
28490 // 960×500. The projection also works quite well at 960×600 if you change the
28491 // scale to 1285 and adjust the translate accordingly. The set of standard
28492 // parallels for each region comes from USGS, which is published here:
28493 // http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
28494 var albersUsa = function() {
28495   var cache,
28496       cacheStream,
28497       lower48 = albers(), lower48Point,
28498       alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338
28499       hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007
28500       point, pointStream = {point: function(x, y) { point = [x, y]; }};
28501
28502   function albersUsa(coordinates) {
28503     var x = coordinates[0], y = coordinates[1];
28504     return point = null,
28505         (lower48Point.point(x, y), point)
28506         || (alaskaPoint.point(x, y), point)
28507         || (hawaiiPoint.point(x, y), point);
28508   }
28509
28510   albersUsa.invert = function(coordinates) {
28511     var k = lower48.scale(),
28512         t = lower48.translate(),
28513         x = (coordinates[0] - t[0]) / k,
28514         y = (coordinates[1] - t[1]) / k;
28515     return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska
28516         : y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii
28517         : lower48).invert(coordinates);
28518   };
28519
28520   albersUsa.stream = function(stream) {
28521     return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]);
28522   };
28523
28524   albersUsa.precision = function(_) {
28525     if (!arguments.length) return lower48.precision();
28526     lower48.precision(_), alaska.precision(_), hawaii.precision(_);
28527     return reset();
28528   };
28529
28530   albersUsa.scale = function(_) {
28531     if (!arguments.length) return lower48.scale();
28532     lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_);
28533     return albersUsa.translate(lower48.translate());
28534   };
28535
28536   albersUsa.translate = function(_) {
28537     if (!arguments.length) return lower48.translate();
28538     var k = lower48.scale(), x = +_[0], y = +_[1];
28539
28540     lower48Point = lower48
28541         .translate(_)
28542         .clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]])
28543         .stream(pointStream);
28544
28545     alaskaPoint = alaska
28546         .translate([x - 0.307 * k, y + 0.201 * k])
28547         .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]])
28548         .stream(pointStream);
28549
28550     hawaiiPoint = hawaii
28551         .translate([x - 0.205 * k, y + 0.212 * k])
28552         .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]])
28553         .stream(pointStream);
28554
28555     return reset();
28556   };
28557
28558   albersUsa.fitExtent = function(extent, object) {
28559     return fitExtent(albersUsa, extent, object);
28560   };
28561
28562   albersUsa.fitSize = function(size, object) {
28563     return fitSize(albersUsa, size, object);
28564   };
28565
28566   function reset() {
28567     cache = cacheStream = null;
28568     return albersUsa;
28569   }
28570
28571   return albersUsa.scale(1070);
28572 };
28573
28574 function azimuthalRaw(scale) {
28575   return function(x, y) {
28576     var cx = cos$1(x),
28577         cy = cos$1(y),
28578         k = scale(cx * cy);
28579     return [
28580       k * cy * sin$1(x),
28581       k * sin$1(y)
28582     ];
28583   }
28584 }
28585
28586 function azimuthalInvert(angle) {
28587   return function(x, y) {
28588     var z = sqrt(x * x + y * y),
28589         c = angle(z),
28590         sc = sin$1(c),
28591         cc = cos$1(c);
28592     return [
28593       atan2(x * sc, z * cc),
28594       asin(z && y * sc / z)
28595     ];
28596   }
28597 }
28598
28599 var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) {
28600   return sqrt(2 / (1 + cxcy));
28601 });
28602
28603 azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) {
28604   return 2 * asin(z / 2);
28605 });
28606
28607 var azimuthalEqualArea = function() {
28608   return projection(azimuthalEqualAreaRaw)
28609       .scale(124.75)
28610       .clipAngle(180 - 1e-3);
28611 };
28612
28613 var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
28614   return (c = acos(c)) && c / sin$1(c);
28615 });
28616
28617 azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
28618   return z;
28619 });
28620
28621 var azimuthalEquidistant = function() {
28622   return projection(azimuthalEquidistantRaw)
28623       .scale(79.4188)
28624       .clipAngle(180 - 1e-3);
28625 };
28626
28627 function mercatorRaw(lambda, phi) {
28628   return [lambda, log(tan((halfPi$2 + phi) / 2))];
28629 }
28630
28631 mercatorRaw.invert = function(x, y) {
28632   return [x, 2 * atan(exp(y)) - halfPi$2];
28633 };
28634
28635 var mercator = function() {
28636   return mercatorProjection(mercatorRaw)
28637       .scale(961 / tau$3);
28638 };
28639
28640 function mercatorProjection(project) {
28641   var m = projection(project),
28642       center = m.center,
28643       scale = m.scale,
28644       translate = m.translate,
28645       clipExtent = m.clipExtent,
28646       x0 = null, y0, x1, y1; // clip extent
28647
28648   m.scale = function(_) {
28649     return arguments.length ? (scale(_), reclip()) : scale();
28650   };
28651
28652   m.translate = function(_) {
28653     return arguments.length ? (translate(_), reclip()) : translate();
28654   };
28655
28656   m.center = function(_) {
28657     return arguments.length ? (center(_), reclip()) : center();
28658   };
28659
28660   m.clipExtent = function(_) {
28661     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]];
28662   };
28663
28664   function reclip() {
28665     var k = pi$3 * scale(),
28666         t = m(rotation(m.rotate()).invert([0, 0]));
28667     return clipExtent(x0 == null
28668         ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw
28669         ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]]
28670         : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]);
28671   }
28672
28673   return reclip();
28674 }
28675
28676 function tany(y) {
28677   return tan((halfPi$2 + y) / 2);
28678 }
28679
28680 function conicConformalRaw(y0, y1) {
28681   var cy0 = cos$1(y0),
28682       n = y0 === y1 ? sin$1(y0) : log(cy0 / cos$1(y1)) / log(tany(y1) / tany(y0)),
28683       f = cy0 * pow(tany(y0), n) / n;
28684
28685   if (!n) return mercatorRaw;
28686
28687   function project(x, y) {
28688     if (f > 0) { if (y < -halfPi$2 + epsilon$2) y = -halfPi$2 + epsilon$2; }
28689     else { if (y > halfPi$2 - epsilon$2) y = halfPi$2 - epsilon$2; }
28690     var r = f / pow(tany(y), n);
28691     return [r * sin$1(n * x), f - r * cos$1(n * x)];
28692   }
28693
28694   project.invert = function(x, y) {
28695     var fy = f - y, r = sign(n) * sqrt(x * x + fy * fy);
28696     return [atan2(x, abs(fy)) / n * sign(fy), 2 * atan(pow(f / r, 1 / n)) - halfPi$2];
28697   };
28698
28699   return project;
28700 }
28701
28702 var conicConformal = function() {
28703   return conicProjection(conicConformalRaw)
28704       .scale(109.5)
28705       .parallels([30, 30]);
28706 };
28707
28708 function equirectangularRaw(lambda, phi) {
28709   return [lambda, phi];
28710 }
28711
28712 equirectangularRaw.invert = equirectangularRaw;
28713
28714 var equirectangular = function() {
28715   return projection(equirectangularRaw)
28716       .scale(152.63);
28717 };
28718
28719 function conicEquidistantRaw(y0, y1) {
28720   var cy0 = cos$1(y0),
28721       n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(y1)) / (y1 - y0),
28722       g = cy0 / n + y0;
28723
28724   if (abs(n) < epsilon$2) return equirectangularRaw;
28725
28726   function project(x, y) {
28727     var gy = g - y, nx = n * x;
28728     return [gy * sin$1(nx), g - gy * cos$1(nx)];
28729   }
28730
28731   project.invert = function(x, y) {
28732     var gy = g - y;
28733     return [atan2(x, abs(gy)) / n * sign(gy), g - sign(n) * sqrt(x * x + gy * gy)];
28734   };
28735
28736   return project;
28737 }
28738
28739 var conicEquidistant = function() {
28740   return conicProjection(conicEquidistantRaw)
28741       .scale(131.154)
28742       .center([0, 13.9389]);
28743 };
28744
28745 function gnomonicRaw(x, y) {
28746   var cy = cos$1(y), k = cos$1(x) * cy;
28747   return [cy * sin$1(x) / k, sin$1(y) / k];
28748 }
28749
28750 gnomonicRaw.invert = azimuthalInvert(atan);
28751
28752 var gnomonic = function() {
28753   return projection(gnomonicRaw)
28754       .scale(144.049)
28755       .clipAngle(60);
28756 };
28757
28758 function scaleTranslate(kx, ky, tx, ty) {
28759   return kx === 1 && ky === 1 && tx === 0 && ty === 0 ? identity$4 : transformer({
28760     point: function(x, y) {
28761       this.stream.point(x * kx + tx, y * ky + ty);
28762     }
28763   });
28764 }
28765
28766 var identity$5 = function() {
28767   var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, transform$$1 = identity$4, // scale, translate and reflect
28768       x0 = null, y0, x1, y1, clip = identity$4, // clip extent
28769       cache,
28770       cacheStream,
28771       projection;
28772
28773   function reset() {
28774     cache = cacheStream = null;
28775     return projection;
28776   }
28777
28778   return projection = {
28779     stream: function(stream) {
28780       return cache && cacheStream === stream ? cache : cache = transform$$1(clip(cacheStream = stream));
28781     },
28782     clipExtent: function(_) {
28783       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]];
28784     },
28785     scale: function(_) {
28786       return arguments.length ? (transform$$1 = scaleTranslate((k = +_) * sx, k * sy, tx, ty), reset()) : k;
28787     },
28788     translate: function(_) {
28789       return arguments.length ? (transform$$1 = scaleTranslate(k * sx, k * sy, tx = +_[0], ty = +_[1]), reset()) : [tx, ty];
28790     },
28791     reflectX: function(_) {
28792       return arguments.length ? (transform$$1 = scaleTranslate(k * (sx = _ ? -1 : 1), k * sy, tx, ty), reset()) : sx < 0;
28793     },
28794     reflectY: function(_) {
28795       return arguments.length ? (transform$$1 = scaleTranslate(k * sx, k * (sy = _ ? -1 : 1), tx, ty), reset()) : sy < 0;
28796     },
28797     fitExtent: function(extent, object) {
28798       return fitExtent(projection, extent, object);
28799     },
28800     fitSize: function(size, object) {
28801       return fitSize(projection, size, object);
28802     }
28803   };
28804 };
28805
28806 function orthographicRaw(x, y) {
28807   return [cos$1(y) * sin$1(x), sin$1(y)];
28808 }
28809
28810 orthographicRaw.invert = azimuthalInvert(asin);
28811
28812 var orthographic = function() {
28813   return projection(orthographicRaw)
28814       .scale(249.5)
28815       .clipAngle(90 + epsilon$2);
28816 };
28817
28818 function stereographicRaw(x, y) {
28819   var cy = cos$1(y), k = 1 + cos$1(x) * cy;
28820   return [cy * sin$1(x) / k, sin$1(y) / k];
28821 }
28822
28823 stereographicRaw.invert = azimuthalInvert(function(z) {
28824   return 2 * atan(z);
28825 });
28826
28827 var stereographic = function() {
28828   return projection(stereographicRaw)
28829       .scale(250)
28830       .clipAngle(142);
28831 };
28832
28833 function transverseMercatorRaw(lambda, phi) {
28834   return [log(tan((halfPi$2 + phi) / 2)), -lambda];
28835 }
28836
28837 transverseMercatorRaw.invert = function(x, y) {
28838   return [-y, 2 * atan(exp(x)) - halfPi$2];
28839 };
28840
28841 var transverseMercator = function() {
28842   var m = mercatorProjection(transverseMercatorRaw),
28843       center = m.center,
28844       rotate = m.rotate;
28845
28846   m.center = function(_) {
28847     return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]);
28848   };
28849
28850   m.rotate = function(_) {
28851     return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]);
28852   };
28853
28854   return rotate([0, 0, 90])
28855       .scale(159.155);
28856 };
28857
28858 function defaultSeparation(a, b) {
28859   return a.parent === b.parent ? 1 : 2;
28860 }
28861
28862 function meanX(children) {
28863   return children.reduce(meanXReduce, 0) / children.length;
28864 }
28865
28866 function meanXReduce(x, c) {
28867   return x + c.x;
28868 }
28869
28870 function maxY(children) {
28871   return 1 + children.reduce(maxYReduce, 0);
28872 }
28873
28874 function maxYReduce(y, c) {
28875   return Math.max(y, c.y);
28876 }
28877
28878 function leafLeft(node) {
28879   var children;
28880   while (children = node.children) node = children[0];
28881   return node;
28882 }
28883
28884 function leafRight(node) {
28885   var children;
28886   while (children = node.children) node = children[children.length - 1];
28887   return node;
28888 }
28889
28890 var cluster = function() {
28891   var separation = defaultSeparation,
28892       dx = 1,
28893       dy = 1,
28894       nodeSize = false;
28895
28896   function cluster(root) {
28897     var previousNode,
28898         x = 0;
28899
28900     // First walk, computing the initial x & y values.
28901     root.eachAfter(function(node) {
28902       var children = node.children;
28903       if (children) {
28904         node.x = meanX(children);
28905         node.y = maxY(children);
28906       } else {
28907         node.x = previousNode ? x += separation(node, previousNode) : 0;
28908         node.y = 0;
28909         previousNode = node;
28910       }
28911     });
28912
28913     var left = leafLeft(root),
28914         right = leafRight(root),
28915         x0 = left.x - separation(left, right) / 2,
28916         x1 = right.x + separation(right, left) / 2;
28917
28918     // Second walk, normalizing x & y to the desired size.
28919     return root.eachAfter(nodeSize ? function(node) {
28920       node.x = (node.x - root.x) * dx;
28921       node.y = (root.y - node.y) * dy;
28922     } : function(node) {
28923       node.x = (node.x - x0) / (x1 - x0) * dx;
28924       node.y = (1 - (root.y ? node.y / root.y : 1)) * dy;
28925     });
28926   }
28927
28928   cluster.separation = function(x) {
28929     return arguments.length ? (separation = x, cluster) : separation;
28930   };
28931
28932   cluster.size = function(x) {
28933     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]);
28934   };
28935
28936   cluster.nodeSize = function(x) {
28937     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null);
28938   };
28939
28940   return cluster;
28941 };
28942
28943 function count(node) {
28944   var sum = 0,
28945       children = node.children,
28946       i = children && children.length;
28947   if (!i) sum = 1;
28948   else while (--i >= 0) sum += children[i].value;
28949   node.value = sum;
28950 }
28951
28952 var node_count = function() {
28953   return this.eachAfter(count);
28954 };
28955
28956 var node_each = function(callback) {
28957   var node = this, current, next = [node], children, i, n;
28958   do {
28959     current = next.reverse(), next = [];
28960     while (node = current.pop()) {
28961       callback(node), children = node.children;
28962       if (children) for (i = 0, n = children.length; i < n; ++i) {
28963         next.push(children[i]);
28964       }
28965     }
28966   } while (next.length);
28967   return this;
28968 };
28969
28970 var node_eachBefore = function(callback) {
28971   var node = this, nodes = [node], children, i;
28972   while (node = nodes.pop()) {
28973     callback(node), children = node.children;
28974     if (children) for (i = children.length - 1; i >= 0; --i) {
28975       nodes.push(children[i]);
28976     }
28977   }
28978   return this;
28979 };
28980
28981 var node_eachAfter = function(callback) {
28982   var node = this, nodes = [node], next = [], children, i, n;
28983   while (node = nodes.pop()) {
28984     next.push(node), children = node.children;
28985     if (children) for (i = 0, n = children.length; i < n; ++i) {
28986       nodes.push(children[i]);
28987     }
28988   }
28989   while (node = next.pop()) {
28990     callback(node);
28991   }
28992   return this;
28993 };
28994
28995 var node_sum = function(value) {
28996   return this.eachAfter(function(node) {
28997     var sum = +value(node.data) || 0,
28998         children = node.children,
28999         i = children && children.length;
29000     while (--i >= 0) sum += children[i].value;
29001     node.value = sum;
29002   });
29003 };
29004
29005 var node_sort = function(compare) {
29006   return this.eachBefore(function(node) {
29007     if (node.children) {
29008       node.children.sort(compare);
29009     }
29010   });
29011 };
29012
29013 var node_path = function(end) {
29014   var start = this,
29015       ancestor = leastCommonAncestor(start, end),
29016       nodes = [start];
29017   while (start !== ancestor) {
29018     start = start.parent;
29019     nodes.push(start);
29020   }
29021   var k = nodes.length;
29022   while (end !== ancestor) {
29023     nodes.splice(k, 0, end);
29024     end = end.parent;
29025   }
29026   return nodes;
29027 };
29028
29029 function leastCommonAncestor(a, b) {
29030   if (a === b) return a;
29031   var aNodes = a.ancestors(),
29032       bNodes = b.ancestors(),
29033       c = null;
29034   a = aNodes.pop();
29035   b = bNodes.pop();
29036   while (a === b) {
29037     c = a;
29038     a = aNodes.pop();
29039     b = bNodes.pop();
29040   }
29041   return c;
29042 }
29043
29044 var node_ancestors = function() {
29045   var node = this, nodes = [node];
29046   while (node = node.parent) {
29047     nodes.push(node);
29048   }
29049   return nodes;
29050 };
29051
29052 var node_descendants = function() {
29053   var nodes = [];
29054   this.each(function(node) {
29055     nodes.push(node);
29056   });
29057   return nodes;
29058 };
29059
29060 var node_leaves = function() {
29061   var leaves = [];
29062   this.eachBefore(function(node) {
29063     if (!node.children) {
29064       leaves.push(node);
29065     }
29066   });
29067   return leaves;
29068 };
29069
29070 var node_links = function() {
29071   var root = this, links = [];
29072   root.each(function(node) {
29073     if (node !== root) { // Don’t include the root’s parent, if any.
29074       links.push({source: node.parent, target: node});
29075     }
29076   });
29077   return links;
29078 };
29079
29080 function hierarchy(data, children) {
29081   var root = new Node(data),
29082       valued = +data.value && (root.value = data.value),
29083       node,
29084       nodes = [root],
29085       child,
29086       childs,
29087       i,
29088       n;
29089
29090   if (children == null) children = defaultChildren;
29091
29092   while (node = nodes.pop()) {
29093     if (valued) node.value = +node.data.value;
29094     if ((childs = children(node.data)) && (n = childs.length)) {
29095       node.children = new Array(n);
29096       for (i = n - 1; i >= 0; --i) {
29097         nodes.push(child = node.children[i] = new Node(childs[i]));
29098         child.parent = node;
29099         child.depth = node.depth + 1;
29100       }
29101     }
29102   }
29103
29104   return root.eachBefore(computeHeight);
29105 }
29106
29107 function node_copy() {
29108   return hierarchy(this).eachBefore(copyData);
29109 }
29110
29111 function defaultChildren(d) {
29112   return d.children;
29113 }
29114
29115 function copyData(node) {
29116   node.data = node.data.data;
29117 }
29118
29119 function computeHeight(node) {
29120   var height = 0;
29121   do node.height = height;
29122   while ((node = node.parent) && (node.height < ++height));
29123 }
29124
29125 function Node(data) {
29126   this.data = data;
29127   this.depth =
29128   this.height = 0;
29129   this.parent = null;
29130 }
29131
29132 Node.prototype = hierarchy.prototype = {
29133   constructor: Node,
29134   count: node_count,
29135   each: node_each,
29136   eachAfter: node_eachAfter,
29137   eachBefore: node_eachBefore,
29138   sum: node_sum,
29139   sort: node_sort,
29140   path: node_path,
29141   ancestors: node_ancestors,
29142   descendants: node_descendants,
29143   leaves: node_leaves,
29144   links: node_links,
29145   copy: node_copy
29146 };
29147
29148 var slice$3 = Array.prototype.slice;
29149
29150 function shuffle$1(array) {
29151   var m = array.length,
29152       t,
29153       i;
29154
29155   while (m) {
29156     i = Math.random() * m-- | 0;
29157     t = array[m];
29158     array[m] = array[i];
29159     array[i] = t;
29160   }
29161
29162   return array;
29163 }
29164
29165 var enclose = function(circles) {
29166   var i = 0, n = (circles = shuffle$1(slice$3.call(circles))).length, B = [], p, e;
29167
29168   while (i < n) {
29169     p = circles[i];
29170     if (e && enclosesWeak(e, p)) ++i;
29171     else e = encloseBasis(B = extendBasis(B, p)), i = 0;
29172   }
29173
29174   return e;
29175 };
29176
29177 function extendBasis(B, p) {
29178   var i, j;
29179
29180   if (enclosesWeakAll(p, B)) return [p];
29181
29182   // If we get here then B must have at least one element.
29183   for (i = 0; i < B.length; ++i) {
29184     if (enclosesNot(p, B[i])
29185         && enclosesWeakAll(encloseBasis2(B[i], p), B)) {
29186       return [B[i], p];
29187     }
29188   }
29189
29190   // If we get here then B must have at least two elements.
29191   for (i = 0; i < B.length - 1; ++i) {
29192     for (j = i + 1; j < B.length; ++j) {
29193       if (enclosesNot(encloseBasis2(B[i], B[j]), p)
29194           && enclosesNot(encloseBasis2(B[i], p), B[j])
29195           && enclosesNot(encloseBasis2(B[j], p), B[i])
29196           && enclosesWeakAll(encloseBasis3(B[i], B[j], p), B)) {
29197         return [B[i], B[j], p];
29198       }
29199     }
29200   }
29201
29202   // If we get here then something is very wrong.
29203   throw new Error;
29204 }
29205
29206 function enclosesNot(a, b) {
29207   var dr = a.r - b.r, dx = b.x - a.x, dy = b.y - a.y;
29208   return dr < 0 || dr * dr < dx * dx + dy * dy;
29209 }
29210
29211 function enclosesWeak(a, b) {
29212   var dr = a.r - b.r + 1e-6, dx = b.x - a.x, dy = b.y - a.y;
29213   return dr > 0 && dr * dr > dx * dx + dy * dy;
29214 }
29215
29216 function enclosesWeakAll(a, B) {
29217   for (var i = 0; i < B.length; ++i) {
29218     if (!enclosesWeak(a, B[i])) {
29219       return false;
29220     }
29221   }
29222   return true;
29223 }
29224
29225 function encloseBasis(B) {
29226   switch (B.length) {
29227     case 1: return encloseBasis1(B[0]);
29228     case 2: return encloseBasis2(B[0], B[1]);
29229     case 3: return encloseBasis3(B[0], B[1], B[2]);
29230   }
29231 }
29232
29233 function encloseBasis1(a) {
29234   return {
29235     x: a.x,
29236     y: a.y,
29237     r: a.r
29238   };
29239 }
29240
29241 function encloseBasis2(a, b) {
29242   var x1 = a.x, y1 = a.y, r1 = a.r,
29243       x2 = b.x, y2 = b.y, r2 = b.r,
29244       x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
29245       l = Math.sqrt(x21 * x21 + y21 * y21);
29246   return {
29247     x: (x1 + x2 + x21 / l * r21) / 2,
29248     y: (y1 + y2 + y21 / l * r21) / 2,
29249     r: (l + r1 + r2) / 2
29250   };
29251 }
29252
29253 function encloseBasis3(a, b, c) {
29254   var x1 = a.x, y1 = a.y, r1 = a.r,
29255       x2 = b.x, y2 = b.y, r2 = b.r,
29256       x3 = c.x, y3 = c.y, r3 = c.r,
29257       a2 = x1 - x2,
29258       a3 = x1 - x3,
29259       b2 = y1 - y2,
29260       b3 = y1 - y3,
29261       c2 = r2 - r1,
29262       c3 = r3 - r1,
29263       d1 = x1 * x1 + y1 * y1 - r1 * r1,
29264       d2 = d1 - x2 * x2 - y2 * y2 + r2 * r2,
29265       d3 = d1 - x3 * x3 - y3 * y3 + r3 * r3,
29266       ab = a3 * b2 - a2 * b3,
29267       xa = (b2 * d3 - b3 * d2) / (ab * 2) - x1,
29268       xb = (b3 * c2 - b2 * c3) / ab,
29269       ya = (a3 * d2 - a2 * d3) / (ab * 2) - y1,
29270       yb = (a2 * c3 - a3 * c2) / ab,
29271       A = xb * xb + yb * yb - 1,
29272       B = 2 * (r1 + xa * xb + ya * yb),
29273       C = xa * xa + ya * ya - r1 * r1,
29274       r = -(A ? (B + Math.sqrt(B * B - 4 * A * C)) / (2 * A) : C / B);
29275   return {
29276     x: x1 + xa + xb * r,
29277     y: y1 + ya + yb * r,
29278     r: r
29279   };
29280 }
29281
29282 function place(a, b, c) {
29283   var ax = a.x,
29284       ay = a.y,
29285       da = b.r + c.r,
29286       db = a.r + c.r,
29287       dx = b.x - ax,
29288       dy = b.y - ay,
29289       dc = dx * dx + dy * dy;
29290   if (dc) {
29291     var x = 0.5 + ((db *= db) - (da *= da)) / (2 * dc),
29292         y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
29293     c.x = ax + x * dx + y * dy;
29294     c.y = ay + x * dy - y * dx;
29295   } else {
29296     c.x = ax + db;
29297     c.y = ay;
29298   }
29299 }
29300
29301 function intersects(a, b) {
29302   var dx = b.x - a.x,
29303       dy = b.y - a.y,
29304       dr = a.r + b.r;
29305   return dr * dr - 1e-6 > dx * dx + dy * dy;
29306 }
29307
29308 function score(node) {
29309   var a = node._,
29310       b = node.next._,
29311       ab = a.r + b.r,
29312       dx = (a.x * b.r + b.x * a.r) / ab,
29313       dy = (a.y * b.r + b.y * a.r) / ab;
29314   return dx * dx + dy * dy;
29315 }
29316
29317 function Node$1(circle) {
29318   this._ = circle;
29319   this.next = null;
29320   this.previous = null;
29321 }
29322
29323 function packEnclose(circles) {
29324   if (!(n = circles.length)) return 0;
29325
29326   var a, b, c, n, aa, ca, i, j, k, sj, sk;
29327
29328   // Place the first circle.
29329   a = circles[0], a.x = 0, a.y = 0;
29330   if (!(n > 1)) return a.r;
29331
29332   // Place the second circle.
29333   b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
29334   if (!(n > 2)) return a.r + b.r;
29335
29336   // Place the third circle.
29337   place(b, a, c = circles[2]);
29338
29339   // Initialize the front-chain using the first three circles a, b and c.
29340   a = new Node$1(a), b = new Node$1(b), c = new Node$1(c);
29341   a.next = c.previous = b;
29342   b.next = a.previous = c;
29343   c.next = b.previous = a;
29344
29345   // Attempt to place each remaining circle…
29346   pack: for (i = 3; i < n; ++i) {
29347     place(a._, b._, c = circles[i]), c = new Node$1(c);
29348
29349     // Find the closest intersecting circle on the front-chain, if any.
29350     // “Closeness” is determined by linear distance along the front-chain.
29351     // “Ahead” or “behind” is likewise determined by linear distance.
29352     j = b.next, k = a.previous, sj = b._.r, sk = a._.r;
29353     do {
29354       if (sj <= sk) {
29355         if (intersects(j._, c._)) {
29356           b = j, a.next = b, b.previous = a, --i;
29357           continue pack;
29358         }
29359         sj += j._.r, j = j.next;
29360       } else {
29361         if (intersects(k._, c._)) {
29362           a = k, a.next = b, b.previous = a, --i;
29363           continue pack;
29364         }
29365         sk += k._.r, k = k.previous;
29366       }
29367     } while (j !== k.next);
29368
29369     // Success! Insert the new circle c between a and b.
29370     c.previous = a, c.next = b, a.next = b.previous = b = c;
29371
29372     // Compute the new closest circle pair to the centroid.
29373     aa = score(a);
29374     while ((c = c.next) !== b) {
29375       if ((ca = score(c)) < aa) {
29376         a = c, aa = ca;
29377       }
29378     }
29379     b = a.next;
29380   }
29381
29382   // Compute the enclosing circle of the front chain.
29383   a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
29384
29385   // Translate the circles to put the enclosing circle around the origin.
29386   for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
29387
29388   return c.r;
29389 }
29390
29391 var siblings = function(circles) {
29392   packEnclose(circles);
29393   return circles;
29394 };
29395
29396 function optional(f) {
29397   return f == null ? null : required(f);
29398 }
29399
29400 function required(f) {
29401   if (typeof f !== "function") throw new Error;
29402   return f;
29403 }
29404
29405 function constantZero() {
29406   return 0;
29407 }
29408
29409 var constant$8 = function(x) {
29410   return function() {
29411     return x;
29412   };
29413 };
29414
29415 function defaultRadius$1(d) {
29416   return Math.sqrt(d.value);
29417 }
29418
29419 var index$5 = function() {
29420   var radius = null,
29421       dx = 1,
29422       dy = 1,
29423       padding = constantZero;
29424
29425   function pack(root) {
29426     root.x = dx / 2, root.y = dy / 2;
29427     if (radius) {
29428       root.eachBefore(radiusLeaf(radius))
29429           .eachAfter(packChildren(padding, 0.5))
29430           .eachBefore(translateChild(1));
29431     } else {
29432       root.eachBefore(radiusLeaf(defaultRadius$1))
29433           .eachAfter(packChildren(constantZero, 1))
29434           .eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
29435           .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
29436     }
29437     return root;
29438   }
29439
29440   pack.radius = function(x) {
29441     return arguments.length ? (radius = optional(x), pack) : radius;
29442   };
29443
29444   pack.size = function(x) {
29445     return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
29446   };
29447
29448   pack.padding = function(x) {
29449     return arguments.length ? (padding = typeof x === "function" ? x : constant$8(+x), pack) : padding;
29450   };
29451
29452   return pack;
29453 };
29454
29455 function radiusLeaf(radius) {
29456   return function(node) {
29457     if (!node.children) {
29458       node.r = Math.max(0, +radius(node) || 0);
29459     }
29460   };
29461 }
29462
29463 function packChildren(padding, k) {
29464   return function(node) {
29465     if (children = node.children) {
29466       var children,
29467           i,
29468           n = children.length,
29469           r = padding(node) * k || 0,
29470           e;
29471
29472       if (r) for (i = 0; i < n; ++i) children[i].r += r;
29473       e = packEnclose(children);
29474       if (r) for (i = 0; i < n; ++i) children[i].r -= r;
29475       node.r = e + r;
29476     }
29477   };
29478 }
29479
29480 function translateChild(k) {
29481   return function(node) {
29482     var parent = node.parent;
29483     node.r *= k;
29484     if (parent) {
29485       node.x = parent.x + k * node.x;
29486       node.y = parent.y + k * node.y;
29487     }
29488   };
29489 }
29490
29491 var roundNode = function(node) {
29492   node.x0 = Math.round(node.x0);
29493   node.y0 = Math.round(node.y0);
29494   node.x1 = Math.round(node.x1);
29495   node.y1 = Math.round(node.y1);
29496 };
29497
29498 var treemapDice = function(parent, x0, y0, x1, y1) {
29499   var nodes = parent.children,
29500       node,
29501       i = -1,
29502       n = nodes.length,
29503       k = parent.value && (x1 - x0) / parent.value;
29504
29505   while (++i < n) {
29506     node = nodes[i], node.y0 = y0, node.y1 = y1;
29507     node.x0 = x0, node.x1 = x0 += node.value * k;
29508   }
29509 };
29510
29511 var partition = function() {
29512   var dx = 1,
29513       dy = 1,
29514       padding = 0,
29515       round = false;
29516
29517   function partition(root) {
29518     var n = root.height + 1;
29519     root.x0 =
29520     root.y0 = padding;
29521     root.x1 = dx;
29522     root.y1 = dy / n;
29523     root.eachBefore(positionNode(dy, n));
29524     if (round) root.eachBefore(roundNode);
29525     return root;
29526   }
29527
29528   function positionNode(dy, n) {
29529     return function(node) {
29530       if (node.children) {
29531         treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
29532       }
29533       var x0 = node.x0,
29534           y0 = node.y0,
29535           x1 = node.x1 - padding,
29536           y1 = node.y1 - padding;
29537       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29538       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29539       node.x0 = x0;
29540       node.y0 = y0;
29541       node.x1 = x1;
29542       node.y1 = y1;
29543     };
29544   }
29545
29546   partition.round = function(x) {
29547     return arguments.length ? (round = !!x, partition) : round;
29548   };
29549
29550   partition.size = function(x) {
29551     return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy];
29552   };
29553
29554   partition.padding = function(x) {
29555     return arguments.length ? (padding = +x, partition) : padding;
29556   };
29557
29558   return partition;
29559 };
29560
29561 var keyPrefix$1 = "$";
29562 var preroot = {depth: -1};
29563 var ambiguous = {};
29564
29565 function defaultId(d) {
29566   return d.id;
29567 }
29568
29569 function defaultParentId(d) {
29570   return d.parentId;
29571 }
29572
29573 var stratify = function() {
29574   var id = defaultId,
29575       parentId = defaultParentId;
29576
29577   function stratify(data) {
29578     var d,
29579         i,
29580         n = data.length,
29581         root,
29582         parent,
29583         node,
29584         nodes = new Array(n),
29585         nodeId,
29586         nodeKey,
29587         nodeByKey = {};
29588
29589     for (i = 0; i < n; ++i) {
29590       d = data[i], node = nodes[i] = new Node(d);
29591       if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
29592         nodeKey = keyPrefix$1 + (node.id = nodeId);
29593         nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node;
29594       }
29595     }
29596
29597     for (i = 0; i < n; ++i) {
29598       node = nodes[i], nodeId = parentId(data[i], i, data);
29599       if (nodeId == null || !(nodeId += "")) {
29600         if (root) throw new Error("multiple roots");
29601         root = node;
29602       } else {
29603         parent = nodeByKey[keyPrefix$1 + nodeId];
29604         if (!parent) throw new Error("missing: " + nodeId);
29605         if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
29606         if (parent.children) parent.children.push(node);
29607         else parent.children = [node];
29608         node.parent = parent;
29609       }
29610     }
29611
29612     if (!root) throw new Error("no root");
29613     root.parent = preroot;
29614     root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
29615     root.parent = null;
29616     if (n > 0) throw new Error("cycle");
29617
29618     return root;
29619   }
29620
29621   stratify.id = function(x) {
29622     return arguments.length ? (id = required(x), stratify) : id;
29623   };
29624
29625   stratify.parentId = function(x) {
29626     return arguments.length ? (parentId = required(x), stratify) : parentId;
29627   };
29628
29629   return stratify;
29630 };
29631
29632 function defaultSeparation$1(a, b) {
29633   return a.parent === b.parent ? 1 : 2;
29634 }
29635
29636 // function radialSeparation(a, b) {
29637 //   return (a.parent === b.parent ? 1 : 2) / a.depth;
29638 // }
29639
29640 // This function is used to traverse the left contour of a subtree (or
29641 // subforest). It returns the successor of v on this contour. This successor is
29642 // either given by the leftmost child of v or by the thread of v. The function
29643 // returns null if and only if v is on the highest level of its subtree.
29644 function nextLeft(v) {
29645   var children = v.children;
29646   return children ? children[0] : v.t;
29647 }
29648
29649 // This function works analogously to nextLeft.
29650 function nextRight(v) {
29651   var children = v.children;
29652   return children ? children[children.length - 1] : v.t;
29653 }
29654
29655 // Shifts the current subtree rooted at w+. This is done by increasing
29656 // prelim(w+) and mod(w+) by shift.
29657 function moveSubtree(wm, wp, shift) {
29658   var change = shift / (wp.i - wm.i);
29659   wp.c -= change;
29660   wp.s += shift;
29661   wm.c += change;
29662   wp.z += shift;
29663   wp.m += shift;
29664 }
29665
29666 // All other shifts, applied to the smaller subtrees between w- and w+, are
29667 // performed by this function. To prepare the shifts, we have to adjust
29668 // change(w+), shift(w+), and change(w-).
29669 function executeShifts(v) {
29670   var shift = 0,
29671       change = 0,
29672       children = v.children,
29673       i = children.length,
29674       w;
29675   while (--i >= 0) {
29676     w = children[i];
29677     w.z += shift;
29678     w.m += shift;
29679     shift += w.s + (change += w.c);
29680   }
29681 }
29682
29683 // If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise,
29684 // returns the specified (default) ancestor.
29685 function nextAncestor(vim, v, ancestor) {
29686   return vim.a.parent === v.parent ? vim.a : ancestor;
29687 }
29688
29689 function TreeNode(node, i) {
29690   this._ = node;
29691   this.parent = null;
29692   this.children = null;
29693   this.A = null; // default ancestor
29694   this.a = this; // ancestor
29695   this.z = 0; // prelim
29696   this.m = 0; // mod
29697   this.c = 0; // change
29698   this.s = 0; // shift
29699   this.t = null; // thread
29700   this.i = i; // number
29701 }
29702
29703 TreeNode.prototype = Object.create(Node.prototype);
29704
29705 function treeRoot(root) {
29706   var tree = new TreeNode(root, 0),
29707       node,
29708       nodes = [tree],
29709       child,
29710       children,
29711       i,
29712       n;
29713
29714   while (node = nodes.pop()) {
29715     if (children = node._.children) {
29716       node.children = new Array(n = children.length);
29717       for (i = n - 1; i >= 0; --i) {
29718         nodes.push(child = node.children[i] = new TreeNode(children[i], i));
29719         child.parent = node;
29720       }
29721     }
29722   }
29723
29724   (tree.parent = new TreeNode(null, 0)).children = [tree];
29725   return tree;
29726 }
29727
29728 // Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
29729 var tree = function() {
29730   var separation = defaultSeparation$1,
29731       dx = 1,
29732       dy = 1,
29733       nodeSize = null;
29734
29735   function tree(root) {
29736     var t = treeRoot(root);
29737
29738     // Compute the layout using Buchheim et al.’s algorithm.
29739     t.eachAfter(firstWalk), t.parent.m = -t.z;
29740     t.eachBefore(secondWalk);
29741
29742     // If a fixed node size is specified, scale x and y.
29743     if (nodeSize) root.eachBefore(sizeNode);
29744
29745     // If a fixed tree size is specified, scale x and y based on the extent.
29746     // Compute the left-most, right-most, and depth-most nodes for extents.
29747     else {
29748       var left = root,
29749           right = root,
29750           bottom = root;
29751       root.eachBefore(function(node) {
29752         if (node.x < left.x) left = node;
29753         if (node.x > right.x) right = node;
29754         if (node.depth > bottom.depth) bottom = node;
29755       });
29756       var s = left === right ? 1 : separation(left, right) / 2,
29757           tx = s - left.x,
29758           kx = dx / (right.x + s + tx),
29759           ky = dy / (bottom.depth || 1);
29760       root.eachBefore(function(node) {
29761         node.x = (node.x + tx) * kx;
29762         node.y = node.depth * ky;
29763       });
29764     }
29765
29766     return root;
29767   }
29768
29769   // Computes a preliminary x-coordinate for v. Before that, FIRST WALK is
29770   // applied recursively to the children of v, as well as the function
29771   // APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the
29772   // node v is placed to the midpoint of its outermost children.
29773   function firstWalk(v) {
29774     var children = v.children,
29775         siblings = v.parent.children,
29776         w = v.i ? siblings[v.i - 1] : null;
29777     if (children) {
29778       executeShifts(v);
29779       var midpoint = (children[0].z + children[children.length - 1].z) / 2;
29780       if (w) {
29781         v.z = w.z + separation(v._, w._);
29782         v.m = v.z - midpoint;
29783       } else {
29784         v.z = midpoint;
29785       }
29786     } else if (w) {
29787       v.z = w.z + separation(v._, w._);
29788     }
29789     v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
29790   }
29791
29792   // Computes all real x-coordinates by summing up the modifiers recursively.
29793   function secondWalk(v) {
29794     v._.x = v.z + v.parent.m;
29795     v.m += v.parent.m;
29796   }
29797
29798   // The core of the algorithm. Here, a new subtree is combined with the
29799   // previous subtrees. Threads are used to traverse the inside and outside
29800   // contours of the left and right subtree up to the highest common level. The
29801   // vertices used for the traversals are vi+, vi-, vo-, and vo+, where the
29802   // superscript o means outside and i means inside, the subscript - means left
29803   // subtree and + means right subtree. For summing up the modifiers along the
29804   // contour, we use respective variables si+, si-, so-, and so+. Whenever two
29805   // nodes of the inside contours conflict, we compute the left one of the
29806   // greatest uncommon ancestors using the function ANCESTOR and call MOVE
29807   // SUBTREE to shift the subtree and prepare the shifts of smaller subtrees.
29808   // Finally, we add a new thread (if necessary).
29809   function apportion(v, w, ancestor) {
29810     if (w) {
29811       var vip = v,
29812           vop = v,
29813           vim = w,
29814           vom = vip.parent.children[0],
29815           sip = vip.m,
29816           sop = vop.m,
29817           sim = vim.m,
29818           som = vom.m,
29819           shift;
29820       while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) {
29821         vom = nextLeft(vom);
29822         vop = nextRight(vop);
29823         vop.a = v;
29824         shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
29825         if (shift > 0) {
29826           moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
29827           sip += shift;
29828           sop += shift;
29829         }
29830         sim += vim.m;
29831         sip += vip.m;
29832         som += vom.m;
29833         sop += vop.m;
29834       }
29835       if (vim && !nextRight(vop)) {
29836         vop.t = vim;
29837         vop.m += sim - sop;
29838       }
29839       if (vip && !nextLeft(vom)) {
29840         vom.t = vip;
29841         vom.m += sip - som;
29842         ancestor = v;
29843       }
29844     }
29845     return ancestor;
29846   }
29847
29848   function sizeNode(node) {
29849     node.x *= dx;
29850     node.y = node.depth * dy;
29851   }
29852
29853   tree.separation = function(x) {
29854     return arguments.length ? (separation = x, tree) : separation;
29855   };
29856
29857   tree.size = function(x) {
29858     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]);
29859   };
29860
29861   tree.nodeSize = function(x) {
29862     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null);
29863   };
29864
29865   return tree;
29866 };
29867
29868 var treemapSlice = function(parent, x0, y0, x1, y1) {
29869   var nodes = parent.children,
29870       node,
29871       i = -1,
29872       n = nodes.length,
29873       k = parent.value && (y1 - y0) / parent.value;
29874
29875   while (++i < n) {
29876     node = nodes[i], node.x0 = x0, node.x1 = x1;
29877     node.y0 = y0, node.y1 = y0 += node.value * k;
29878   }
29879 };
29880
29881 var phi = (1 + Math.sqrt(5)) / 2;
29882
29883 function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
29884   var rows = [],
29885       nodes = parent.children,
29886       row,
29887       nodeValue,
29888       i0 = 0,
29889       i1 = 0,
29890       n = nodes.length,
29891       dx, dy,
29892       value = parent.value,
29893       sumValue,
29894       minValue,
29895       maxValue,
29896       newRatio,
29897       minRatio,
29898       alpha,
29899       beta;
29900
29901   while (i0 < n) {
29902     dx = x1 - x0, dy = y1 - y0;
29903
29904     // Find the next non-empty node.
29905     do sumValue = nodes[i1++].value; while (!sumValue && i1 < n);
29906     minValue = maxValue = sumValue;
29907     alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
29908     beta = sumValue * sumValue * alpha;
29909     minRatio = Math.max(maxValue / beta, beta / minValue);
29910
29911     // Keep adding nodes while the aspect ratio maintains or improves.
29912     for (; i1 < n; ++i1) {
29913       sumValue += nodeValue = nodes[i1].value;
29914       if (nodeValue < minValue) minValue = nodeValue;
29915       if (nodeValue > maxValue) maxValue = nodeValue;
29916       beta = sumValue * sumValue * alpha;
29917       newRatio = Math.max(maxValue / beta, beta / minValue);
29918       if (newRatio > minRatio) { sumValue -= nodeValue; break; }
29919       minRatio = newRatio;
29920     }
29921
29922     // Position and record the row orientation.
29923     rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
29924     if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
29925     else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
29926     value -= sumValue, i0 = i1;
29927   }
29928
29929   return rows;
29930 }
29931
29932 var squarify = (function custom(ratio) {
29933
29934   function squarify(parent, x0, y0, x1, y1) {
29935     squarifyRatio(ratio, parent, x0, y0, x1, y1);
29936   }
29937
29938   squarify.ratio = function(x) {
29939     return custom((x = +x) > 1 ? x : 1);
29940   };
29941
29942   return squarify;
29943 })(phi);
29944
29945 var index$6 = function() {
29946   var tile = squarify,
29947       round = false,
29948       dx = 1,
29949       dy = 1,
29950       paddingStack = [0],
29951       paddingInner = constantZero,
29952       paddingTop = constantZero,
29953       paddingRight = constantZero,
29954       paddingBottom = constantZero,
29955       paddingLeft = constantZero;
29956
29957   function treemap(root) {
29958     root.x0 =
29959     root.y0 = 0;
29960     root.x1 = dx;
29961     root.y1 = dy;
29962     root.eachBefore(positionNode);
29963     paddingStack = [0];
29964     if (round) root.eachBefore(roundNode);
29965     return root;
29966   }
29967
29968   function positionNode(node) {
29969     var p = paddingStack[node.depth],
29970         x0 = node.x0 + p,
29971         y0 = node.y0 + p,
29972         x1 = node.x1 - p,
29973         y1 = node.y1 - p;
29974     if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29975     if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29976     node.x0 = x0;
29977     node.y0 = y0;
29978     node.x1 = x1;
29979     node.y1 = y1;
29980     if (node.children) {
29981       p = paddingStack[node.depth + 1] = paddingInner(node) / 2;
29982       x0 += paddingLeft(node) - p;
29983       y0 += paddingTop(node) - p;
29984       x1 -= paddingRight(node) - p;
29985       y1 -= paddingBottom(node) - p;
29986       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29987       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29988       tile(node, x0, y0, x1, y1);
29989     }
29990   }
29991
29992   treemap.round = function(x) {
29993     return arguments.length ? (round = !!x, treemap) : round;
29994   };
29995
29996   treemap.size = function(x) {
29997     return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy];
29998   };
29999
30000   treemap.tile = function(x) {
30001     return arguments.length ? (tile = required(x), treemap) : tile;
30002   };
30003
30004   treemap.padding = function(x) {
30005     return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner();
30006   };
30007
30008   treemap.paddingInner = function(x) {
30009     return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$8(+x), treemap) : paddingInner;
30010   };
30011
30012   treemap.paddingOuter = function(x) {
30013     return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop();
30014   };
30015
30016   treemap.paddingTop = function(x) {
30017     return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$8(+x), treemap) : paddingTop;
30018   };
30019
30020   treemap.paddingRight = function(x) {
30021     return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$8(+x), treemap) : paddingRight;
30022   };
30023
30024   treemap.paddingBottom = function(x) {
30025     return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$8(+x), treemap) : paddingBottom;
30026   };
30027
30028   treemap.paddingLeft = function(x) {
30029     return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$8(+x), treemap) : paddingLeft;
30030   };
30031
30032   return treemap;
30033 };
30034
30035 var binary = function(parent, x0, y0, x1, y1) {
30036   var nodes = parent.children,
30037       i, n = nodes.length,
30038       sum, sums = new Array(n + 1);
30039
30040   for (sums[0] = sum = i = 0; i < n; ++i) {
30041     sums[i + 1] = sum += nodes[i].value;
30042   }
30043
30044   partition(0, n, parent.value, x0, y0, x1, y1);
30045
30046   function partition(i, j, value, x0, y0, x1, y1) {
30047     if (i >= j - 1) {
30048       var node = nodes[i];
30049       node.x0 = x0, node.y0 = y0;
30050       node.x1 = x1, node.y1 = y1;
30051       return;
30052     }
30053
30054     var valueOffset = sums[i],
30055         valueTarget = (value / 2) + valueOffset,
30056         k = i + 1,
30057         hi = j - 1;
30058
30059     while (k < hi) {
30060       var mid = k + hi >>> 1;
30061       if (sums[mid] < valueTarget) k = mid + 1;
30062       else hi = mid;
30063     }
30064
30065     if ((valueTarget - sums[k - 1]) < (sums[k] - valueTarget) && i + 1 < k) --k;
30066
30067     var valueLeft = sums[k] - valueOffset,
30068         valueRight = value - valueLeft;
30069
30070     if ((x1 - x0) > (y1 - y0)) {
30071       var xk = (x0 * valueRight + x1 * valueLeft) / value;
30072       partition(i, k, valueLeft, x0, y0, xk, y1);
30073       partition(k, j, valueRight, xk, y0, x1, y1);
30074     } else {
30075       var yk = (y0 * valueRight + y1 * valueLeft) / value;
30076       partition(i, k, valueLeft, x0, y0, x1, yk);
30077       partition(k, j, valueRight, x0, yk, x1, y1);
30078     }
30079   }
30080 };
30081
30082 var sliceDice = function(parent, x0, y0, x1, y1) {
30083   (parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1);
30084 };
30085
30086 var resquarify = (function custom(ratio) {
30087
30088   function resquarify(parent, x0, y0, x1, y1) {
30089     if ((rows = parent._squarify) && (rows.ratio === ratio)) {
30090       var rows,
30091           row,
30092           nodes,
30093           i,
30094           j = -1,
30095           n,
30096           m = rows.length,
30097           value = parent.value;
30098
30099       while (++j < m) {
30100         row = rows[j], nodes = row.children;
30101         for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
30102         if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value);
30103         else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1);
30104         value -= row.value;
30105       }
30106     } else {
30107       parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1);
30108       rows.ratio = ratio;
30109     }
30110   }
30111
30112   resquarify.ratio = function(x) {
30113     return custom((x = +x) > 1 ? x : 1);
30114   };
30115
30116   return resquarify;
30117 })(phi);
30118
30119 var d3polygonArea = function(polygon) {
30120   var i = -1,
30121       n = polygon.length,
30122       a,
30123       b = polygon[n - 1],
30124       area = 0;
30125
30126   while (++i < n) {
30127     a = b;
30128     b = polygon[i];
30129     area += a[1] * b[0] - a[0] * b[1];
30130   }
30131
30132   return area / 2;
30133 };
30134
30135 var d3polygonCentroid = function(polygon) {
30136   var i = -1,
30137       n = polygon.length,
30138       x = 0,
30139       y = 0,
30140       a,
30141       b = polygon[n - 1],
30142       c,
30143       k = 0;
30144
30145   while (++i < n) {
30146     a = b;
30147     b = polygon[i];
30148     k += c = a[0] * b[1] - b[0] * a[1];
30149     x += (a[0] + b[0]) * c;
30150     y += (a[1] + b[1]) * c;
30151   }
30152
30153   return k *= 3, [x / k, y / k];
30154 };
30155
30156 // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
30157 // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
30158 // right, +y is up). Returns a positive value if ABC is counter-clockwise,
30159 // negative if clockwise, and zero if the points are collinear.
30160 var cross$1 = function(a, b, c) {
30161   return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
30162 };
30163
30164 function lexicographicOrder(a, b) {
30165   return a[0] - b[0] || a[1] - b[1];
30166 }
30167
30168 // Computes the upper convex hull per the monotone chain algorithm.
30169 // Assumes points.length >= 3, is sorted by x, unique in y.
30170 // Returns an array of indices into points in left-to-right order.
30171 function computeUpperHullIndexes(points) {
30172   var n = points.length,
30173       indexes = [0, 1],
30174       size = 2;
30175
30176   for (var i = 2; i < n; ++i) {
30177     while (size > 1 && cross$1(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size;
30178     indexes[size++] = i;
30179   }
30180
30181   return indexes.slice(0, size); // remove popped points
30182 }
30183
30184 var d3polygonHull = function(points) {
30185   if ((n = points.length) < 3) return null;
30186
30187   var i,
30188       n,
30189       sortedPoints = new Array(n),
30190       flippedPoints = new Array(n);
30191
30192   for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i];
30193   sortedPoints.sort(lexicographicOrder);
30194   for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
30195
30196   var upperIndexes = computeUpperHullIndexes(sortedPoints),
30197       lowerIndexes = computeUpperHullIndexes(flippedPoints);
30198
30199   // Construct the hull polygon, removing possible duplicate endpoints.
30200   var skipLeft = lowerIndexes[0] === upperIndexes[0],
30201       skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
30202       hull = [];
30203
30204   // Add upper hull in right-to-l order.
30205   // Then add lower hull in left-to-right order.
30206   for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]);
30207   for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
30208
30209   return hull;
30210 };
30211
30212 var contains$1 = function(polygon, point) {
30213   var n = polygon.length,
30214       p = polygon[n - 1],
30215       x = point[0], y = point[1],
30216       x0 = p[0], y0 = p[1],
30217       x1, y1,
30218       inside = false;
30219
30220   for (var i = 0; i < n; ++i) {
30221     p = polygon[i], x1 = p[0], y1 = p[1];
30222     if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside;
30223     x0 = x1, y0 = y1;
30224   }
30225
30226   return inside;
30227 };
30228
30229 var length$1 = function(polygon) {
30230   var i = -1,
30231       n = polygon.length,
30232       b = polygon[n - 1],
30233       xa,
30234       ya,
30235       xb = b[0],
30236       yb = b[1],
30237       perimeter = 0;
30238
30239   while (++i < n) {
30240     xa = xb;
30241     ya = yb;
30242     b = polygon[i];
30243     xb = b[0];
30244     yb = b[1];
30245     xa -= xb;
30246     ya -= yb;
30247     perimeter += Math.sqrt(xa * xa + ya * ya);
30248   }
30249
30250   return perimeter;
30251 };
30252
30253 var slice$4 = [].slice;
30254
30255 var noabort = {};
30256
30257 function Queue(size) {
30258   this._size = size;
30259   this._call =
30260   this._error = null;
30261   this._tasks = [];
30262   this._data = [];
30263   this._waiting =
30264   this._active =
30265   this._ended =
30266   this._start = 0; // inside a synchronous task callback?
30267 }
30268
30269 Queue.prototype = queue.prototype = {
30270   constructor: Queue,
30271   defer: function(callback) {
30272     if (typeof callback !== "function") throw new Error("invalid callback");
30273     if (this._call) throw new Error("defer after await");
30274     if (this._error != null) return this;
30275     var t = slice$4.call(arguments, 1);
30276     t.push(callback);
30277     ++this._waiting, this._tasks.push(t);
30278     poke$1(this);
30279     return this;
30280   },
30281   abort: function() {
30282     if (this._error == null) abort(this, new Error("abort"));
30283     return this;
30284   },
30285   await: function(callback) {
30286     if (typeof callback !== "function") throw new Error("invalid callback");
30287     if (this._call) throw new Error("multiple await");
30288     this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
30289     maybeNotify(this);
30290     return this;
30291   },
30292   awaitAll: function(callback) {
30293     if (typeof callback !== "function") throw new Error("invalid callback");
30294     if (this._call) throw new Error("multiple await");
30295     this._call = callback;
30296     maybeNotify(this);
30297     return this;
30298   }
30299 };
30300
30301 function poke$1(q) {
30302   if (!q._start) {
30303     try { start$1(q); } // let the current task complete
30304     catch (e) {
30305       if (q._tasks[q._ended + q._active - 1]) abort(q, e); // task errored synchronously
30306       else if (!q._data) throw e; // await callback errored synchronously
30307     }
30308   }
30309 }
30310
30311 function start$1(q) {
30312   while (q._start = q._waiting && q._active < q._size) {
30313     var i = q._ended + q._active,
30314         t = q._tasks[i],
30315         j = t.length - 1,
30316         c = t[j];
30317     t[j] = end(q, i);
30318     --q._waiting, ++q._active;
30319     t = c.apply(null, t);
30320     if (!q._tasks[i]) continue; // task finished synchronously
30321     q._tasks[i] = t || noabort;
30322   }
30323 }
30324
30325 function end(q, i) {
30326   return function(e, r) {
30327     if (!q._tasks[i]) return; // ignore multiple callbacks
30328     --q._active, ++q._ended;
30329     q._tasks[i] = null;
30330     if (q._error != null) return; // ignore secondary errors
30331     if (e != null) {
30332       abort(q, e);
30333     } else {
30334       q._data[i] = r;
30335       if (q._waiting) poke$1(q);
30336       else maybeNotify(q);
30337     }
30338   };
30339 }
30340
30341 function abort(q, e) {
30342   var i = q._tasks.length, t;
30343   q._error = e; // ignore active callbacks
30344   q._data = undefined; // allow gc
30345   q._waiting = NaN; // prevent starting
30346
30347   while (--i >= 0) {
30348     if (t = q._tasks[i]) {
30349       q._tasks[i] = null;
30350       if (t.abort) {
30351         try { t.abort(); }
30352         catch (e) { /* ignore */ }
30353       }
30354     }
30355   }
30356
30357   q._active = NaN; // allow notification
30358   maybeNotify(q);
30359 }
30360
30361 function maybeNotify(q) {
30362   if (!q._active && q._call) {
30363     var d = q._data;
30364     q._data = undefined; // allow gc
30365     q._call(q._error, d);
30366   }
30367 }
30368
30369 function queue(concurrency) {
30370   if (concurrency == null) concurrency = Infinity;
30371   else if (!((concurrency = +concurrency) >= 1)) throw new Error("invalid concurrency");
30372   return new Queue(concurrency);
30373 }
30374
30375 var defaultSource$1 = function() {
30376   return Math.random();
30377 };
30378
30379 var uniform = (function sourceRandomUniform(source) {
30380   function randomUniform(min, max) {
30381     min = min == null ? 0 : +min;
30382     max = max == null ? 1 : +max;
30383     if (arguments.length === 1) max = min, min = 0;
30384     else max -= min;
30385     return function() {
30386       return source() * max + min;
30387     };
30388   }
30389
30390   randomUniform.source = sourceRandomUniform;
30391
30392   return randomUniform;
30393 })(defaultSource$1);
30394
30395 var normal = (function sourceRandomNormal(source) {
30396   function randomNormal(mu, sigma) {
30397     var x, r;
30398     mu = mu == null ? 0 : +mu;
30399     sigma = sigma == null ? 1 : +sigma;
30400     return function() {
30401       var y;
30402
30403       // If available, use the second previously-generated uniform random.
30404       if (x != null) y = x, x = null;
30405
30406       // Otherwise, generate a new x and y.
30407       else do {
30408         x = source() * 2 - 1;
30409         y = source() * 2 - 1;
30410         r = x * x + y * y;
30411       } while (!r || r > 1);
30412
30413       return mu + sigma * y * Math.sqrt(-2 * Math.log(r) / r);
30414     };
30415   }
30416
30417   randomNormal.source = sourceRandomNormal;
30418
30419   return randomNormal;
30420 })(defaultSource$1);
30421
30422 var logNormal = (function sourceRandomLogNormal(source) {
30423   function randomLogNormal() {
30424     var randomNormal = normal.source(source).apply(this, arguments);
30425     return function() {
30426       return Math.exp(randomNormal());
30427     };
30428   }
30429
30430   randomLogNormal.source = sourceRandomLogNormal;
30431
30432   return randomLogNormal;
30433 })(defaultSource$1);
30434
30435 var irwinHall = (function sourceRandomIrwinHall(source) {
30436   function randomIrwinHall(n) {
30437     return function() {
30438       for (var sum = 0, i = 0; i < n; ++i) sum += source();
30439       return sum;
30440     };
30441   }
30442
30443   randomIrwinHall.source = sourceRandomIrwinHall;
30444
30445   return randomIrwinHall;
30446 })(defaultSource$1);
30447
30448 var bates = (function sourceRandomBates(source) {
30449   function randomBates(n) {
30450     var randomIrwinHall = irwinHall.source(source)(n);
30451     return function() {
30452       return randomIrwinHall() / n;
30453     };
30454   }
30455
30456   randomBates.source = sourceRandomBates;
30457
30458   return randomBates;
30459 })(defaultSource$1);
30460
30461 var exponential$1 = (function sourceRandomExponential(source) {
30462   function randomExponential(lambda) {
30463     return function() {
30464       return -Math.log(1 - source()) / lambda;
30465     };
30466   }
30467
30468   randomExponential.source = sourceRandomExponential;
30469
30470   return randomExponential;
30471 })(defaultSource$1);
30472
30473 var request = function(url, callback) {
30474   var request,
30475       event = dispatch("beforesend", "progress", "load", "error"),
30476       mimeType,
30477       headers = map$1(),
30478       xhr = new XMLHttpRequest,
30479       user = null,
30480       password = null,
30481       response,
30482       responseType,
30483       timeout = 0;
30484
30485   // If IE does not support CORS, use XDomainRequest.
30486   if (typeof XDomainRequest !== "undefined"
30487       && !("withCredentials" in xhr)
30488       && /^(http(s)?:)?\/\//.test(url)) xhr = new XDomainRequest;
30489
30490   "onload" in xhr
30491       ? xhr.onload = xhr.onerror = xhr.ontimeout = respond
30492       : xhr.onreadystatechange = function(o) { xhr.readyState > 3 && respond(o); };
30493
30494   function respond(o) {
30495     var status = xhr.status, result;
30496     if (!status && hasResponse(xhr)
30497         || status >= 200 && status < 300
30498         || status === 304) {
30499       if (response) {
30500         try {
30501           result = response.call(request, xhr);
30502         } catch (e) {
30503           event.call("error", request, e);
30504           return;
30505         }
30506       } else {
30507         result = xhr;
30508       }
30509       event.call("load", request, result);
30510     } else {
30511       event.call("error", request, o);
30512     }
30513   }
30514
30515   xhr.onprogress = function(e) {
30516     event.call("progress", request, e);
30517   };
30518
30519   request = {
30520     header: function(name, value) {
30521       name = (name + "").toLowerCase();
30522       if (arguments.length < 2) return headers.get(name);
30523       if (value == null) headers.remove(name);
30524       else headers.set(name, value + "");
30525       return request;
30526     },
30527
30528     // If mimeType is non-null and no Accept header is set, a default is used.
30529     mimeType: function(value) {
30530       if (!arguments.length) return mimeType;
30531       mimeType = value == null ? null : value + "";
30532       return request;
30533     },
30534
30535     // Specifies what type the response value should take;
30536     // for instance, arraybuffer, blob, document, or text.
30537     responseType: function(value) {
30538       if (!arguments.length) return responseType;
30539       responseType = value;
30540       return request;
30541     },
30542
30543     timeout: function(value) {
30544       if (!arguments.length) return timeout;
30545       timeout = +value;
30546       return request;
30547     },
30548
30549     user: function(value) {
30550       return arguments.length < 1 ? user : (user = value == null ? null : value + "", request);
30551     },
30552
30553     password: function(value) {
30554       return arguments.length < 1 ? password : (password = value == null ? null : value + "", request);
30555     },
30556
30557     // Specify how to convert the response content to a specific type;
30558     // changes the callback value on "load" events.
30559     response: function(value) {
30560       response = value;
30561       return request;
30562     },
30563
30564     // Alias for send("GET", …).
30565     get: function(data, callback) {
30566       return request.send("GET", data, callback);
30567     },
30568
30569     // Alias for send("POST", …).
30570     post: function(data, callback) {
30571       return request.send("POST", data, callback);
30572     },
30573
30574     // If callback is non-null, it will be used for error and load events.
30575     send: function(method, data, callback) {
30576       xhr.open(method, url, true, user, password);
30577       if (mimeType != null && !headers.has("accept")) headers.set("accept", mimeType + ",*/*");
30578       if (xhr.setRequestHeader) headers.each(function(value, name) { xhr.setRequestHeader(name, value); });
30579       if (mimeType != null && xhr.overrideMimeType) xhr.overrideMimeType(mimeType);
30580       if (responseType != null) xhr.responseType = responseType;
30581       if (timeout > 0) xhr.timeout = timeout;
30582       if (callback == null && typeof data === "function") callback = data, data = null;
30583       if (callback != null && callback.length === 1) callback = fixCallback(callback);
30584       if (callback != null) request.on("error", callback).on("load", function(xhr) { callback(null, xhr); });
30585       event.call("beforesend", request, xhr);
30586       xhr.send(data == null ? null : data);
30587       return request;
30588     },
30589
30590     abort: function() {
30591       xhr.abort();
30592       return request;
30593     },
30594
30595     on: function() {
30596       var value = event.on.apply(event, arguments);
30597       return value === event ? request : value;
30598     }
30599   };
30600
30601   if (callback != null) {
30602     if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30603     return request.get(callback);
30604   }
30605
30606   return request;
30607 };
30608
30609 function fixCallback(callback) {
30610   return function(error, xhr) {
30611     callback(error == null ? xhr : null);
30612   };
30613 }
30614
30615 function hasResponse(xhr) {
30616   var type = xhr.responseType;
30617   return type && type !== "text"
30618       ? xhr.response // null on error
30619       : xhr.responseText; // "" on error
30620 }
30621
30622 var type$3 = function(defaultMimeType, response) {
30623   return function(url, callback) {
30624     var r = request(url).mimeType(defaultMimeType).response(response);
30625     if (callback != null) {
30626       if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30627       return r.get(callback);
30628     }
30629     return r;
30630   };
30631 };
30632
30633 var html = type$3("text/html", function(xhr) {
30634   return document.createRange().createContextualFragment(xhr.responseText);
30635 });
30636
30637 var json = type$3("application/json", function(xhr) {
30638   return JSON.parse(xhr.responseText);
30639 });
30640
30641 var text = type$3("text/plain", function(xhr) {
30642   return xhr.responseText;
30643 });
30644
30645 var xml = type$3("application/xml", function(xhr) {
30646   var xml = xhr.responseXML;
30647   if (!xml) throw new Error("parse error");
30648   return xml;
30649 });
30650
30651 var dsv$1 = function(defaultMimeType, parse) {
30652   return function(url, row, callback) {
30653     if (arguments.length < 3) callback = row, row = null;
30654     var r = request(url).mimeType(defaultMimeType);
30655     r.row = function(_) { return arguments.length ? r.response(responseOf(parse, row = _)) : row; };
30656     r.row(row);
30657     return callback ? r.get(callback) : r;
30658   };
30659 };
30660
30661 function responseOf(parse, row) {
30662   return function(request$$1) {
30663     return parse(request$$1.responseText, row);
30664   };
30665 }
30666
30667 var csv$1 = dsv$1("text/csv", csvParse);
30668
30669 var tsv$1 = dsv$1("text/tab-separated-values", tsvParse);
30670
30671 var array$2 = Array.prototype;
30672
30673 var map$3 = array$2.map;
30674 var slice$5 = array$2.slice;
30675
30676 var implicit = {name: "implicit"};
30677
30678 function ordinal(range) {
30679   var index = map$1(),
30680       domain = [],
30681       unknown = implicit;
30682
30683   range = range == null ? [] : slice$5.call(range);
30684
30685   function scale(d) {
30686     var key = d + "", i = index.get(key);
30687     if (!i) {
30688       if (unknown !== implicit) return unknown;
30689       index.set(key, i = domain.push(d));
30690     }
30691     return range[(i - 1) % range.length];
30692   }
30693
30694   scale.domain = function(_) {
30695     if (!arguments.length) return domain.slice();
30696     domain = [], index = map$1();
30697     var i = -1, n = _.length, d, key;
30698     while (++i < n) if (!index.has(key = (d = _[i]) + "")) index.set(key, domain.push(d));
30699     return scale;
30700   };
30701
30702   scale.range = function(_) {
30703     return arguments.length ? (range = slice$5.call(_), scale) : range.slice();
30704   };
30705
30706   scale.unknown = function(_) {
30707     return arguments.length ? (unknown = _, scale) : unknown;
30708   };
30709
30710   scale.copy = function() {
30711     return ordinal()
30712         .domain(domain)
30713         .range(range)
30714         .unknown(unknown);
30715   };
30716
30717   return scale;
30718 }
30719
30720 function band() {
30721   var scale = ordinal().unknown(undefined),
30722       domain = scale.domain,
30723       ordinalRange = scale.range,
30724       range = [0, 1],
30725       step,
30726       bandwidth,
30727       round = false,
30728       paddingInner = 0,
30729       paddingOuter = 0,
30730       align = 0.5;
30731
30732   delete scale.unknown;
30733
30734   function rescale() {
30735     var n = domain().length,
30736         reverse = range[1] < range[0],
30737         start = range[reverse - 0],
30738         stop = range[1 - reverse];
30739     step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
30740     if (round) step = Math.floor(step);
30741     start += (stop - start - step * (n - paddingInner)) * align;
30742     bandwidth = step * (1 - paddingInner);
30743     if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
30744     var values = sequence(n).map(function(i) { return start + step * i; });
30745     return ordinalRange(reverse ? values.reverse() : values);
30746   }
30747
30748   scale.domain = function(_) {
30749     return arguments.length ? (domain(_), rescale()) : domain();
30750   };
30751
30752   scale.range = function(_) {
30753     return arguments.length ? (range = [+_[0], +_[1]], rescale()) : range.slice();
30754   };
30755
30756   scale.rangeRound = function(_) {
30757     return range = [+_[0], +_[1]], round = true, rescale();
30758   };
30759
30760   scale.bandwidth = function() {
30761     return bandwidth;
30762   };
30763
30764   scale.step = function() {
30765     return step;
30766   };
30767
30768   scale.round = function(_) {
30769     return arguments.length ? (round = !!_, rescale()) : round;
30770   };
30771
30772   scale.padding = function(_) {
30773     return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30774   };
30775
30776   scale.paddingInner = function(_) {
30777     return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30778   };
30779
30780   scale.paddingOuter = function(_) {
30781     return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter;
30782   };
30783
30784   scale.align = function(_) {
30785     return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
30786   };
30787
30788   scale.copy = function() {
30789     return band()
30790         .domain(domain())
30791         .range(range)
30792         .round(round)
30793         .paddingInner(paddingInner)
30794         .paddingOuter(paddingOuter)
30795         .align(align);
30796   };
30797
30798   return rescale();
30799 }
30800
30801 function pointish(scale) {
30802   var copy = scale.copy;
30803
30804   scale.padding = scale.paddingOuter;
30805   delete scale.paddingInner;
30806   delete scale.paddingOuter;
30807
30808   scale.copy = function() {
30809     return pointish(copy());
30810   };
30811
30812   return scale;
30813 }
30814
30815 function point$1() {
30816   return pointish(band().paddingInner(1));
30817 }
30818
30819 var constant$9 = function(x) {
30820   return function() {
30821     return x;
30822   };
30823 };
30824
30825 var number$2 = function(x) {
30826   return +x;
30827 };
30828
30829 var unit = [0, 1];
30830
30831 function deinterpolateLinear(a, b) {
30832   return (b -= (a = +a))
30833       ? function(x) { return (x - a) / b; }
30834       : constant$9(b);
30835 }
30836
30837 function deinterpolateClamp(deinterpolate) {
30838   return function(a, b) {
30839     var d = deinterpolate(a = +a, b = +b);
30840     return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
30841   };
30842 }
30843
30844 function reinterpolateClamp(reinterpolate$$1) {
30845   return function(a, b) {
30846     var r = reinterpolate$$1(a = +a, b = +b);
30847     return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
30848   };
30849 }
30850
30851 function bimap(domain, range, deinterpolate, reinterpolate$$1) {
30852   var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];
30853   if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate$$1(r1, r0);
30854   else d0 = deinterpolate(d0, d1), r0 = reinterpolate$$1(r0, r1);
30855   return function(x) { return r0(d0(x)); };
30856 }
30857
30858 function polymap(domain, range, deinterpolate, reinterpolate$$1) {
30859   var j = Math.min(domain.length, range.length) - 1,
30860       d = new Array(j),
30861       r = new Array(j),
30862       i = -1;
30863
30864   // Reverse descending domains.
30865   if (domain[j] < domain[0]) {
30866     domain = domain.slice().reverse();
30867     range = range.slice().reverse();
30868   }
30869
30870   while (++i < j) {
30871     d[i] = deinterpolate(domain[i], domain[i + 1]);
30872     r[i] = reinterpolate$$1(range[i], range[i + 1]);
30873   }
30874
30875   return function(x) {
30876     var i = bisectRight(domain, x, 1, j) - 1;
30877     return r[i](d[i](x));
30878   };
30879 }
30880
30881 function copy(source, target) {
30882   return target
30883       .domain(source.domain())
30884       .range(source.range())
30885       .interpolate(source.interpolate())
30886       .clamp(source.clamp());
30887 }
30888
30889 // deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
30890 // reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
30891 function continuous(deinterpolate, reinterpolate$$1) {
30892   var domain = unit,
30893       range = unit,
30894       interpolate = interpolateValue,
30895       clamp = false,
30896       piecewise,
30897       output,
30898       input;
30899
30900   function rescale() {
30901     piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap;
30902     output = input = null;
30903     return scale;
30904   }
30905
30906   function scale(x) {
30907     return (output || (output = piecewise(domain, range, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate)))(+x);
30908   }
30909
30910   scale.invert = function(y) {
30911     return (input || (input = piecewise(range, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate$$1) : reinterpolate$$1)))(+y);
30912   };
30913
30914   scale.domain = function(_) {
30915     return arguments.length ? (domain = map$3.call(_, number$2), rescale()) : domain.slice();
30916   };
30917
30918   scale.range = function(_) {
30919     return arguments.length ? (range = slice$5.call(_), rescale()) : range.slice();
30920   };
30921
30922   scale.rangeRound = function(_) {
30923     return range = slice$5.call(_), interpolate = interpolateRound, rescale();
30924   };
30925
30926   scale.clamp = function(_) {
30927     return arguments.length ? (clamp = !!_, rescale()) : clamp;
30928   };
30929
30930   scale.interpolate = function(_) {
30931     return arguments.length ? (interpolate = _, rescale()) : interpolate;
30932   };
30933
30934   return rescale();
30935 }
30936
30937 var tickFormat = function(domain, count, specifier) {
30938   var start = domain[0],
30939       stop = domain[domain.length - 1],
30940       step = tickStep(start, stop, count == null ? 10 : count),
30941       precision;
30942   specifier = formatSpecifier(specifier == null ? ",f" : specifier);
30943   switch (specifier.type) {
30944     case "s": {
30945       var value = Math.max(Math.abs(start), Math.abs(stop));
30946       if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
30947       return formatPrefix(specifier, value);
30948     }
30949     case "":
30950     case "e":
30951     case "g":
30952     case "p":
30953     case "r": {
30954       if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
30955       break;
30956     }
30957     case "f":
30958     case "%": {
30959       if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
30960       break;
30961     }
30962   }
30963   return format(specifier);
30964 };
30965
30966 function linearish(scale) {
30967   var domain = scale.domain;
30968
30969   scale.ticks = function(count) {
30970     var d = domain();
30971     return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
30972   };
30973
30974   scale.tickFormat = function(count, specifier) {
30975     return tickFormat(domain(), count, specifier);
30976   };
30977
30978   scale.nice = function(count) {
30979     if (count == null) count = 10;
30980
30981     var d = domain(),
30982         i0 = 0,
30983         i1 = d.length - 1,
30984         start = d[i0],
30985         stop = d[i1],
30986         step;
30987
30988     if (stop < start) {
30989       step = start, start = stop, stop = step;
30990       step = i0, i0 = i1, i1 = step;
30991     }
30992
30993     step = tickIncrement(start, stop, count);
30994
30995     if (step > 0) {
30996       start = Math.floor(start / step) * step;
30997       stop = Math.ceil(stop / step) * step;
30998       step = tickIncrement(start, stop, count);
30999     } else if (step < 0) {
31000       start = Math.ceil(start * step) / step;
31001       stop = Math.floor(stop * step) / step;
31002       step = tickIncrement(start, stop, count);
31003     }
31004
31005     if (step > 0) {
31006       d[i0] = Math.floor(start / step) * step;
31007       d[i1] = Math.ceil(stop / step) * step;
31008       domain(d);
31009     } else if (step < 0) {
31010       d[i0] = Math.ceil(start * step) / step;
31011       d[i1] = Math.floor(stop * step) / step;
31012       domain(d);
31013     }
31014
31015     return scale;
31016   };
31017
31018   return scale;
31019 }
31020
31021 function linear$2() {
31022   var scale = continuous(deinterpolateLinear, reinterpolate);
31023
31024   scale.copy = function() {
31025     return copy(scale, linear$2());
31026   };
31027
31028   return linearish(scale);
31029 }
31030
31031 function identity$6() {
31032   var domain = [0, 1];
31033
31034   function scale(x) {
31035     return +x;
31036   }
31037
31038   scale.invert = scale;
31039
31040   scale.domain = scale.range = function(_) {
31041     return arguments.length ? (domain = map$3.call(_, number$2), scale) : domain.slice();
31042   };
31043
31044   scale.copy = function() {
31045     return identity$6().domain(domain);
31046   };
31047
31048   return linearish(scale);
31049 }
31050
31051 var nice = function(domain, interval) {
31052   domain = domain.slice();
31053
31054   var i0 = 0,
31055       i1 = domain.length - 1,
31056       x0 = domain[i0],
31057       x1 = domain[i1],
31058       t;
31059
31060   if (x1 < x0) {
31061     t = i0, i0 = i1, i1 = t;
31062     t = x0, x0 = x1, x1 = t;
31063   }
31064
31065   domain[i0] = interval.floor(x0);
31066   domain[i1] = interval.ceil(x1);
31067   return domain;
31068 };
31069
31070 function deinterpolate(a, b) {
31071   return (b = Math.log(b / a))
31072       ? function(x) { return Math.log(x / a) / b; }
31073       : constant$9(b);
31074 }
31075
31076 function reinterpolate$1(a, b) {
31077   return a < 0
31078       ? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); }
31079       : function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); };
31080 }
31081
31082 function pow10(x) {
31083   return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
31084 }
31085
31086 function powp(base) {
31087   return base === 10 ? pow10
31088       : base === Math.E ? Math.exp
31089       : function(x) { return Math.pow(base, x); };
31090 }
31091
31092 function logp(base) {
31093   return base === Math.E ? Math.log
31094       : base === 10 && Math.log10
31095       || base === 2 && Math.log2
31096       || (base = Math.log(base), function(x) { return Math.log(x) / base; });
31097 }
31098
31099 function reflect(f) {
31100   return function(x) {
31101     return -f(-x);
31102   };
31103 }
31104
31105 function log$1() {
31106   var scale = continuous(deinterpolate, reinterpolate$1).domain([1, 10]),
31107       domain = scale.domain,
31108       base = 10,
31109       logs = logp(10),
31110       pows = powp(10);
31111
31112   function rescale() {
31113     logs = logp(base), pows = powp(base);
31114     if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows);
31115     return scale;
31116   }
31117
31118   scale.base = function(_) {
31119     return arguments.length ? (base = +_, rescale()) : base;
31120   };
31121
31122   scale.domain = function(_) {
31123     return arguments.length ? (domain(_), rescale()) : domain();
31124   };
31125
31126   scale.ticks = function(count) {
31127     var d = domain(),
31128         u = d[0],
31129         v = d[d.length - 1],
31130         r;
31131
31132     if (r = v < u) i = u, u = v, v = i;
31133
31134     var i = logs(u),
31135         j = logs(v),
31136         p,
31137         k,
31138         t,
31139         n = count == null ? 10 : +count,
31140         z = [];
31141
31142     if (!(base % 1) && j - i < n) {
31143       i = Math.round(i) - 1, j = Math.round(j) + 1;
31144       if (u > 0) for (; i < j; ++i) {
31145         for (k = 1, p = pows(i); k < base; ++k) {
31146           t = p * k;
31147           if (t < u) continue;
31148           if (t > v) break;
31149           z.push(t);
31150         }
31151       } else for (; i < j; ++i) {
31152         for (k = base - 1, p = pows(i); k >= 1; --k) {
31153           t = p * k;
31154           if (t < u) continue;
31155           if (t > v) break;
31156           z.push(t);
31157         }
31158       }
31159     } else {
31160       z = ticks(i, j, Math.min(j - i, n)).map(pows);
31161     }
31162
31163     return r ? z.reverse() : z;
31164   };
31165
31166   scale.tickFormat = function(count, specifier) {
31167     if (specifier == null) specifier = base === 10 ? ".0e" : ",";
31168     if (typeof specifier !== "function") specifier = format(specifier);
31169     if (count === Infinity) return specifier;
31170     if (count == null) count = 10;
31171     var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
31172     return function(d) {
31173       var i = d / pows(Math.round(logs(d)));
31174       if (i * base < base - 0.5) i *= base;
31175       return i <= k ? specifier(d) : "";
31176     };
31177   };
31178
31179   scale.nice = function() {
31180     return domain(nice(domain(), {
31181       floor: function(x) { return pows(Math.floor(logs(x))); },
31182       ceil: function(x) { return pows(Math.ceil(logs(x))); }
31183     }));
31184   };
31185
31186   scale.copy = function() {
31187     return copy(scale, log$1().base(base));
31188   };
31189
31190   return scale;
31191 }
31192
31193 function raise$1(x, exponent) {
31194   return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
31195 }
31196
31197 function pow$1() {
31198   var exponent = 1,
31199       scale = continuous(deinterpolate, reinterpolate),
31200       domain = scale.domain;
31201
31202   function deinterpolate(a, b) {
31203     return (b = raise$1(b, exponent) - (a = raise$1(a, exponent)))
31204         ? function(x) { return (raise$1(x, exponent) - a) / b; }
31205         : constant$9(b);
31206   }
31207
31208   function reinterpolate(a, b) {
31209     b = raise$1(b, exponent) - (a = raise$1(a, exponent));
31210     return function(t) { return raise$1(a + b * t, 1 / exponent); };
31211   }
31212
31213   scale.exponent = function(_) {
31214     return arguments.length ? (exponent = +_, domain(domain())) : exponent;
31215   };
31216
31217   scale.copy = function() {
31218     return copy(scale, pow$1().exponent(exponent));
31219   };
31220
31221   return linearish(scale);
31222 }
31223
31224 function sqrt$1() {
31225   return pow$1().exponent(0.5);
31226 }
31227
31228 function quantile() {
31229   var domain = [],
31230       range = [],
31231       thresholds = [];
31232
31233   function rescale() {
31234     var i = 0, n = Math.max(1, range.length);
31235     thresholds = new Array(n - 1);
31236     while (++i < n) thresholds[i - 1] = threshold(domain, i / n);
31237     return scale;
31238   }
31239
31240   function scale(x) {
31241     if (!isNaN(x = +x)) return range[bisectRight(thresholds, x)];
31242   }
31243
31244   scale.invertExtent = function(y) {
31245     var i = range.indexOf(y);
31246     return i < 0 ? [NaN, NaN] : [
31247       i > 0 ? thresholds[i - 1] : domain[0],
31248       i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
31249     ];
31250   };
31251
31252   scale.domain = function(_) {
31253     if (!arguments.length) return domain.slice();
31254     domain = [];
31255     for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);
31256     domain.sort(ascending);
31257     return rescale();
31258   };
31259
31260   scale.range = function(_) {
31261     return arguments.length ? (range = slice$5.call(_), rescale()) : range.slice();
31262   };
31263
31264   scale.quantiles = function() {
31265     return thresholds.slice();
31266   };
31267
31268   scale.copy = function() {
31269     return quantile()
31270         .domain(domain)
31271         .range(range);
31272   };
31273
31274   return scale;
31275 }
31276
31277 function quantize$1() {
31278   var x0 = 0,
31279       x1 = 1,
31280       n = 1,
31281       domain = [0.5],
31282       range = [0, 1];
31283
31284   function scale(x) {
31285     if (x <= x) return range[bisectRight(domain, x, 0, n)];
31286   }
31287
31288   function rescale() {
31289     var i = -1;
31290     domain = new Array(n);
31291     while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
31292     return scale;
31293   }
31294
31295   scale.domain = function(_) {
31296     return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1];
31297   };
31298
31299   scale.range = function(_) {
31300     return arguments.length ? (n = (range = slice$5.call(_)).length - 1, rescale()) : range.slice();
31301   };
31302
31303   scale.invertExtent = function(y) {
31304     var i = range.indexOf(y);
31305     return i < 0 ? [NaN, NaN]
31306         : i < 1 ? [x0, domain[0]]
31307         : i >= n ? [domain[n - 1], x1]
31308         : [domain[i - 1], domain[i]];
31309   };
31310
31311   scale.copy = function() {
31312     return quantize$1()
31313         .domain([x0, x1])
31314         .range(range);
31315   };
31316
31317   return linearish(scale);
31318 }
31319
31320 function threshold$1() {
31321   var domain = [0.5],
31322       range = [0, 1],
31323       n = 1;
31324
31325   function scale(x) {
31326     if (x <= x) return range[bisectRight(domain, x, 0, n)];
31327   }
31328
31329   scale.domain = function(_) {
31330     return arguments.length ? (domain = slice$5.call(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
31331   };
31332
31333   scale.range = function(_) {
31334     return arguments.length ? (range = slice$5.call(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();
31335   };
31336
31337   scale.invertExtent = function(y) {
31338     var i = range.indexOf(y);
31339     return [domain[i - 1], domain[i]];
31340   };
31341
31342   scale.copy = function() {
31343     return threshold$1()
31344         .domain(domain)
31345         .range(range);
31346   };
31347
31348   return scale;
31349 }
31350
31351 var t0$1 = new Date;
31352 var t1$1 = new Date;
31353
31354 function newInterval(floori, offseti, count, field) {
31355
31356   function interval(date) {
31357     return floori(date = new Date(+date)), date;
31358   }
31359
31360   interval.floor = interval;
31361
31362   interval.ceil = function(date) {
31363     return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
31364   };
31365
31366   interval.round = function(date) {
31367     var d0 = interval(date),
31368         d1 = interval.ceil(date);
31369     return date - d0 < d1 - date ? d0 : d1;
31370   };
31371
31372   interval.offset = function(date, step) {
31373     return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
31374   };
31375
31376   interval.range = function(start, stop, step) {
31377     var range = [];
31378     start = interval.ceil(start);
31379     step = step == null ? 1 : Math.floor(step);
31380     if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
31381     do range.push(new Date(+start)); while (offseti(start, step), floori(start), start < stop)
31382     return range;
31383   };
31384
31385   interval.filter = function(test) {
31386     return newInterval(function(date) {
31387       if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);
31388     }, function(date, step) {
31389       if (date >= date) {
31390         if (step < 0) while (++step <= 0) {
31391           while (offseti(date, -1), !test(date)) {} // eslint-disable-line no-empty
31392         } else while (--step >= 0) {
31393           while (offseti(date, +1), !test(date)) {} // eslint-disable-line no-empty
31394         }
31395       }
31396     });
31397   };
31398
31399   if (count) {
31400     interval.count = function(start, end) {
31401       t0$1.setTime(+start), t1$1.setTime(+end);
31402       floori(t0$1), floori(t1$1);
31403       return Math.floor(count(t0$1, t1$1));
31404     };
31405
31406     interval.every = function(step) {
31407       step = Math.floor(step);
31408       return !isFinite(step) || !(step > 0) ? null
31409           : !(step > 1) ? interval
31410           : interval.filter(field
31411               ? function(d) { return field(d) % step === 0; }
31412               : function(d) { return interval.count(0, d) % step === 0; });
31413     };
31414   }
31415
31416   return interval;
31417 }
31418
31419 var millisecond = newInterval(function() {
31420   // noop
31421 }, function(date, step) {
31422   date.setTime(+date + step);
31423 }, function(start, end) {
31424   return end - start;
31425 });
31426
31427 // An optimized implementation for this simple case.
31428 millisecond.every = function(k) {
31429   k = Math.floor(k);
31430   if (!isFinite(k) || !(k > 0)) return null;
31431   if (!(k > 1)) return millisecond;
31432   return newInterval(function(date) {
31433     date.setTime(Math.floor(date / k) * k);
31434   }, function(date, step) {
31435     date.setTime(+date + step * k);
31436   }, function(start, end) {
31437     return (end - start) / k;
31438   });
31439 };
31440
31441 var milliseconds = millisecond.range;
31442
31443 var durationSecond$1 = 1e3;
31444 var durationMinute$1 = 6e4;
31445 var durationHour$1 = 36e5;
31446 var durationDay$1 = 864e5;
31447 var durationWeek$1 = 6048e5;
31448
31449 var second = newInterval(function(date) {
31450   date.setTime(Math.floor(date / durationSecond$1) * durationSecond$1);
31451 }, function(date, step) {
31452   date.setTime(+date + step * durationSecond$1);
31453 }, function(start, end) {
31454   return (end - start) / durationSecond$1;
31455 }, function(date) {
31456   return date.getUTCSeconds();
31457 });
31458
31459 var seconds = second.range;
31460
31461 var minute = newInterval(function(date) {
31462   date.setTime(Math.floor(date / durationMinute$1) * durationMinute$1);
31463 }, function(date, step) {
31464   date.setTime(+date + step * durationMinute$1);
31465 }, function(start, end) {
31466   return (end - start) / durationMinute$1;
31467 }, function(date) {
31468   return date.getMinutes();
31469 });
31470
31471 var minutes = minute.range;
31472
31473 var hour = newInterval(function(date) {
31474   var offset = date.getTimezoneOffset() * durationMinute$1 % durationHour$1;
31475   if (offset < 0) offset += durationHour$1;
31476   date.setTime(Math.floor((+date - offset) / durationHour$1) * durationHour$1 + offset);
31477 }, function(date, step) {
31478   date.setTime(+date + step * durationHour$1);
31479 }, function(start, end) {
31480   return (end - start) / durationHour$1;
31481 }, function(date) {
31482   return date.getHours();
31483 });
31484
31485 var hours = hour.range;
31486
31487 var day = newInterval(function(date) {
31488   date.setHours(0, 0, 0, 0);
31489 }, function(date, step) {
31490   date.setDate(date.getDate() + step);
31491 }, function(start, end) {
31492   return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationDay$1;
31493 }, function(date) {
31494   return date.getDate() - 1;
31495 });
31496
31497 var days = day.range;
31498
31499 function weekday(i) {
31500   return newInterval(function(date) {
31501     date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
31502     date.setHours(0, 0, 0, 0);
31503   }, function(date, step) {
31504     date.setDate(date.getDate() + step * 7);
31505   }, function(start, end) {
31506     return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationWeek$1;
31507   });
31508 }
31509
31510 var sunday = weekday(0);
31511 var monday = weekday(1);
31512 var tuesday = weekday(2);
31513 var wednesday = weekday(3);
31514 var thursday = weekday(4);
31515 var friday = weekday(5);
31516 var saturday = weekday(6);
31517
31518 var sundays = sunday.range;
31519 var mondays = monday.range;
31520 var tuesdays = tuesday.range;
31521 var wednesdays = wednesday.range;
31522 var thursdays = thursday.range;
31523 var fridays = friday.range;
31524 var saturdays = saturday.range;
31525
31526 var month = newInterval(function(date) {
31527   date.setDate(1);
31528   date.setHours(0, 0, 0, 0);
31529 }, function(date, step) {
31530   date.setMonth(date.getMonth() + step);
31531 }, function(start, end) {
31532   return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
31533 }, function(date) {
31534   return date.getMonth();
31535 });
31536
31537 var months = month.range;
31538
31539 var year = newInterval(function(date) {
31540   date.setMonth(0, 1);
31541   date.setHours(0, 0, 0, 0);
31542 }, function(date, step) {
31543   date.setFullYear(date.getFullYear() + step);
31544 }, function(start, end) {
31545   return end.getFullYear() - start.getFullYear();
31546 }, function(date) {
31547   return date.getFullYear();
31548 });
31549
31550 // An optimized implementation for this simple case.
31551 year.every = function(k) {
31552   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31553     date.setFullYear(Math.floor(date.getFullYear() / k) * k);
31554     date.setMonth(0, 1);
31555     date.setHours(0, 0, 0, 0);
31556   }, function(date, step) {
31557     date.setFullYear(date.getFullYear() + step * k);
31558   });
31559 };
31560
31561 var years = year.range;
31562
31563 var utcMinute = newInterval(function(date) {
31564   date.setUTCSeconds(0, 0);
31565 }, function(date, step) {
31566   date.setTime(+date + step * durationMinute$1);
31567 }, function(start, end) {
31568   return (end - start) / durationMinute$1;
31569 }, function(date) {
31570   return date.getUTCMinutes();
31571 });
31572
31573 var utcMinutes = utcMinute.range;
31574
31575 var utcHour = newInterval(function(date) {
31576   date.setUTCMinutes(0, 0, 0);
31577 }, function(date, step) {
31578   date.setTime(+date + step * durationHour$1);
31579 }, function(start, end) {
31580   return (end - start) / durationHour$1;
31581 }, function(date) {
31582   return date.getUTCHours();
31583 });
31584
31585 var utcHours = utcHour.range;
31586
31587 var utcDay = newInterval(function(date) {
31588   date.setUTCHours(0, 0, 0, 0);
31589 }, function(date, step) {
31590   date.setUTCDate(date.getUTCDate() + step);
31591 }, function(start, end) {
31592   return (end - start) / durationDay$1;
31593 }, function(date) {
31594   return date.getUTCDate() - 1;
31595 });
31596
31597 var utcDays = utcDay.range;
31598
31599 function utcWeekday(i) {
31600   return newInterval(function(date) {
31601     date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
31602     date.setUTCHours(0, 0, 0, 0);
31603   }, function(date, step) {
31604     date.setUTCDate(date.getUTCDate() + step * 7);
31605   }, function(start, end) {
31606     return (end - start) / durationWeek$1;
31607   });
31608 }
31609
31610 var utcSunday = utcWeekday(0);
31611 var utcMonday = utcWeekday(1);
31612 var utcTuesday = utcWeekday(2);
31613 var utcWednesday = utcWeekday(3);
31614 var utcThursday = utcWeekday(4);
31615 var utcFriday = utcWeekday(5);
31616 var utcSaturday = utcWeekday(6);
31617
31618 var utcSundays = utcSunday.range;
31619 var utcMondays = utcMonday.range;
31620 var utcTuesdays = utcTuesday.range;
31621 var utcWednesdays = utcWednesday.range;
31622 var utcThursdays = utcThursday.range;
31623 var utcFridays = utcFriday.range;
31624 var utcSaturdays = utcSaturday.range;
31625
31626 var utcMonth = newInterval(function(date) {
31627   date.setUTCDate(1);
31628   date.setUTCHours(0, 0, 0, 0);
31629 }, function(date, step) {
31630   date.setUTCMonth(date.getUTCMonth() + step);
31631 }, function(start, end) {
31632   return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
31633 }, function(date) {
31634   return date.getUTCMonth();
31635 });
31636
31637 var utcMonths = utcMonth.range;
31638
31639 var utcYear = newInterval(function(date) {
31640   date.setUTCMonth(0, 1);
31641   date.setUTCHours(0, 0, 0, 0);
31642 }, function(date, step) {
31643   date.setUTCFullYear(date.getUTCFullYear() + step);
31644 }, function(start, end) {
31645   return end.getUTCFullYear() - start.getUTCFullYear();
31646 }, function(date) {
31647   return date.getUTCFullYear();
31648 });
31649
31650 // An optimized implementation for this simple case.
31651 utcYear.every = function(k) {
31652   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31653     date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
31654     date.setUTCMonth(0, 1);
31655     date.setUTCHours(0, 0, 0, 0);
31656   }, function(date, step) {
31657     date.setUTCFullYear(date.getUTCFullYear() + step * k);
31658   });
31659 };
31660
31661 var utcYears = utcYear.range;
31662
31663 function localDate(d) {
31664   if (0 <= d.y && d.y < 100) {
31665     var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);
31666     date.setFullYear(d.y);
31667     return date;
31668   }
31669   return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);
31670 }
31671
31672 function utcDate(d) {
31673   if (0 <= d.y && d.y < 100) {
31674     var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));
31675     date.setUTCFullYear(d.y);
31676     return date;
31677   }
31678   return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
31679 }
31680
31681 function newYear(y) {
31682   return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0};
31683 }
31684
31685 function formatLocale$1(locale) {
31686   var locale_dateTime = locale.dateTime,
31687       locale_date = locale.date,
31688       locale_time = locale.time,
31689       locale_periods = locale.periods,
31690       locale_weekdays = locale.days,
31691       locale_shortWeekdays = locale.shortDays,
31692       locale_months = locale.months,
31693       locale_shortMonths = locale.shortMonths;
31694
31695   var periodRe = formatRe(locale_periods),
31696       periodLookup = formatLookup(locale_periods),
31697       weekdayRe = formatRe(locale_weekdays),
31698       weekdayLookup = formatLookup(locale_weekdays),
31699       shortWeekdayRe = formatRe(locale_shortWeekdays),
31700       shortWeekdayLookup = formatLookup(locale_shortWeekdays),
31701       monthRe = formatRe(locale_months),
31702       monthLookup = formatLookup(locale_months),
31703       shortMonthRe = formatRe(locale_shortMonths),
31704       shortMonthLookup = formatLookup(locale_shortMonths);
31705
31706   var formats = {
31707     "a": formatShortWeekday,
31708     "A": formatWeekday,
31709     "b": formatShortMonth,
31710     "B": formatMonth,
31711     "c": null,
31712     "d": formatDayOfMonth,
31713     "e": formatDayOfMonth,
31714     "H": formatHour24,
31715     "I": formatHour12,
31716     "j": formatDayOfYear,
31717     "L": formatMilliseconds,
31718     "m": formatMonthNumber,
31719     "M": formatMinutes,
31720     "p": formatPeriod,
31721     "S": formatSeconds,
31722     "U": formatWeekNumberSunday,
31723     "w": formatWeekdayNumber,
31724     "W": formatWeekNumberMonday,
31725     "x": null,
31726     "X": null,
31727     "y": formatYear,
31728     "Y": formatFullYear,
31729     "Z": formatZone,
31730     "%": formatLiteralPercent
31731   };
31732
31733   var utcFormats = {
31734     "a": formatUTCShortWeekday,
31735     "A": formatUTCWeekday,
31736     "b": formatUTCShortMonth,
31737     "B": formatUTCMonth,
31738     "c": null,
31739     "d": formatUTCDayOfMonth,
31740     "e": formatUTCDayOfMonth,
31741     "H": formatUTCHour24,
31742     "I": formatUTCHour12,
31743     "j": formatUTCDayOfYear,
31744     "L": formatUTCMilliseconds,
31745     "m": formatUTCMonthNumber,
31746     "M": formatUTCMinutes,
31747     "p": formatUTCPeriod,
31748     "S": formatUTCSeconds,
31749     "U": formatUTCWeekNumberSunday,
31750     "w": formatUTCWeekdayNumber,
31751     "W": formatUTCWeekNumberMonday,
31752     "x": null,
31753     "X": null,
31754     "y": formatUTCYear,
31755     "Y": formatUTCFullYear,
31756     "Z": formatUTCZone,
31757     "%": formatLiteralPercent
31758   };
31759
31760   var parses = {
31761     "a": parseShortWeekday,
31762     "A": parseWeekday,
31763     "b": parseShortMonth,
31764     "B": parseMonth,
31765     "c": parseLocaleDateTime,
31766     "d": parseDayOfMonth,
31767     "e": parseDayOfMonth,
31768     "H": parseHour24,
31769     "I": parseHour24,
31770     "j": parseDayOfYear,
31771     "L": parseMilliseconds,
31772     "m": parseMonthNumber,
31773     "M": parseMinutes,
31774     "p": parsePeriod,
31775     "S": parseSeconds,
31776     "U": parseWeekNumberSunday,
31777     "w": parseWeekdayNumber,
31778     "W": parseWeekNumberMonday,
31779     "x": parseLocaleDate,
31780     "X": parseLocaleTime,
31781     "y": parseYear,
31782     "Y": parseFullYear,
31783     "Z": parseZone,
31784     "%": parseLiteralPercent
31785   };
31786
31787   // These recursive directive definitions must be deferred.
31788   formats.x = newFormat(locale_date, formats);
31789   formats.X = newFormat(locale_time, formats);
31790   formats.c = newFormat(locale_dateTime, formats);
31791   utcFormats.x = newFormat(locale_date, utcFormats);
31792   utcFormats.X = newFormat(locale_time, utcFormats);
31793   utcFormats.c = newFormat(locale_dateTime, utcFormats);
31794
31795   function newFormat(specifier, formats) {
31796     return function(date) {
31797       var string = [],
31798           i = -1,
31799           j = 0,
31800           n = specifier.length,
31801           c,
31802           pad,
31803           format;
31804
31805       if (!(date instanceof Date)) date = new Date(+date);
31806
31807       while (++i < n) {
31808         if (specifier.charCodeAt(i) === 37) {
31809           string.push(specifier.slice(j, i));
31810           if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
31811           else pad = c === "e" ? " " : "0";
31812           if (format = formats[c]) c = format(date, pad);
31813           string.push(c);
31814           j = i + 1;
31815         }
31816       }
31817
31818       string.push(specifier.slice(j, i));
31819       return string.join("");
31820     };
31821   }
31822
31823   function newParse(specifier, newDate) {
31824     return function(string) {
31825       var d = newYear(1900),
31826           i = parseSpecifier(d, specifier, string += "", 0);
31827       if (i != string.length) return null;
31828
31829       // The am-pm flag is 0 for AM, and 1 for PM.
31830       if ("p" in d) d.H = d.H % 12 + d.p * 12;
31831
31832       // Convert day-of-week and week-of-year to day-of-year.
31833       if ("W" in d || "U" in d) {
31834         if (!("w" in d)) d.w = "W" in d ? 1 : 0;
31835         var day$$1 = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay();
31836         d.m = 0;
31837         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;
31838       }
31839
31840       // If a time zone is specified, all fields are interpreted as UTC and then
31841       // offset according to the specified time zone.
31842       if ("Z" in d) {
31843         d.H += d.Z / 100 | 0;
31844         d.M += d.Z % 100;
31845         return utcDate(d);
31846       }
31847
31848       // Otherwise, all fields are in local time.
31849       return newDate(d);
31850     };
31851   }
31852
31853   function parseSpecifier(d, specifier, string, j) {
31854     var i = 0,
31855         n = specifier.length,
31856         m = string.length,
31857         c,
31858         parse;
31859
31860     while (i < n) {
31861       if (j >= m) return -1;
31862       c = specifier.charCodeAt(i++);
31863       if (c === 37) {
31864         c = specifier.charAt(i++);
31865         parse = parses[c in pads ? specifier.charAt(i++) : c];
31866         if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
31867       } else if (c != string.charCodeAt(j++)) {
31868         return -1;
31869       }
31870     }
31871
31872     return j;
31873   }
31874
31875   function parsePeriod(d, string, i) {
31876     var n = periodRe.exec(string.slice(i));
31877     return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31878   }
31879
31880   function parseShortWeekday(d, string, i) {
31881     var n = shortWeekdayRe.exec(string.slice(i));
31882     return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31883   }
31884
31885   function parseWeekday(d, string, i) {
31886     var n = weekdayRe.exec(string.slice(i));
31887     return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31888   }
31889
31890   function parseShortMonth(d, string, i) {
31891     var n = shortMonthRe.exec(string.slice(i));
31892     return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31893   }
31894
31895   function parseMonth(d, string, i) {
31896     var n = monthRe.exec(string.slice(i));
31897     return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31898   }
31899
31900   function parseLocaleDateTime(d, string, i) {
31901     return parseSpecifier(d, locale_dateTime, string, i);
31902   }
31903
31904   function parseLocaleDate(d, string, i) {
31905     return parseSpecifier(d, locale_date, string, i);
31906   }
31907
31908   function parseLocaleTime(d, string, i) {
31909     return parseSpecifier(d, locale_time, string, i);
31910   }
31911
31912   function formatShortWeekday(d) {
31913     return locale_shortWeekdays[d.getDay()];
31914   }
31915
31916   function formatWeekday(d) {
31917     return locale_weekdays[d.getDay()];
31918   }
31919
31920   function formatShortMonth(d) {
31921     return locale_shortMonths[d.getMonth()];
31922   }
31923
31924   function formatMonth(d) {
31925     return locale_months[d.getMonth()];
31926   }
31927
31928   function formatPeriod(d) {
31929     return locale_periods[+(d.getHours() >= 12)];
31930   }
31931
31932   function formatUTCShortWeekday(d) {
31933     return locale_shortWeekdays[d.getUTCDay()];
31934   }
31935
31936   function formatUTCWeekday(d) {
31937     return locale_weekdays[d.getUTCDay()];
31938   }
31939
31940   function formatUTCShortMonth(d) {
31941     return locale_shortMonths[d.getUTCMonth()];
31942   }
31943
31944   function formatUTCMonth(d) {
31945     return locale_months[d.getUTCMonth()];
31946   }
31947
31948   function formatUTCPeriod(d) {
31949     return locale_periods[+(d.getUTCHours() >= 12)];
31950   }
31951
31952   return {
31953     format: function(specifier) {
31954       var f = newFormat(specifier += "", formats);
31955       f.toString = function() { return specifier; };
31956       return f;
31957     },
31958     parse: function(specifier) {
31959       var p = newParse(specifier += "", localDate);
31960       p.toString = function() { return specifier; };
31961       return p;
31962     },
31963     utcFormat: function(specifier) {
31964       var f = newFormat(specifier += "", utcFormats);
31965       f.toString = function() { return specifier; };
31966       return f;
31967     },
31968     utcParse: function(specifier) {
31969       var p = newParse(specifier, utcDate);
31970       p.toString = function() { return specifier; };
31971       return p;
31972     }
31973   };
31974 }
31975
31976 var pads = {"-": "", "_": " ", "0": "0"};
31977 var numberRe = /^\s*\d+/;
31978 var percentRe = /^%/;
31979 var requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
31980
31981 function pad(value, fill, width) {
31982   var sign = value < 0 ? "-" : "",
31983       string = (sign ? -value : value) + "",
31984       length = string.length;
31985   return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
31986 }
31987
31988 function requote(s) {
31989   return s.replace(requoteRe, "\\$&");
31990 }
31991
31992 function formatRe(names) {
31993   return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
31994 }
31995
31996 function formatLookup(names) {
31997   var map = {}, i = -1, n = names.length;
31998   while (++i < n) map[names[i].toLowerCase()] = i;
31999   return map;
32000 }
32001
32002 function parseWeekdayNumber(d, string, i) {
32003   var n = numberRe.exec(string.slice(i, i + 1));
32004   return n ? (d.w = +n[0], i + n[0].length) : -1;
32005 }
32006
32007 function parseWeekNumberSunday(d, string, i) {
32008   var n = numberRe.exec(string.slice(i));
32009   return n ? (d.U = +n[0], i + n[0].length) : -1;
32010 }
32011
32012 function parseWeekNumberMonday(d, string, i) {
32013   var n = numberRe.exec(string.slice(i));
32014   return n ? (d.W = +n[0], i + n[0].length) : -1;
32015 }
32016
32017 function parseFullYear(d, string, i) {
32018   var n = numberRe.exec(string.slice(i, i + 4));
32019   return n ? (d.y = +n[0], i + n[0].length) : -1;
32020 }
32021
32022 function parseYear(d, string, i) {
32023   var n = numberRe.exec(string.slice(i, i + 2));
32024   return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
32025 }
32026
32027 function parseZone(d, string, i) {
32028   var n = /^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(string.slice(i, i + 6));
32029   return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1;
32030 }
32031
32032 function parseMonthNumber(d, string, i) {
32033   var n = numberRe.exec(string.slice(i, i + 2));
32034   return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
32035 }
32036
32037 function parseDayOfMonth(d, string, i) {
32038   var n = numberRe.exec(string.slice(i, i + 2));
32039   return n ? (d.d = +n[0], i + n[0].length) : -1;
32040 }
32041
32042 function parseDayOfYear(d, string, i) {
32043   var n = numberRe.exec(string.slice(i, i + 3));
32044   return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;
32045 }
32046
32047 function parseHour24(d, string, i) {
32048   var n = numberRe.exec(string.slice(i, i + 2));
32049   return n ? (d.H = +n[0], i + n[0].length) : -1;
32050 }
32051
32052 function parseMinutes(d, string, i) {
32053   var n = numberRe.exec(string.slice(i, i + 2));
32054   return n ? (d.M = +n[0], i + n[0].length) : -1;
32055 }
32056
32057 function parseSeconds(d, string, i) {
32058   var n = numberRe.exec(string.slice(i, i + 2));
32059   return n ? (d.S = +n[0], i + n[0].length) : -1;
32060 }
32061
32062 function parseMilliseconds(d, string, i) {
32063   var n = numberRe.exec(string.slice(i, i + 3));
32064   return n ? (d.L = +n[0], i + n[0].length) : -1;
32065 }
32066
32067 function parseLiteralPercent(d, string, i) {
32068   var n = percentRe.exec(string.slice(i, i + 1));
32069   return n ? i + n[0].length : -1;
32070 }
32071
32072 function formatDayOfMonth(d, p) {
32073   return pad(d.getDate(), p, 2);
32074 }
32075
32076 function formatHour24(d, p) {
32077   return pad(d.getHours(), p, 2);
32078 }
32079
32080 function formatHour12(d, p) {
32081   return pad(d.getHours() % 12 || 12, p, 2);
32082 }
32083
32084 function formatDayOfYear(d, p) {
32085   return pad(1 + day.count(year(d), d), p, 3);
32086 }
32087
32088 function formatMilliseconds(d, p) {
32089   return pad(d.getMilliseconds(), p, 3);
32090 }
32091
32092 function formatMonthNumber(d, p) {
32093   return pad(d.getMonth() + 1, p, 2);
32094 }
32095
32096 function formatMinutes(d, p) {
32097   return pad(d.getMinutes(), p, 2);
32098 }
32099
32100 function formatSeconds(d, p) {
32101   return pad(d.getSeconds(), p, 2);
32102 }
32103
32104 function formatWeekNumberSunday(d, p) {
32105   return pad(sunday.count(year(d), d), p, 2);
32106 }
32107
32108 function formatWeekdayNumber(d) {
32109   return d.getDay();
32110 }
32111
32112 function formatWeekNumberMonday(d, p) {
32113   return pad(monday.count(year(d), d), p, 2);
32114 }
32115
32116 function formatYear(d, p) {
32117   return pad(d.getFullYear() % 100, p, 2);
32118 }
32119
32120 function formatFullYear(d, p) {
32121   return pad(d.getFullYear() % 10000, p, 4);
32122 }
32123
32124 function formatZone(d) {
32125   var z = d.getTimezoneOffset();
32126   return (z > 0 ? "-" : (z *= -1, "+"))
32127       + pad(z / 60 | 0, "0", 2)
32128       + pad(z % 60, "0", 2);
32129 }
32130
32131 function formatUTCDayOfMonth(d, p) {
32132   return pad(d.getUTCDate(), p, 2);
32133 }
32134
32135 function formatUTCHour24(d, p) {
32136   return pad(d.getUTCHours(), p, 2);
32137 }
32138
32139 function formatUTCHour12(d, p) {
32140   return pad(d.getUTCHours() % 12 || 12, p, 2);
32141 }
32142
32143 function formatUTCDayOfYear(d, p) {
32144   return pad(1 + utcDay.count(utcYear(d), d), p, 3);
32145 }
32146
32147 function formatUTCMilliseconds(d, p) {
32148   return pad(d.getUTCMilliseconds(), p, 3);
32149 }
32150
32151 function formatUTCMonthNumber(d, p) {
32152   return pad(d.getUTCMonth() + 1, p, 2);
32153 }
32154
32155 function formatUTCMinutes(d, p) {
32156   return pad(d.getUTCMinutes(), p, 2);
32157 }
32158
32159 function formatUTCSeconds(d, p) {
32160   return pad(d.getUTCSeconds(), p, 2);
32161 }
32162
32163 function formatUTCWeekNumberSunday(d, p) {
32164   return pad(utcSunday.count(utcYear(d), d), p, 2);
32165 }
32166
32167 function formatUTCWeekdayNumber(d) {
32168   return d.getUTCDay();
32169 }
32170
32171 function formatUTCWeekNumberMonday(d, p) {
32172   return pad(utcMonday.count(utcYear(d), d), p, 2);
32173 }
32174
32175 function formatUTCYear(d, p) {
32176   return pad(d.getUTCFullYear() % 100, p, 2);
32177 }
32178
32179 function formatUTCFullYear(d, p) {
32180   return pad(d.getUTCFullYear() % 10000, p, 4);
32181 }
32182
32183 function formatUTCZone() {
32184   return "+0000";
32185 }
32186
32187 function formatLiteralPercent() {
32188   return "%";
32189 }
32190
32191 var locale$2;
32192 var timeFormat;
32193 var timeParse;
32194 var utcFormat;
32195 var utcParse;
32196
32197 defaultLocale$1({
32198   dateTime: "%x, %X",
32199   date: "%-m/%-d/%Y",
32200   time: "%-I:%M:%S %p",
32201   periods: ["AM", "PM"],
32202   days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
32203   shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
32204   months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
32205   shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
32206 });
32207
32208 function defaultLocale$1(definition) {
32209   locale$2 = formatLocale$1(definition);
32210   timeFormat = locale$2.format;
32211   timeParse = locale$2.parse;
32212   utcFormat = locale$2.utcFormat;
32213   utcParse = locale$2.utcParse;
32214   return locale$2;
32215 }
32216
32217 var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ";
32218
32219 function formatIsoNative(date) {
32220   return date.toISOString();
32221 }
32222
32223 var formatIso = Date.prototype.toISOString
32224     ? formatIsoNative
32225     : utcFormat(isoSpecifier);
32226
32227 function parseIsoNative(string) {
32228   var date = new Date(string);
32229   return isNaN(date) ? null : date;
32230 }
32231
32232 var parseIso = +new Date("2000-01-01T00:00:00.000Z")
32233     ? parseIsoNative
32234     : utcParse(isoSpecifier);
32235
32236 var durationSecond = 1000;
32237 var durationMinute = durationSecond * 60;
32238 var durationHour = durationMinute * 60;
32239 var durationDay = durationHour * 24;
32240 var durationWeek = durationDay * 7;
32241 var durationMonth = durationDay * 30;
32242 var durationYear = durationDay * 365;
32243
32244 function date$1(t) {
32245   return new Date(t);
32246 }
32247
32248 function number$3(t) {
32249   return t instanceof Date ? +t : +new Date(+t);
32250 }
32251
32252 function calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format) {
32253   var scale = continuous(deinterpolateLinear, reinterpolate),
32254       invert = scale.invert,
32255       domain = scale.domain;
32256
32257   var formatMillisecond = format(".%L"),
32258       formatSecond = format(":%S"),
32259       formatMinute = format("%I:%M"),
32260       formatHour = format("%I %p"),
32261       formatDay = format("%a %d"),
32262       formatWeek = format("%b %d"),
32263       formatMonth = format("%B"),
32264       formatYear = format("%Y");
32265
32266   var tickIntervals = [
32267     [second$$1,  1,      durationSecond],
32268     [second$$1,  5,  5 * durationSecond],
32269     [second$$1, 15, 15 * durationSecond],
32270     [second$$1, 30, 30 * durationSecond],
32271     [minute$$1,  1,      durationMinute],
32272     [minute$$1,  5,  5 * durationMinute],
32273     [minute$$1, 15, 15 * durationMinute],
32274     [minute$$1, 30, 30 * durationMinute],
32275     [  hour$$1,  1,      durationHour  ],
32276     [  hour$$1,  3,  3 * durationHour  ],
32277     [  hour$$1,  6,  6 * durationHour  ],
32278     [  hour$$1, 12, 12 * durationHour  ],
32279     [   day$$1,  1,      durationDay   ],
32280     [   day$$1,  2,  2 * durationDay   ],
32281     [  week,  1,      durationWeek  ],
32282     [ month$$1,  1,      durationMonth ],
32283     [ month$$1,  3,  3 * durationMonth ],
32284     [  year$$1,  1,      durationYear  ]
32285   ];
32286
32287   function tickFormat(date$$1) {
32288     return (second$$1(date$$1) < date$$1 ? formatMillisecond
32289         : minute$$1(date$$1) < date$$1 ? formatSecond
32290         : hour$$1(date$$1) < date$$1 ? formatMinute
32291         : day$$1(date$$1) < date$$1 ? formatHour
32292         : month$$1(date$$1) < date$$1 ? (week(date$$1) < date$$1 ? formatDay : formatWeek)
32293         : year$$1(date$$1) < date$$1 ? formatMonth
32294         : formatYear)(date$$1);
32295   }
32296
32297   function tickInterval(interval$$1, start, stop, step) {
32298     if (interval$$1 == null) interval$$1 = 10;
32299
32300     // If a desired tick count is specified, pick a reasonable tick interval
32301     // based on the extent of the domain and a rough estimate of tick size.
32302     // Otherwise, assume interval is already a time interval and use it.
32303     if (typeof interval$$1 === "number") {
32304       var target = Math.abs(stop - start) / interval$$1,
32305           i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
32306       if (i === tickIntervals.length) {
32307         step = tickStep(start / durationYear, stop / durationYear, interval$$1);
32308         interval$$1 = year$$1;
32309       } else if (i) {
32310         i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
32311         step = i[1];
32312         interval$$1 = i[0];
32313       } else {
32314         step = tickStep(start, stop, interval$$1);
32315         interval$$1 = millisecond$$1;
32316       }
32317     }
32318
32319     return step == null ? interval$$1 : interval$$1.every(step);
32320   }
32321
32322   scale.invert = function(y) {
32323     return new Date(invert(y));
32324   };
32325
32326   scale.domain = function(_) {
32327     return arguments.length ? domain(map$3.call(_, number$3)) : domain().map(date$1);
32328   };
32329
32330   scale.ticks = function(interval$$1, step) {
32331     var d = domain(),
32332         t0 = d[0],
32333         t1 = d[d.length - 1],
32334         r = t1 < t0,
32335         t;
32336     if (r) t = t0, t0 = t1, t1 = t;
32337     t = tickInterval(interval$$1, t0, t1, step);
32338     t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
32339     return r ? t.reverse() : t;
32340   };
32341
32342   scale.tickFormat = function(count, specifier) {
32343     return specifier == null ? tickFormat : format(specifier);
32344   };
32345
32346   scale.nice = function(interval$$1, step) {
32347     var d = domain();
32348     return (interval$$1 = tickInterval(interval$$1, d[0], d[d.length - 1], step))
32349         ? domain(nice(d, interval$$1))
32350         : scale;
32351   };
32352
32353   scale.copy = function() {
32354     return copy(scale, calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format));
32355   };
32356
32357   return scale;
32358 }
32359
32360 var time = function() {
32361   return calendar(year, month, sunday, day, hour, minute, second, millisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
32362 };
32363
32364 var utcTime = function() {
32365   return calendar(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, millisecond, utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]);
32366 };
32367
32368 var colors = function(s) {
32369   return s.match(/.{6}/g).map(function(x) {
32370     return "#" + x;
32371   });
32372 };
32373
32374 var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf");
32375
32376 var category20b = colors("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6");
32377
32378 var category20c = colors("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9");
32379
32380 var category20 = colors("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5");
32381
32382 var cubehelix$3 = cubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0));
32383
32384 var warm = cubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32385
32386 var cool = cubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32387
32388 var rainbow = cubehelix();
32389
32390 var rainbow$1 = function(t) {
32391   if (t < 0 || t > 1) t -= Math.floor(t);
32392   var ts = Math.abs(t - 0.5);
32393   rainbow.h = 360 * t - 100;
32394   rainbow.s = 1.5 - 1.5 * ts;
32395   rainbow.l = 0.8 - 0.9 * ts;
32396   return rainbow + "";
32397 };
32398
32399 function ramp(range) {
32400   var n = range.length;
32401   return function(t) {
32402     return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
32403   };
32404 }
32405
32406 var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
32407
32408 var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
32409
32410 var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
32411
32412 var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
32413
32414 function sequential(interpolator) {
32415   var x0 = 0,
32416       x1 = 1,
32417       clamp = false;
32418
32419   function scale(x) {
32420     var t = (x - x0) / (x1 - x0);
32421     return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);
32422   }
32423
32424   scale.domain = function(_) {
32425     return arguments.length ? (x0 = +_[0], x1 = +_[1], scale) : [x0, x1];
32426   };
32427
32428   scale.clamp = function(_) {
32429     return arguments.length ? (clamp = !!_, scale) : clamp;
32430   };
32431
32432   scale.interpolator = function(_) {
32433     return arguments.length ? (interpolator = _, scale) : interpolator;
32434   };
32435
32436   scale.copy = function() {
32437     return sequential(interpolator).domain([x0, x1]).clamp(clamp);
32438   };
32439
32440   return linearish(scale);
32441 }
32442
32443 var constant$10 = function(x) {
32444   return function constant() {
32445     return x;
32446   };
32447 };
32448
32449 var abs$1 = Math.abs;
32450 var atan2$1 = Math.atan2;
32451 var cos$2 = Math.cos;
32452 var max$2 = Math.max;
32453 var min$1 = Math.min;
32454 var sin$2 = Math.sin;
32455 var sqrt$2 = Math.sqrt;
32456
32457 var epsilon$3 = 1e-12;
32458 var pi$4 = Math.PI;
32459 var halfPi$3 = pi$4 / 2;
32460 var tau$4 = 2 * pi$4;
32461
32462 function acos$1(x) {
32463   return x > 1 ? 0 : x < -1 ? pi$4 : Math.acos(x);
32464 }
32465
32466 function asin$1(x) {
32467   return x >= 1 ? halfPi$3 : x <= -1 ? -halfPi$3 : Math.asin(x);
32468 }
32469
32470 function arcInnerRadius(d) {
32471   return d.innerRadius;
32472 }
32473
32474 function arcOuterRadius(d) {
32475   return d.outerRadius;
32476 }
32477
32478 function arcStartAngle(d) {
32479   return d.startAngle;
32480 }
32481
32482 function arcEndAngle(d) {
32483   return d.endAngle;
32484 }
32485
32486 function arcPadAngle(d) {
32487   return d && d.padAngle; // Note: optional!
32488 }
32489
32490 function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
32491   var x10 = x1 - x0, y10 = y1 - y0,
32492       x32 = x3 - x2, y32 = y3 - y2,
32493       t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10);
32494   return [x0 + t * x10, y0 + t * y10];
32495 }
32496
32497 // Compute perpendicular offset line of length rc.
32498 // http://mathworld.wolfram.com/Circle-LineIntersection.html
32499 function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
32500   var x01 = x0 - x1,
32501       y01 = y0 - y1,
32502       lo = (cw ? rc : -rc) / sqrt$2(x01 * x01 + y01 * y01),
32503       ox = lo * y01,
32504       oy = -lo * x01,
32505       x11 = x0 + ox,
32506       y11 = y0 + oy,
32507       x10 = x1 + ox,
32508       y10 = y1 + oy,
32509       x00 = (x11 + x10) / 2,
32510       y00 = (y11 + y10) / 2,
32511       dx = x10 - x11,
32512       dy = y10 - y11,
32513       d2 = dx * dx + dy * dy,
32514       r = r1 - rc,
32515       D = x11 * y10 - x10 * y11,
32516       d = (dy < 0 ? -1 : 1) * sqrt$2(max$2(0, r * r * d2 - D * D)),
32517       cx0 = (D * dy - dx * d) / d2,
32518       cy0 = (-D * dx - dy * d) / d2,
32519       cx1 = (D * dy + dx * d) / d2,
32520       cy1 = (-D * dx + dy * d) / d2,
32521       dx0 = cx0 - x00,
32522       dy0 = cy0 - y00,
32523       dx1 = cx1 - x00,
32524       dy1 = cy1 - y00;
32525
32526   // Pick the closer of the two intersection points.
32527   // TODO Is there a faster way to determine which intersection to use?
32528   if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
32529
32530   return {
32531     cx: cx0,
32532     cy: cy0,
32533     x01: -ox,
32534     y01: -oy,
32535     x11: cx0 * (r1 / r - 1),
32536     y11: cy0 * (r1 / r - 1)
32537   };
32538 }
32539
32540 var arc = function() {
32541   var innerRadius = arcInnerRadius,
32542       outerRadius = arcOuterRadius,
32543       cornerRadius = constant$10(0),
32544       padRadius = null,
32545       startAngle = arcStartAngle,
32546       endAngle = arcEndAngle,
32547       padAngle = arcPadAngle,
32548       context = null;
32549
32550   function arc() {
32551     var buffer,
32552         r,
32553         r0 = +innerRadius.apply(this, arguments),
32554         r1 = +outerRadius.apply(this, arguments),
32555         a0 = startAngle.apply(this, arguments) - halfPi$3,
32556         a1 = endAngle.apply(this, arguments) - halfPi$3,
32557         da = abs$1(a1 - a0),
32558         cw = a1 > a0;
32559
32560     if (!context) context = buffer = path();
32561
32562     // Ensure that the outer radius is always larger than the inner radius.
32563     if (r1 < r0) r = r1, r1 = r0, r0 = r;
32564
32565     // Is it a point?
32566     if (!(r1 > epsilon$3)) context.moveTo(0, 0);
32567
32568     // Or is it a circle or annulus?
32569     else if (da > tau$4 - epsilon$3) {
32570       context.moveTo(r1 * cos$2(a0), r1 * sin$2(a0));
32571       context.arc(0, 0, r1, a0, a1, !cw);
32572       if (r0 > epsilon$3) {
32573         context.moveTo(r0 * cos$2(a1), r0 * sin$2(a1));
32574         context.arc(0, 0, r0, a1, a0, cw);
32575       }
32576     }
32577
32578     // Or is it a circular or annular sector?
32579     else {
32580       var a01 = a0,
32581           a11 = a1,
32582           a00 = a0,
32583           a10 = a1,
32584           da0 = da,
32585           da1 = da,
32586           ap = padAngle.apply(this, arguments) / 2,
32587           rp = (ap > epsilon$3) && (padRadius ? +padRadius.apply(this, arguments) : sqrt$2(r0 * r0 + r1 * r1)),
32588           rc = min$1(abs$1(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
32589           rc0 = rc,
32590           rc1 = rc,
32591           t0,
32592           t1;
32593
32594       // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
32595       if (rp > epsilon$3) {
32596         var p0 = asin$1(rp / r0 * sin$2(ap)),
32597             p1 = asin$1(rp / r1 * sin$2(ap));
32598         if ((da0 -= p0 * 2) > epsilon$3) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
32599         else da0 = 0, a00 = a10 = (a0 + a1) / 2;
32600         if ((da1 -= p1 * 2) > epsilon$3) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
32601         else da1 = 0, a01 = a11 = (a0 + a1) / 2;
32602       }
32603
32604       var x01 = r1 * cos$2(a01),
32605           y01 = r1 * sin$2(a01),
32606           x10 = r0 * cos$2(a10),
32607           y10 = r0 * sin$2(a10);
32608
32609       // Apply rounded corners?
32610       if (rc > epsilon$3) {
32611         var x11 = r1 * cos$2(a11),
32612             y11 = r1 * sin$2(a11),
32613             x00 = r0 * cos$2(a00),
32614             y00 = r0 * sin$2(a00);
32615
32616         // Restrict the corner radius according to the sector angle.
32617         if (da < pi$4) {
32618           var oc = da0 > epsilon$3 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10],
32619               ax = x01 - oc[0],
32620               ay = y01 - oc[1],
32621               bx = x11 - oc[0],
32622               by = y11 - oc[1],
32623               kc = 1 / sin$2(acos$1((ax * bx + ay * by) / (sqrt$2(ax * ax + ay * ay) * sqrt$2(bx * bx + by * by))) / 2),
32624               lc = sqrt$2(oc[0] * oc[0] + oc[1] * oc[1]);
32625           rc0 = min$1(rc, (r0 - lc) / (kc - 1));
32626           rc1 = min$1(rc, (r1 - lc) / (kc + 1));
32627         }
32628       }
32629
32630       // Is the sector collapsed to a line?
32631       if (!(da1 > epsilon$3)) context.moveTo(x01, y01);
32632
32633       // Does the sector’s outer ring have rounded corners?
32634       else if (rc1 > epsilon$3) {
32635         t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
32636         t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
32637
32638         context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
32639
32640         // Have the corners merged?
32641         if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32642
32643         // Otherwise, draw the two corners and the ring.
32644         else {
32645           context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32646           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);
32647           context.arc(t1.cx, t1.cy, rc1, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32648         }
32649       }
32650
32651       // Or is the outer ring just a circular arc?
32652       else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
32653
32654       // Is there no inner ring, and it’s a circular sector?
32655       // Or perhaps it’s an annular sector collapsed due to padding?
32656       if (!(r0 > epsilon$3) || !(da0 > epsilon$3)) context.lineTo(x10, y10);
32657
32658       // Does the sector’s inner ring (or point) have rounded corners?
32659       else if (rc0 > epsilon$3) {
32660         t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
32661         t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
32662
32663         context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
32664
32665         // Have the corners merged?
32666         if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32667
32668         // Otherwise, draw the two corners and the ring.
32669         else {
32670           context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32671           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);
32672           context.arc(t1.cx, t1.cy, rc0, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32673         }
32674       }
32675
32676       // Or is the inner ring just a circular arc?
32677       else context.arc(0, 0, r0, a10, a00, cw);
32678     }
32679
32680     context.closePath();
32681
32682     if (buffer) return context = null, buffer + "" || null;
32683   }
32684
32685   arc.centroid = function() {
32686     var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
32687         a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi$4 / 2;
32688     return [cos$2(a) * r, sin$2(a) * r];
32689   };
32690
32691   arc.innerRadius = function(_) {
32692     return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : innerRadius;
32693   };
32694
32695   arc.outerRadius = function(_) {
32696     return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : outerRadius;
32697   };
32698
32699   arc.cornerRadius = function(_) {
32700     return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : cornerRadius;
32701   };
32702
32703   arc.padRadius = function(_) {
32704     return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), arc) : padRadius;
32705   };
32706
32707   arc.startAngle = function(_) {
32708     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : startAngle;
32709   };
32710
32711   arc.endAngle = function(_) {
32712     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : endAngle;
32713   };
32714
32715   arc.padAngle = function(_) {
32716     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : padAngle;
32717   };
32718
32719   arc.context = function(_) {
32720     return arguments.length ? ((context = _ == null ? null : _), arc) : context;
32721   };
32722
32723   return arc;
32724 };
32725
32726 function Linear(context) {
32727   this._context = context;
32728 }
32729
32730 Linear.prototype = {
32731   areaStart: function() {
32732     this._line = 0;
32733   },
32734   areaEnd: function() {
32735     this._line = NaN;
32736   },
32737   lineStart: function() {
32738     this._point = 0;
32739   },
32740   lineEnd: function() {
32741     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
32742     this._line = 1 - this._line;
32743   },
32744   point: function(x, y) {
32745     x = +x, y = +y;
32746     switch (this._point) {
32747       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
32748       case 1: this._point = 2; // proceed
32749       default: this._context.lineTo(x, y); break;
32750     }
32751   }
32752 };
32753
32754 var curveLinear = function(context) {
32755   return new Linear(context);
32756 };
32757
32758 function x$3(p) {
32759   return p[0];
32760 }
32761
32762 function y$3(p) {
32763   return p[1];
32764 }
32765
32766 var line = function() {
32767   var x = x$3,
32768       y = y$3,
32769       defined = constant$10(true),
32770       context = null,
32771       curve = curveLinear,
32772       output = null;
32773
32774   function line(data) {
32775     var i,
32776         n = data.length,
32777         d,
32778         defined0 = false,
32779         buffer;
32780
32781     if (context == null) output = curve(buffer = path());
32782
32783     for (i = 0; i <= n; ++i) {
32784       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32785         if (defined0 = !defined0) output.lineStart();
32786         else output.lineEnd();
32787       }
32788       if (defined0) output.point(+x(d, i, data), +y(d, i, data));
32789     }
32790
32791     if (buffer) return output = null, buffer + "" || null;
32792   }
32793
32794   line.x = function(_) {
32795     return arguments.length ? (x = typeof _ === "function" ? _ : constant$10(+_), line) : x;
32796   };
32797
32798   line.y = function(_) {
32799     return arguments.length ? (y = typeof _ === "function" ? _ : constant$10(+_), line) : y;
32800   };
32801
32802   line.defined = function(_) {
32803     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), line) : defined;
32804   };
32805
32806   line.curve = function(_) {
32807     return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
32808   };
32809
32810   line.context = function(_) {
32811     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
32812   };
32813
32814   return line;
32815 };
32816
32817 var area$1 = function() {
32818   var x0 = x$3,
32819       x1 = null,
32820       y0 = constant$10(0),
32821       y1 = y$3,
32822       defined = constant$10(true),
32823       context = null,
32824       curve = curveLinear,
32825       output = null;
32826
32827   function area(data) {
32828     var i,
32829         j,
32830         k,
32831         n = data.length,
32832         d,
32833         defined0 = false,
32834         buffer,
32835         x0z = new Array(n),
32836         y0z = new Array(n);
32837
32838     if (context == null) output = curve(buffer = path());
32839
32840     for (i = 0; i <= n; ++i) {
32841       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32842         if (defined0 = !defined0) {
32843           j = i;
32844           output.areaStart();
32845           output.lineStart();
32846         } else {
32847           output.lineEnd();
32848           output.lineStart();
32849           for (k = i - 1; k >= j; --k) {
32850             output.point(x0z[k], y0z[k]);
32851           }
32852           output.lineEnd();
32853           output.areaEnd();
32854         }
32855       }
32856       if (defined0) {
32857         x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
32858         output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
32859       }
32860     }
32861
32862     if (buffer) return output = null, buffer + "" || null;
32863   }
32864
32865   function arealine() {
32866     return line().defined(defined).curve(curve).context(context);
32867   }
32868
32869   area.x = function(_) {
32870     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), x1 = null, area) : x0;
32871   };
32872
32873   area.x0 = function(_) {
32874     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), area) : x0;
32875   };
32876
32877   area.x1 = function(_) {
32878     return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : x1;
32879   };
32880
32881   area.y = function(_) {
32882     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), y1 = null, area) : y0;
32883   };
32884
32885   area.y0 = function(_) {
32886     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), area) : y0;
32887   };
32888
32889   area.y1 = function(_) {
32890     return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : y1;
32891   };
32892
32893   area.lineX0 =
32894   area.lineY0 = function() {
32895     return arealine().x(x0).y(y0);
32896   };
32897
32898   area.lineY1 = function() {
32899     return arealine().x(x0).y(y1);
32900   };
32901
32902   area.lineX1 = function() {
32903     return arealine().x(x1).y(y0);
32904   };
32905
32906   area.defined = function(_) {
32907     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), area) : defined;
32908   };
32909
32910   area.curve = function(_) {
32911     return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
32912   };
32913
32914   area.context = function(_) {
32915     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
32916   };
32917
32918   return area;
32919 };
32920
32921 var descending$1 = function(a, b) {
32922   return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
32923 };
32924
32925 var identity$7 = function(d) {
32926   return d;
32927 };
32928
32929 var pie = function() {
32930   var value = identity$7,
32931       sortValues = descending$1,
32932       sort = null,
32933       startAngle = constant$10(0),
32934       endAngle = constant$10(tau$4),
32935       padAngle = constant$10(0);
32936
32937   function pie(data) {
32938     var i,
32939         n = data.length,
32940         j,
32941         k,
32942         sum = 0,
32943         index = new Array(n),
32944         arcs = new Array(n),
32945         a0 = +startAngle.apply(this, arguments),
32946         da = Math.min(tau$4, Math.max(-tau$4, endAngle.apply(this, arguments) - a0)),
32947         a1,
32948         p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
32949         pa = p * (da < 0 ? -1 : 1),
32950         v;
32951
32952     for (i = 0; i < n; ++i) {
32953       if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
32954         sum += v;
32955       }
32956     }
32957
32958     // Optionally sort the arcs by previously-computed values or by data.
32959     if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
32960     else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });
32961
32962     // Compute the arcs! They are stored in the original data's order.
32963     for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
32964       j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
32965         data: data[j],
32966         index: i,
32967         value: v,
32968         startAngle: a0,
32969         endAngle: a1,
32970         padAngle: p
32971       };
32972     }
32973
32974     return arcs;
32975   }
32976
32977   pie.value = function(_) {
32978     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), pie) : value;
32979   };
32980
32981   pie.sortValues = function(_) {
32982     return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
32983   };
32984
32985   pie.sort = function(_) {
32986     return arguments.length ? (sort = _, sortValues = null, pie) : sort;
32987   };
32988
32989   pie.startAngle = function(_) {
32990     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : startAngle;
32991   };
32992
32993   pie.endAngle = function(_) {
32994     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : endAngle;
32995   };
32996
32997   pie.padAngle = function(_) {
32998     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : padAngle;
32999   };
33000
33001   return pie;
33002 };
33003
33004 var curveRadialLinear = curveRadial(curveLinear);
33005
33006 function Radial(curve) {
33007   this._curve = curve;
33008 }
33009
33010 Radial.prototype = {
33011   areaStart: function() {
33012     this._curve.areaStart();
33013   },
33014   areaEnd: function() {
33015     this._curve.areaEnd();
33016   },
33017   lineStart: function() {
33018     this._curve.lineStart();
33019   },
33020   lineEnd: function() {
33021     this._curve.lineEnd();
33022   },
33023   point: function(a, r) {
33024     this._curve.point(r * Math.sin(a), r * -Math.cos(a));
33025   }
33026 };
33027
33028 function curveRadial(curve) {
33029
33030   function radial(context) {
33031     return new Radial(curve(context));
33032   }
33033
33034   radial._curve = curve;
33035
33036   return radial;
33037 }
33038
33039 function lineRadial(l) {
33040   var c = l.curve;
33041
33042   l.angle = l.x, delete l.x;
33043   l.radius = l.y, delete l.y;
33044
33045   l.curve = function(_) {
33046     return arguments.length ? c(curveRadial(_)) : c()._curve;
33047   };
33048
33049   return l;
33050 }
33051
33052 var lineRadial$1 = function() {
33053   return lineRadial(line().curve(curveRadialLinear));
33054 };
33055
33056 var areaRadial = function() {
33057   var a = area$1().curve(curveRadialLinear),
33058       c = a.curve,
33059       x0 = a.lineX0,
33060       x1 = a.lineX1,
33061       y0 = a.lineY0,
33062       y1 = a.lineY1;
33063
33064   a.angle = a.x, delete a.x;
33065   a.startAngle = a.x0, delete a.x0;
33066   a.endAngle = a.x1, delete a.x1;
33067   a.radius = a.y, delete a.y;
33068   a.innerRadius = a.y0, delete a.y0;
33069   a.outerRadius = a.y1, delete a.y1;
33070   a.lineStartAngle = function() { return lineRadial(x0()); }, delete a.lineX0;
33071   a.lineEndAngle = function() { return lineRadial(x1()); }, delete a.lineX1;
33072   a.lineInnerRadius = function() { return lineRadial(y0()); }, delete a.lineY0;
33073   a.lineOuterRadius = function() { return lineRadial(y1()); }, delete a.lineY1;
33074
33075   a.curve = function(_) {
33076     return arguments.length ? c(curveRadial(_)) : c()._curve;
33077   };
33078
33079   return a;
33080 };
33081
33082 var pointRadial = function(x, y) {
33083   return [(y = +y) * Math.cos(x -= Math.PI / 2), y * Math.sin(x)];
33084 };
33085
33086 var slice$6 = Array.prototype.slice;
33087
33088 function linkSource(d) {
33089   return d.source;
33090 }
33091
33092 function linkTarget(d) {
33093   return d.target;
33094 }
33095
33096 function link$2(curve) {
33097   var source = linkSource,
33098       target = linkTarget,
33099       x = x$3,
33100       y = y$3,
33101       context = null;
33102
33103   function link() {
33104     var buffer, argv = slice$6.call(arguments), s = source.apply(this, argv), t = target.apply(this, argv);
33105     if (!context) context = buffer = path();
33106     curve(context, +x.apply(this, (argv[0] = s, argv)), +y.apply(this, argv), +x.apply(this, (argv[0] = t, argv)), +y.apply(this, argv));
33107     if (buffer) return context = null, buffer + "" || null;
33108   }
33109
33110   link.source = function(_) {
33111     return arguments.length ? (source = _, link) : source;
33112   };
33113
33114   link.target = function(_) {
33115     return arguments.length ? (target = _, link) : target;
33116   };
33117
33118   link.x = function(_) {
33119     return arguments.length ? (x = typeof _ === "function" ? _ : constant$10(+_), link) : x;
33120   };
33121
33122   link.y = function(_) {
33123     return arguments.length ? (y = typeof _ === "function" ? _ : constant$10(+_), link) : y;
33124   };
33125
33126   link.context = function(_) {
33127     return arguments.length ? ((context = _ == null ? null : _), link) : context;
33128   };
33129
33130   return link;
33131 }
33132
33133 function curveHorizontal(context, x0, y0, x1, y1) {
33134   context.moveTo(x0, y0);
33135   context.bezierCurveTo(x0 = (x0 + x1) / 2, y0, x0, y1, x1, y1);
33136 }
33137
33138 function curveVertical(context, x0, y0, x1, y1) {
33139   context.moveTo(x0, y0);
33140   context.bezierCurveTo(x0, y0 = (y0 + y1) / 2, x1, y0, x1, y1);
33141 }
33142
33143 function curveRadial$1(context, x0, y0, x1, y1) {
33144   var p0 = pointRadial(x0, y0),
33145       p1 = pointRadial(x0, y0 = (y0 + y1) / 2),
33146       p2 = pointRadial(x1, y0),
33147       p3 = pointRadial(x1, y1);
33148   context.moveTo(p0[0], p0[1]);
33149   context.bezierCurveTo(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);
33150 }
33151
33152 function linkHorizontal() {
33153   return link$2(curveHorizontal);
33154 }
33155
33156 function linkVertical() {
33157   return link$2(curveVertical);
33158 }
33159
33160 function linkRadial() {
33161   var l = link$2(curveRadial$1);
33162   l.angle = l.x, delete l.x;
33163   l.radius = l.y, delete l.y;
33164   return l;
33165 }
33166
33167 var circle$2 = {
33168   draw: function(context, size) {
33169     var r = Math.sqrt(size / pi$4);
33170     context.moveTo(r, 0);
33171     context.arc(0, 0, r, 0, tau$4);
33172   }
33173 };
33174
33175 var cross$2 = {
33176   draw: function(context, size) {
33177     var r = Math.sqrt(size / 5) / 2;
33178     context.moveTo(-3 * r, -r);
33179     context.lineTo(-r, -r);
33180     context.lineTo(-r, -3 * r);
33181     context.lineTo(r, -3 * r);
33182     context.lineTo(r, -r);
33183     context.lineTo(3 * r, -r);
33184     context.lineTo(3 * r, r);
33185     context.lineTo(r, r);
33186     context.lineTo(r, 3 * r);
33187     context.lineTo(-r, 3 * r);
33188     context.lineTo(-r, r);
33189     context.lineTo(-3 * r, r);
33190     context.closePath();
33191   }
33192 };
33193
33194 var tan30 = Math.sqrt(1 / 3);
33195 var tan30_2 = tan30 * 2;
33196
33197 var diamond = {
33198   draw: function(context, size) {
33199     var y = Math.sqrt(size / tan30_2),
33200         x = y * tan30;
33201     context.moveTo(0, -y);
33202     context.lineTo(x, 0);
33203     context.lineTo(0, y);
33204     context.lineTo(-x, 0);
33205     context.closePath();
33206   }
33207 };
33208
33209 var ka = 0.89081309152928522810;
33210 var kr = Math.sin(pi$4 / 10) / Math.sin(7 * pi$4 / 10);
33211 var kx = Math.sin(tau$4 / 10) * kr;
33212 var ky = -Math.cos(tau$4 / 10) * kr;
33213
33214 var star = {
33215   draw: function(context, size) {
33216     var r = Math.sqrt(size * ka),
33217         x = kx * r,
33218         y = ky * r;
33219     context.moveTo(0, -r);
33220     context.lineTo(x, y);
33221     for (var i = 1; i < 5; ++i) {
33222       var a = tau$4 * i / 5,
33223           c = Math.cos(a),
33224           s = Math.sin(a);
33225       context.lineTo(s * r, -c * r);
33226       context.lineTo(c * x - s * y, s * x + c * y);
33227     }
33228     context.closePath();
33229   }
33230 };
33231
33232 var square = {
33233   draw: function(context, size) {
33234     var w = Math.sqrt(size),
33235         x = -w / 2;
33236     context.rect(x, x, w, w);
33237   }
33238 };
33239
33240 var sqrt3 = Math.sqrt(3);
33241
33242 var triangle = {
33243   draw: function(context, size) {
33244     var y = -Math.sqrt(size / (sqrt3 * 3));
33245     context.moveTo(0, y * 2);
33246     context.lineTo(-sqrt3 * y, -y);
33247     context.lineTo(sqrt3 * y, -y);
33248     context.closePath();
33249   }
33250 };
33251
33252 var c = -0.5;
33253 var s = Math.sqrt(3) / 2;
33254 var k = 1 / Math.sqrt(12);
33255 var a = (k / 2 + 1) * 3;
33256
33257 var wye = {
33258   draw: function(context, size) {
33259     var r = Math.sqrt(size / a),
33260         x0 = r / 2,
33261         y0 = r * k,
33262         x1 = x0,
33263         y1 = r * k + r,
33264         x2 = -x1,
33265         y2 = y1;
33266     context.moveTo(x0, y0);
33267     context.lineTo(x1, y1);
33268     context.lineTo(x2, y2);
33269     context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
33270     context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
33271     context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
33272     context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
33273     context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
33274     context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
33275     context.closePath();
33276   }
33277 };
33278
33279 var symbols = [
33280   circle$2,
33281   cross$2,
33282   diamond,
33283   square,
33284   star,
33285   triangle,
33286   wye
33287 ];
33288
33289 var symbol = function() {
33290   var type = constant$10(circle$2),
33291       size = constant$10(64),
33292       context = null;
33293
33294   function symbol() {
33295     var buffer;
33296     if (!context) context = buffer = path();
33297     type.apply(this, arguments).draw(context, +size.apply(this, arguments));
33298     if (buffer) return context = null, buffer + "" || null;
33299   }
33300
33301   symbol.type = function(_) {
33302     return arguments.length ? (type = typeof _ === "function" ? _ : constant$10(_), symbol) : type;
33303   };
33304
33305   symbol.size = function(_) {
33306     return arguments.length ? (size = typeof _ === "function" ? _ : constant$10(+_), symbol) : size;
33307   };
33308
33309   symbol.context = function(_) {
33310     return arguments.length ? (context = _ == null ? null : _, symbol) : context;
33311   };
33312
33313   return symbol;
33314 };
33315
33316 var noop$2 = function() {};
33317
33318 function point$2(that, x, y) {
33319   that._context.bezierCurveTo(
33320     (2 * that._x0 + that._x1) / 3,
33321     (2 * that._y0 + that._y1) / 3,
33322     (that._x0 + 2 * that._x1) / 3,
33323     (that._y0 + 2 * that._y1) / 3,
33324     (that._x0 + 4 * that._x1 + x) / 6,
33325     (that._y0 + 4 * that._y1 + y) / 6
33326   );
33327 }
33328
33329 function Basis(context) {
33330   this._context = context;
33331 }
33332
33333 Basis.prototype = {
33334   areaStart: function() {
33335     this._line = 0;
33336   },
33337   areaEnd: function() {
33338     this._line = NaN;
33339   },
33340   lineStart: function() {
33341     this._x0 = this._x1 =
33342     this._y0 = this._y1 = NaN;
33343     this._point = 0;
33344   },
33345   lineEnd: function() {
33346     switch (this._point) {
33347       case 3: point$2(this, this._x1, this._y1); // proceed
33348       case 2: this._context.lineTo(this._x1, this._y1); break;
33349     }
33350     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33351     this._line = 1 - this._line;
33352   },
33353   point: function(x, y) {
33354     x = +x, y = +y;
33355     switch (this._point) {
33356       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33357       case 1: this._point = 2; break;
33358       case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
33359       default: point$2(this, x, y); break;
33360     }
33361     this._x0 = this._x1, this._x1 = x;
33362     this._y0 = this._y1, this._y1 = y;
33363   }
33364 };
33365
33366 var basis$2 = function(context) {
33367   return new Basis(context);
33368 };
33369
33370 function BasisClosed(context) {
33371   this._context = context;
33372 }
33373
33374 BasisClosed.prototype = {
33375   areaStart: noop$2,
33376   areaEnd: noop$2,
33377   lineStart: function() {
33378     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
33379     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
33380     this._point = 0;
33381   },
33382   lineEnd: function() {
33383     switch (this._point) {
33384       case 1: {
33385         this._context.moveTo(this._x2, this._y2);
33386         this._context.closePath();
33387         break;
33388       }
33389       case 2: {
33390         this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
33391         this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
33392         this._context.closePath();
33393         break;
33394       }
33395       case 3: {
33396         this.point(this._x2, this._y2);
33397         this.point(this._x3, this._y3);
33398         this.point(this._x4, this._y4);
33399         break;
33400       }
33401     }
33402   },
33403   point: function(x, y) {
33404     x = +x, y = +y;
33405     switch (this._point) {
33406       case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
33407       case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
33408       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;
33409       default: point$2(this, x, y); break;
33410     }
33411     this._x0 = this._x1, this._x1 = x;
33412     this._y0 = this._y1, this._y1 = y;
33413   }
33414 };
33415
33416 var basisClosed$1 = function(context) {
33417   return new BasisClosed(context);
33418 };
33419
33420 function BasisOpen(context) {
33421   this._context = context;
33422 }
33423
33424 BasisOpen.prototype = {
33425   areaStart: function() {
33426     this._line = 0;
33427   },
33428   areaEnd: function() {
33429     this._line = NaN;
33430   },
33431   lineStart: function() {
33432     this._x0 = this._x1 =
33433     this._y0 = this._y1 = NaN;
33434     this._point = 0;
33435   },
33436   lineEnd: function() {
33437     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33438     this._line = 1 - this._line;
33439   },
33440   point: function(x, y) {
33441     x = +x, y = +y;
33442     switch (this._point) {
33443       case 0: this._point = 1; break;
33444       case 1: this._point = 2; break;
33445       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;
33446       case 3: this._point = 4; // proceed
33447       default: point$2(this, x, y); break;
33448     }
33449     this._x0 = this._x1, this._x1 = x;
33450     this._y0 = this._y1, this._y1 = y;
33451   }
33452 };
33453
33454 var basisOpen = function(context) {
33455   return new BasisOpen(context);
33456 };
33457
33458 function Bundle(context, beta) {
33459   this._basis = new Basis(context);
33460   this._beta = beta;
33461 }
33462
33463 Bundle.prototype = {
33464   lineStart: function() {
33465     this._x = [];
33466     this._y = [];
33467     this._basis.lineStart();
33468   },
33469   lineEnd: function() {
33470     var x = this._x,
33471         y = this._y,
33472         j = x.length - 1;
33473
33474     if (j > 0) {
33475       var x0 = x[0],
33476           y0 = y[0],
33477           dx = x[j] - x0,
33478           dy = y[j] - y0,
33479           i = -1,
33480           t;
33481
33482       while (++i <= j) {
33483         t = i / j;
33484         this._basis.point(
33485           this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
33486           this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
33487         );
33488       }
33489     }
33490
33491     this._x = this._y = null;
33492     this._basis.lineEnd();
33493   },
33494   point: function(x, y) {
33495     this._x.push(+x);
33496     this._y.push(+y);
33497   }
33498 };
33499
33500 var bundle = (function custom(beta) {
33501
33502   function bundle(context) {
33503     return beta === 1 ? new Basis(context) : new Bundle(context, beta);
33504   }
33505
33506   bundle.beta = function(beta) {
33507     return custom(+beta);
33508   };
33509
33510   return bundle;
33511 })(0.85);
33512
33513 function point$3(that, x, y) {
33514   that._context.bezierCurveTo(
33515     that._x1 + that._k * (that._x2 - that._x0),
33516     that._y1 + that._k * (that._y2 - that._y0),
33517     that._x2 + that._k * (that._x1 - x),
33518     that._y2 + that._k * (that._y1 - y),
33519     that._x2,
33520     that._y2
33521   );
33522 }
33523
33524 function Cardinal(context, tension) {
33525   this._context = context;
33526   this._k = (1 - tension) / 6;
33527 }
33528
33529 Cardinal.prototype = {
33530   areaStart: function() {
33531     this._line = 0;
33532   },
33533   areaEnd: function() {
33534     this._line = NaN;
33535   },
33536   lineStart: function() {
33537     this._x0 = this._x1 = this._x2 =
33538     this._y0 = this._y1 = this._y2 = NaN;
33539     this._point = 0;
33540   },
33541   lineEnd: function() {
33542     switch (this._point) {
33543       case 2: this._context.lineTo(this._x2, this._y2); break;
33544       case 3: point$3(this, this._x1, this._y1); break;
33545     }
33546     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33547     this._line = 1 - this._line;
33548   },
33549   point: function(x, y) {
33550     x = +x, y = +y;
33551     switch (this._point) {
33552       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33553       case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
33554       case 2: this._point = 3; // proceed
33555       default: point$3(this, x, y); break;
33556     }
33557     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33558     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33559   }
33560 };
33561
33562 var cardinal = (function custom(tension) {
33563
33564   function cardinal(context) {
33565     return new Cardinal(context, tension);
33566   }
33567
33568   cardinal.tension = function(tension) {
33569     return custom(+tension);
33570   };
33571
33572   return cardinal;
33573 })(0);
33574
33575 function CardinalClosed(context, tension) {
33576   this._context = context;
33577   this._k = (1 - tension) / 6;
33578 }
33579
33580 CardinalClosed.prototype = {
33581   areaStart: noop$2,
33582   areaEnd: noop$2,
33583   lineStart: function() {
33584     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33585     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33586     this._point = 0;
33587   },
33588   lineEnd: function() {
33589     switch (this._point) {
33590       case 1: {
33591         this._context.moveTo(this._x3, this._y3);
33592         this._context.closePath();
33593         break;
33594       }
33595       case 2: {
33596         this._context.lineTo(this._x3, this._y3);
33597         this._context.closePath();
33598         break;
33599       }
33600       case 3: {
33601         this.point(this._x3, this._y3);
33602         this.point(this._x4, this._y4);
33603         this.point(this._x5, this._y5);
33604         break;
33605       }
33606     }
33607   },
33608   point: function(x, y) {
33609     x = +x, y = +y;
33610     switch (this._point) {
33611       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33612       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33613       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33614       default: point$3(this, x, y); break;
33615     }
33616     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33617     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33618   }
33619 };
33620
33621 var cardinalClosed = (function custom(tension) {
33622
33623   function cardinal$$1(context) {
33624     return new CardinalClosed(context, tension);
33625   }
33626
33627   cardinal$$1.tension = function(tension) {
33628     return custom(+tension);
33629   };
33630
33631   return cardinal$$1;
33632 })(0);
33633
33634 function CardinalOpen(context, tension) {
33635   this._context = context;
33636   this._k = (1 - tension) / 6;
33637 }
33638
33639 CardinalOpen.prototype = {
33640   areaStart: function() {
33641     this._line = 0;
33642   },
33643   areaEnd: function() {
33644     this._line = NaN;
33645   },
33646   lineStart: function() {
33647     this._x0 = this._x1 = this._x2 =
33648     this._y0 = this._y1 = this._y2 = NaN;
33649     this._point = 0;
33650   },
33651   lineEnd: function() {
33652     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33653     this._line = 1 - this._line;
33654   },
33655   point: function(x, y) {
33656     x = +x, y = +y;
33657     switch (this._point) {
33658       case 0: this._point = 1; break;
33659       case 1: this._point = 2; break;
33660       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33661       case 3: this._point = 4; // proceed
33662       default: point$3(this, x, y); break;
33663     }
33664     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33665     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33666   }
33667 };
33668
33669 var cardinalOpen = (function custom(tension) {
33670
33671   function cardinal$$1(context) {
33672     return new CardinalOpen(context, tension);
33673   }
33674
33675   cardinal$$1.tension = function(tension) {
33676     return custom(+tension);
33677   };
33678
33679   return cardinal$$1;
33680 })(0);
33681
33682 function point$4(that, x, y) {
33683   var x1 = that._x1,
33684       y1 = that._y1,
33685       x2 = that._x2,
33686       y2 = that._y2;
33687
33688   if (that._l01_a > epsilon$3) {
33689     var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
33690         n = 3 * that._l01_a * (that._l01_a + that._l12_a);
33691     x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
33692     y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
33693   }
33694
33695   if (that._l23_a > epsilon$3) {
33696     var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
33697         m = 3 * that._l23_a * (that._l23_a + that._l12_a);
33698     x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
33699     y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
33700   }
33701
33702   that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
33703 }
33704
33705 function CatmullRom(context, alpha) {
33706   this._context = context;
33707   this._alpha = alpha;
33708 }
33709
33710 CatmullRom.prototype = {
33711   areaStart: function() {
33712     this._line = 0;
33713   },
33714   areaEnd: function() {
33715     this._line = NaN;
33716   },
33717   lineStart: function() {
33718     this._x0 = this._x1 = this._x2 =
33719     this._y0 = this._y1 = this._y2 = NaN;
33720     this._l01_a = this._l12_a = this._l23_a =
33721     this._l01_2a = this._l12_2a = this._l23_2a =
33722     this._point = 0;
33723   },
33724   lineEnd: function() {
33725     switch (this._point) {
33726       case 2: this._context.lineTo(this._x2, this._y2); break;
33727       case 3: this.point(this._x2, this._y2); break;
33728     }
33729     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33730     this._line = 1 - this._line;
33731   },
33732   point: function(x, y) {
33733     x = +x, y = +y;
33734
33735     if (this._point) {
33736       var x23 = this._x2 - x,
33737           y23 = this._y2 - y;
33738       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33739     }
33740
33741     switch (this._point) {
33742       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33743       case 1: this._point = 2; break;
33744       case 2: this._point = 3; // proceed
33745       default: point$4(this, x, y); break;
33746     }
33747
33748     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33749     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33750     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33751     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33752   }
33753 };
33754
33755 var catmullRom = (function custom(alpha) {
33756
33757   function catmullRom(context) {
33758     return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);
33759   }
33760
33761   catmullRom.alpha = function(alpha) {
33762     return custom(+alpha);
33763   };
33764
33765   return catmullRom;
33766 })(0.5);
33767
33768 function CatmullRomClosed(context, alpha) {
33769   this._context = context;
33770   this._alpha = alpha;
33771 }
33772
33773 CatmullRomClosed.prototype = {
33774   areaStart: noop$2,
33775   areaEnd: noop$2,
33776   lineStart: function() {
33777     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33778     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33779     this._l01_a = this._l12_a = this._l23_a =
33780     this._l01_2a = this._l12_2a = this._l23_2a =
33781     this._point = 0;
33782   },
33783   lineEnd: function() {
33784     switch (this._point) {
33785       case 1: {
33786         this._context.moveTo(this._x3, this._y3);
33787         this._context.closePath();
33788         break;
33789       }
33790       case 2: {
33791         this._context.lineTo(this._x3, this._y3);
33792         this._context.closePath();
33793         break;
33794       }
33795       case 3: {
33796         this.point(this._x3, this._y3);
33797         this.point(this._x4, this._y4);
33798         this.point(this._x5, this._y5);
33799         break;
33800       }
33801     }
33802   },
33803   point: function(x, y) {
33804     x = +x, y = +y;
33805
33806     if (this._point) {
33807       var x23 = this._x2 - x,
33808           y23 = this._y2 - y;
33809       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33810     }
33811
33812     switch (this._point) {
33813       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33814       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33815       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33816       default: point$4(this, x, y); break;
33817     }
33818
33819     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33820     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33821     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33822     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33823   }
33824 };
33825
33826 var catmullRomClosed = (function custom(alpha) {
33827
33828   function catmullRom$$1(context) {
33829     return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);
33830   }
33831
33832   catmullRom$$1.alpha = function(alpha) {
33833     return custom(+alpha);
33834   };
33835
33836   return catmullRom$$1;
33837 })(0.5);
33838
33839 function CatmullRomOpen(context, alpha) {
33840   this._context = context;
33841   this._alpha = alpha;
33842 }
33843
33844 CatmullRomOpen.prototype = {
33845   areaStart: function() {
33846     this._line = 0;
33847   },
33848   areaEnd: function() {
33849     this._line = NaN;
33850   },
33851   lineStart: function() {
33852     this._x0 = this._x1 = this._x2 =
33853     this._y0 = this._y1 = this._y2 = NaN;
33854     this._l01_a = this._l12_a = this._l23_a =
33855     this._l01_2a = this._l12_2a = this._l23_2a =
33856     this._point = 0;
33857   },
33858   lineEnd: function() {
33859     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33860     this._line = 1 - this._line;
33861   },
33862   point: function(x, y) {
33863     x = +x, y = +y;
33864
33865     if (this._point) {
33866       var x23 = this._x2 - x,
33867           y23 = this._y2 - y;
33868       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33869     }
33870
33871     switch (this._point) {
33872       case 0: this._point = 1; break;
33873       case 1: this._point = 2; break;
33874       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33875       case 3: this._point = 4; // proceed
33876       default: point$4(this, x, y); break;
33877     }
33878
33879     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33880     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33881     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33882     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33883   }
33884 };
33885
33886 var catmullRomOpen = (function custom(alpha) {
33887
33888   function catmullRom$$1(context) {
33889     return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);
33890   }
33891
33892   catmullRom$$1.alpha = function(alpha) {
33893     return custom(+alpha);
33894   };
33895
33896   return catmullRom$$1;
33897 })(0.5);
33898
33899 function LinearClosed(context) {
33900   this._context = context;
33901 }
33902
33903 LinearClosed.prototype = {
33904   areaStart: noop$2,
33905   areaEnd: noop$2,
33906   lineStart: function() {
33907     this._point = 0;
33908   },
33909   lineEnd: function() {
33910     if (this._point) this._context.closePath();
33911   },
33912   point: function(x, y) {
33913     x = +x, y = +y;
33914     if (this._point) this._context.lineTo(x, y);
33915     else this._point = 1, this._context.moveTo(x, y);
33916   }
33917 };
33918
33919 var linearClosed = function(context) {
33920   return new LinearClosed(context);
33921 };
33922
33923 function sign$1(x) {
33924   return x < 0 ? -1 : 1;
33925 }
33926
33927 // Calculate the slopes of the tangents (Hermite-type interpolation) based on
33928 // the following paper: Steffen, M. 1990. A Simple Method for Monotonic
33929 // Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
33930 // NOV(II), P. 443, 1990.
33931 function slope3(that, x2, y2) {
33932   var h0 = that._x1 - that._x0,
33933       h1 = x2 - that._x1,
33934       s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
33935       s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
33936       p = (s0 * h1 + s1 * h0) / (h0 + h1);
33937   return (sign$1(s0) + sign$1(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
33938 }
33939
33940 // Calculate a one-sided slope.
33941 function slope2(that, t) {
33942   var h = that._x1 - that._x0;
33943   return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
33944 }
33945
33946 // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
33947 // "you can express cubic Hermite interpolation in terms of cubic Bézier curves
33948 // with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
33949 function point$5(that, t0, t1) {
33950   var x0 = that._x0,
33951       y0 = that._y0,
33952       x1 = that._x1,
33953       y1 = that._y1,
33954       dx = (x1 - x0) / 3;
33955   that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
33956 }
33957
33958 function MonotoneX(context) {
33959   this._context = context;
33960 }
33961
33962 MonotoneX.prototype = {
33963   areaStart: function() {
33964     this._line = 0;
33965   },
33966   areaEnd: function() {
33967     this._line = NaN;
33968   },
33969   lineStart: function() {
33970     this._x0 = this._x1 =
33971     this._y0 = this._y1 =
33972     this._t0 = NaN;
33973     this._point = 0;
33974   },
33975   lineEnd: function() {
33976     switch (this._point) {
33977       case 2: this._context.lineTo(this._x1, this._y1); break;
33978       case 3: point$5(this, this._t0, slope2(this, this._t0)); break;
33979     }
33980     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33981     this._line = 1 - this._line;
33982   },
33983   point: function(x, y) {
33984     var t1 = NaN;
33985
33986     x = +x, y = +y;
33987     if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
33988     switch (this._point) {
33989       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33990       case 1: this._point = 2; break;
33991       case 2: this._point = 3; point$5(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
33992       default: point$5(this, this._t0, t1 = slope3(this, x, y)); break;
33993     }
33994
33995     this._x0 = this._x1, this._x1 = x;
33996     this._y0 = this._y1, this._y1 = y;
33997     this._t0 = t1;
33998   }
33999 };
34000
34001 function MonotoneY(context) {
34002   this._context = new ReflectContext(context);
34003 }
34004
34005 (MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {
34006   MonotoneX.prototype.point.call(this, y, x);
34007 };
34008
34009 function ReflectContext(context) {
34010   this._context = context;
34011 }
34012
34013 ReflectContext.prototype = {
34014   moveTo: function(x, y) { this._context.moveTo(y, x); },
34015   closePath: function() { this._context.closePath(); },
34016   lineTo: function(x, y) { this._context.lineTo(y, x); },
34017   bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }
34018 };
34019
34020 function monotoneX(context) {
34021   return new MonotoneX(context);
34022 }
34023
34024 function monotoneY(context) {
34025   return new MonotoneY(context);
34026 }
34027
34028 function Natural(context) {
34029   this._context = context;
34030 }
34031
34032 Natural.prototype = {
34033   areaStart: function() {
34034     this._line = 0;
34035   },
34036   areaEnd: function() {
34037     this._line = NaN;
34038   },
34039   lineStart: function() {
34040     this._x = [];
34041     this._y = [];
34042   },
34043   lineEnd: function() {
34044     var x = this._x,
34045         y = this._y,
34046         n = x.length;
34047
34048     if (n) {
34049       this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
34050       if (n === 2) {
34051         this._context.lineTo(x[1], y[1]);
34052       } else {
34053         var px = controlPoints(x),
34054             py = controlPoints(y);
34055         for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
34056           this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
34057         }
34058       }
34059     }
34060
34061     if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
34062     this._line = 1 - this._line;
34063     this._x = this._y = null;
34064   },
34065   point: function(x, y) {
34066     this._x.push(+x);
34067     this._y.push(+y);
34068   }
34069 };
34070
34071 // See https://www.particleincell.com/2012/bezier-splines/ for derivation.
34072 function controlPoints(x) {
34073   var i,
34074       n = x.length - 1,
34075       m,
34076       a = new Array(n),
34077       b = new Array(n),
34078       r = new Array(n);
34079   a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
34080   for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
34081   a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
34082   for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
34083   a[n - 1] = r[n - 1] / b[n - 1];
34084   for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
34085   b[n - 1] = (x[n] + a[n - 1]) / 2;
34086   for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
34087   return [a, b];
34088 }
34089
34090 var natural = function(context) {
34091   return new Natural(context);
34092 };
34093
34094 function Step(context, t) {
34095   this._context = context;
34096   this._t = t;
34097 }
34098
34099 Step.prototype = {
34100   areaStart: function() {
34101     this._line = 0;
34102   },
34103   areaEnd: function() {
34104     this._line = NaN;
34105   },
34106   lineStart: function() {
34107     this._x = this._y = NaN;
34108     this._point = 0;
34109   },
34110   lineEnd: function() {
34111     if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
34112     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
34113     if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
34114   },
34115   point: function(x, y) {
34116     x = +x, y = +y;
34117     switch (this._point) {
34118       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
34119       case 1: this._point = 2; // proceed
34120       default: {
34121         if (this._t <= 0) {
34122           this._context.lineTo(this._x, y);
34123           this._context.lineTo(x, y);
34124         } else {
34125           var x1 = this._x * (1 - this._t) + x * this._t;
34126           this._context.lineTo(x1, this._y);
34127           this._context.lineTo(x1, y);
34128         }
34129         break;
34130       }
34131     }
34132     this._x = x, this._y = y;
34133   }
34134 };
34135
34136 var step = function(context) {
34137   return new Step(context, 0.5);
34138 };
34139
34140 function stepBefore(context) {
34141   return new Step(context, 0);
34142 }
34143
34144 function stepAfter(context) {
34145   return new Step(context, 1);
34146 }
34147
34148 var none$1 = function(series, order) {
34149   if (!((n = series.length) > 1)) return;
34150   for (var i = 1, j, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
34151     s0 = s1, s1 = series[order[i]];
34152     for (j = 0; j < m; ++j) {
34153       s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
34154     }
34155   }
34156 };
34157
34158 var none$2 = function(series) {
34159   var n = series.length, o = new Array(n);
34160   while (--n >= 0) o[n] = n;
34161   return o;
34162 };
34163
34164 function stackValue(d, key) {
34165   return d[key];
34166 }
34167
34168 var stack = function() {
34169   var keys = constant$10([]),
34170       order = none$2,
34171       offset = none$1,
34172       value = stackValue;
34173
34174   function stack(data) {
34175     var kz = keys.apply(this, arguments),
34176         i,
34177         m = data.length,
34178         n = kz.length,
34179         sz = new Array(n),
34180         oz;
34181
34182     for (i = 0; i < n; ++i) {
34183       for (var ki = kz[i], si = sz[i] = new Array(m), j = 0, sij; j < m; ++j) {
34184         si[j] = sij = [0, +value(data[j], ki, j, data)];
34185         sij.data = data[j];
34186       }
34187       si.key = ki;
34188     }
34189
34190     for (i = 0, oz = order(sz); i < n; ++i) {
34191       sz[oz[i]].index = i;
34192     }
34193
34194     offset(sz, oz);
34195     return sz;
34196   }
34197
34198   stack.keys = function(_) {
34199     return arguments.length ? (keys = typeof _ === "function" ? _ : constant$10(slice$6.call(_)), stack) : keys;
34200   };
34201
34202   stack.value = function(_) {
34203     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), stack) : value;
34204   };
34205
34206   stack.order = function(_) {
34207     return arguments.length ? (order = _ == null ? none$2 : typeof _ === "function" ? _ : constant$10(slice$6.call(_)), stack) : order;
34208   };
34209
34210   stack.offset = function(_) {
34211     return arguments.length ? (offset = _ == null ? none$1 : _, stack) : offset;
34212   };
34213
34214   return stack;
34215 };
34216
34217 var expand = function(series, order) {
34218   if (!((n = series.length) > 0)) return;
34219   for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {
34220     for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;
34221     if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;
34222   }
34223   none$1(series, order);
34224 };
34225
34226 var diverging = function(series, order) {
34227   if (!((n = series.length) > 1)) return;
34228   for (var i, j = 0, d, dy, yp, yn, n, m = series[order[0]].length; j < m; ++j) {
34229     for (yp = yn = 0, i = 0; i < n; ++i) {
34230       if ((dy = (d = series[order[i]][j])[1] - d[0]) >= 0) {
34231         d[0] = yp, d[1] = yp += dy;
34232       } else if (dy < 0) {
34233         d[1] = yn, d[0] = yn += dy;
34234       } else {
34235         d[0] = yp;
34236       }
34237     }
34238   }
34239 };
34240
34241 var silhouette = function(series, order) {
34242   if (!((n = series.length) > 0)) return;
34243   for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
34244     for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;
34245     s0[j][1] += s0[j][0] = -y / 2;
34246   }
34247   none$1(series, order);
34248 };
34249
34250 var wiggle = function(series, order) {
34251   if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;
34252   for (var y = 0, j = 1, s0, m, n; j < m; ++j) {
34253     for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {
34254       var si = series[order[i]],
34255           sij0 = si[j][1] || 0,
34256           sij1 = si[j - 1][1] || 0,
34257           s3 = (sij0 - sij1) / 2;
34258       for (var k = 0; k < i; ++k) {
34259         var sk = series[order[k]],
34260             skj0 = sk[j][1] || 0,
34261             skj1 = sk[j - 1][1] || 0;
34262         s3 += skj0 - skj1;
34263       }
34264       s1 += sij0, s2 += s3 * sij0;
34265     }
34266     s0[j - 1][1] += s0[j - 1][0] = y;
34267     if (s1) y -= s2 / s1;
34268   }
34269   s0[j - 1][1] += s0[j - 1][0] = y;
34270   none$1(series, order);
34271 };
34272
34273 var ascending$2 = function(series) {
34274   var sums = series.map(sum$2);
34275   return none$2(series).sort(function(a, b) { return sums[a] - sums[b]; });
34276 };
34277
34278 function sum$2(series) {
34279   var s = 0, i = -1, n = series.length, v;
34280   while (++i < n) if (v = +series[i][1]) s += v;
34281   return s;
34282 }
34283
34284 var descending$2 = function(series) {
34285   return ascending$2(series).reverse();
34286 };
34287
34288 var insideOut = function(series) {
34289   var n = series.length,
34290       i,
34291       j,
34292       sums = series.map(sum$2),
34293       order = none$2(series).sort(function(a, b) { return sums[b] - sums[a]; }),
34294       top = 0,
34295       bottom = 0,
34296       tops = [],
34297       bottoms = [];
34298
34299   for (i = 0; i < n; ++i) {
34300     j = order[i];
34301     if (top < bottom) {
34302       top += sums[j];
34303       tops.push(j);
34304     } else {
34305       bottom += sums[j];
34306       bottoms.push(j);
34307     }
34308   }
34309
34310   return bottoms.reverse().concat(tops);
34311 };
34312
34313 var reverse = function(series) {
34314   return none$2(series).reverse();
34315 };
34316
34317 var constant$11 = function(x) {
34318   return function() {
34319     return x;
34320   };
34321 };
34322
34323 function x$4(d) {
34324   return d[0];
34325 }
34326
34327 function y$4(d) {
34328   return d[1];
34329 }
34330
34331 function RedBlackTree() {
34332   this._ = null; // root node
34333 }
34334
34335 function RedBlackNode(node) {
34336   node.U = // parent node
34337   node.C = // color - true for red, false for black
34338   node.L = // left node
34339   node.R = // right node
34340   node.P = // previous node
34341   node.N = null; // next node
34342 }
34343
34344 RedBlackTree.prototype = {
34345   constructor: RedBlackTree,
34346
34347   insert: function(after, node) {
34348     var parent, grandpa, uncle;
34349
34350     if (after) {
34351       node.P = after;
34352       node.N = after.N;
34353       if (after.N) after.N.P = node;
34354       after.N = node;
34355       if (after.R) {
34356         after = after.R;
34357         while (after.L) after = after.L;
34358         after.L = node;
34359       } else {
34360         after.R = node;
34361       }
34362       parent = after;
34363     } else if (this._) {
34364       after = RedBlackFirst(this._);
34365       node.P = null;
34366       node.N = after;
34367       after.P = after.L = node;
34368       parent = after;
34369     } else {
34370       node.P = node.N = null;
34371       this._ = node;
34372       parent = null;
34373     }
34374     node.L = node.R = null;
34375     node.U = parent;
34376     node.C = true;
34377
34378     after = node;
34379     while (parent && parent.C) {
34380       grandpa = parent.U;
34381       if (parent === grandpa.L) {
34382         uncle = grandpa.R;
34383         if (uncle && uncle.C) {
34384           parent.C = uncle.C = false;
34385           grandpa.C = true;
34386           after = grandpa;
34387         } else {
34388           if (after === parent.R) {
34389             RedBlackRotateLeft(this, parent);
34390             after = parent;
34391             parent = after.U;
34392           }
34393           parent.C = false;
34394           grandpa.C = true;
34395           RedBlackRotateRight(this, grandpa);
34396         }
34397       } else {
34398         uncle = grandpa.L;
34399         if (uncle && uncle.C) {
34400           parent.C = uncle.C = false;
34401           grandpa.C = true;
34402           after = grandpa;
34403         } else {
34404           if (after === parent.L) {
34405             RedBlackRotateRight(this, parent);
34406             after = parent;
34407             parent = after.U;
34408           }
34409           parent.C = false;
34410           grandpa.C = true;
34411           RedBlackRotateLeft(this, grandpa);
34412         }
34413       }
34414       parent = after.U;
34415     }
34416     this._.C = false;
34417   },
34418
34419   remove: function(node) {
34420     if (node.N) node.N.P = node.P;
34421     if (node.P) node.P.N = node.N;
34422     node.N = node.P = null;
34423
34424     var parent = node.U,
34425         sibling,
34426         left = node.L,
34427         right = node.R,
34428         next,
34429         red;
34430
34431     if (!left) next = right;
34432     else if (!right) next = left;
34433     else next = RedBlackFirst(right);
34434
34435     if (parent) {
34436       if (parent.L === node) parent.L = next;
34437       else parent.R = next;
34438     } else {
34439       this._ = next;
34440     }
34441
34442     if (left && right) {
34443       red = next.C;
34444       next.C = node.C;
34445       next.L = left;
34446       left.U = next;
34447       if (next !== right) {
34448         parent = next.U;
34449         next.U = node.U;
34450         node = next.R;
34451         parent.L = node;
34452         next.R = right;
34453         right.U = next;
34454       } else {
34455         next.U = parent;
34456         parent = next;
34457         node = next.R;
34458       }
34459     } else {
34460       red = node.C;
34461       node = next;
34462     }
34463
34464     if (node) node.U = parent;
34465     if (red) return;
34466     if (node && node.C) { node.C = false; return; }
34467
34468     do {
34469       if (node === this._) break;
34470       if (node === parent.L) {
34471         sibling = parent.R;
34472         if (sibling.C) {
34473           sibling.C = false;
34474           parent.C = true;
34475           RedBlackRotateLeft(this, parent);
34476           sibling = parent.R;
34477         }
34478         if ((sibling.L && sibling.L.C)
34479             || (sibling.R && sibling.R.C)) {
34480           if (!sibling.R || !sibling.R.C) {
34481             sibling.L.C = false;
34482             sibling.C = true;
34483             RedBlackRotateRight(this, sibling);
34484             sibling = parent.R;
34485           }
34486           sibling.C = parent.C;
34487           parent.C = sibling.R.C = false;
34488           RedBlackRotateLeft(this, parent);
34489           node = this._;
34490           break;
34491         }
34492       } else {
34493         sibling = parent.L;
34494         if (sibling.C) {
34495           sibling.C = false;
34496           parent.C = true;
34497           RedBlackRotateRight(this, parent);
34498           sibling = parent.L;
34499         }
34500         if ((sibling.L && sibling.L.C)
34501           || (sibling.R && sibling.R.C)) {
34502           if (!sibling.L || !sibling.L.C) {
34503             sibling.R.C = false;
34504             sibling.C = true;
34505             RedBlackRotateLeft(this, sibling);
34506             sibling = parent.L;
34507           }
34508           sibling.C = parent.C;
34509           parent.C = sibling.L.C = false;
34510           RedBlackRotateRight(this, parent);
34511           node = this._;
34512           break;
34513         }
34514       }
34515       sibling.C = true;
34516       node = parent;
34517       parent = parent.U;
34518     } while (!node.C);
34519
34520     if (node) node.C = false;
34521   }
34522 };
34523
34524 function RedBlackRotateLeft(tree, node) {
34525   var p = node,
34526       q = node.R,
34527       parent = p.U;
34528
34529   if (parent) {
34530     if (parent.L === p) parent.L = q;
34531     else parent.R = q;
34532   } else {
34533     tree._ = q;
34534   }
34535
34536   q.U = parent;
34537   p.U = q;
34538   p.R = q.L;
34539   if (p.R) p.R.U = p;
34540   q.L = p;
34541 }
34542
34543 function RedBlackRotateRight(tree, node) {
34544   var p = node,
34545       q = node.L,
34546       parent = p.U;
34547
34548   if (parent) {
34549     if (parent.L === p) parent.L = q;
34550     else parent.R = q;
34551   } else {
34552     tree._ = q;
34553   }
34554
34555   q.U = parent;
34556   p.U = q;
34557   p.L = q.R;
34558   if (p.L) p.L.U = p;
34559   q.R = p;
34560 }
34561
34562 function RedBlackFirst(node) {
34563   while (node.L) node = node.L;
34564   return node;
34565 }
34566
34567 function createEdge(left, right, v0, v1) {
34568   var edge = [null, null],
34569       index = edges.push(edge) - 1;
34570   edge.left = left;
34571   edge.right = right;
34572   if (v0) setEdgeEnd(edge, left, right, v0);
34573   if (v1) setEdgeEnd(edge, right, left, v1);
34574   cells[left.index].halfedges.push(index);
34575   cells[right.index].halfedges.push(index);
34576   return edge;
34577 }
34578
34579 function createBorderEdge(left, v0, v1) {
34580   var edge = [v0, v1];
34581   edge.left = left;
34582   return edge;
34583 }
34584
34585 function setEdgeEnd(edge, left, right, vertex) {
34586   if (!edge[0] && !edge[1]) {
34587     edge[0] = vertex;
34588     edge.left = left;
34589     edge.right = right;
34590   } else if (edge.left === right) {
34591     edge[1] = vertex;
34592   } else {
34593     edge[0] = vertex;
34594   }
34595 }
34596
34597 // Liang–Barsky line clipping.
34598 function clipEdge(edge, x0, y0, x1, y1) {
34599   var a = edge[0],
34600       b = edge[1],
34601       ax = a[0],
34602       ay = a[1],
34603       bx = b[0],
34604       by = b[1],
34605       t0 = 0,
34606       t1 = 1,
34607       dx = bx - ax,
34608       dy = by - ay,
34609       r;
34610
34611   r = x0 - ax;
34612   if (!dx && r > 0) return;
34613   r /= dx;
34614   if (dx < 0) {
34615     if (r < t0) return;
34616     if (r < t1) t1 = r;
34617   } else if (dx > 0) {
34618     if (r > t1) return;
34619     if (r > t0) t0 = r;
34620   }
34621
34622   r = x1 - ax;
34623   if (!dx && r < 0) return;
34624   r /= dx;
34625   if (dx < 0) {
34626     if (r > t1) return;
34627     if (r > t0) t0 = r;
34628   } else if (dx > 0) {
34629     if (r < t0) return;
34630     if (r < t1) t1 = r;
34631   }
34632
34633   r = y0 - ay;
34634   if (!dy && r > 0) return;
34635   r /= dy;
34636   if (dy < 0) {
34637     if (r < t0) return;
34638     if (r < t1) t1 = r;
34639   } else if (dy > 0) {
34640     if (r > t1) return;
34641     if (r > t0) t0 = r;
34642   }
34643
34644   r = y1 - ay;
34645   if (!dy && r < 0) return;
34646   r /= dy;
34647   if (dy < 0) {
34648     if (r > t1) return;
34649     if (r > t0) t0 = r;
34650   } else if (dy > 0) {
34651     if (r < t0) return;
34652     if (r < t1) t1 = r;
34653   }
34654
34655   if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check?
34656
34657   if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy];
34658   if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy];
34659   return true;
34660 }
34661
34662 function connectEdge(edge, x0, y0, x1, y1) {
34663   var v1 = edge[1];
34664   if (v1) return true;
34665
34666   var v0 = edge[0],
34667       left = edge.left,
34668       right = edge.right,
34669       lx = left[0],
34670       ly = left[1],
34671       rx = right[0],
34672       ry = right[1],
34673       fx = (lx + rx) / 2,
34674       fy = (ly + ry) / 2,
34675       fm,
34676       fb;
34677
34678   if (ry === ly) {
34679     if (fx < x0 || fx >= x1) return;
34680     if (lx > rx) {
34681       if (!v0) v0 = [fx, y0];
34682       else if (v0[1] >= y1) return;
34683       v1 = [fx, y1];
34684     } else {
34685       if (!v0) v0 = [fx, y1];
34686       else if (v0[1] < y0) return;
34687       v1 = [fx, y0];
34688     }
34689   } else {
34690     fm = (lx - rx) / (ry - ly);
34691     fb = fy - fm * fx;
34692     if (fm < -1 || fm > 1) {
34693       if (lx > rx) {
34694         if (!v0) v0 = [(y0 - fb) / fm, y0];
34695         else if (v0[1] >= y1) return;
34696         v1 = [(y1 - fb) / fm, y1];
34697       } else {
34698         if (!v0) v0 = [(y1 - fb) / fm, y1];
34699         else if (v0[1] < y0) return;
34700         v1 = [(y0 - fb) / fm, y0];
34701       }
34702     } else {
34703       if (ly < ry) {
34704         if (!v0) v0 = [x0, fm * x0 + fb];
34705         else if (v0[0] >= x1) return;
34706         v1 = [x1, fm * x1 + fb];
34707       } else {
34708         if (!v0) v0 = [x1, fm * x1 + fb];
34709         else if (v0[0] < x0) return;
34710         v1 = [x0, fm * x0 + fb];
34711       }
34712     }
34713   }
34714
34715   edge[0] = v0;
34716   edge[1] = v1;
34717   return true;
34718 }
34719
34720 function clipEdges(x0, y0, x1, y1) {
34721   var i = edges.length,
34722       edge;
34723
34724   while (i--) {
34725     if (!connectEdge(edge = edges[i], x0, y0, x1, y1)
34726         || !clipEdge(edge, x0, y0, x1, y1)
34727         || !(Math.abs(edge[0][0] - edge[1][0]) > epsilon$4
34728             || Math.abs(edge[0][1] - edge[1][1]) > epsilon$4)) {
34729       delete edges[i];
34730     }
34731   }
34732 }
34733
34734 function createCell(site) {
34735   return cells[site.index] = {
34736     site: site,
34737     halfedges: []
34738   };
34739 }
34740
34741 function cellHalfedgeAngle(cell, edge) {
34742   var site = cell.site,
34743       va = edge.left,
34744       vb = edge.right;
34745   if (site === vb) vb = va, va = site;
34746   if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]);
34747   if (site === va) va = edge[1], vb = edge[0];
34748   else va = edge[0], vb = edge[1];
34749   return Math.atan2(va[0] - vb[0], vb[1] - va[1]);
34750 }
34751
34752 function cellHalfedgeStart(cell, edge) {
34753   return edge[+(edge.left !== cell.site)];
34754 }
34755
34756 function cellHalfedgeEnd(cell, edge) {
34757   return edge[+(edge.left === cell.site)];
34758 }
34759
34760 function sortCellHalfedges() {
34761   for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) {
34762     if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) {
34763       var index = new Array(m),
34764           array = new Array(m);
34765       for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]);
34766       index.sort(function(i, j) { return array[j] - array[i]; });
34767       for (j = 0; j < m; ++j) array[j] = halfedges[index[j]];
34768       for (j = 0; j < m; ++j) halfedges[j] = array[j];
34769     }
34770   }
34771 }
34772
34773 function clipCells(x0, y0, x1, y1) {
34774   var nCells = cells.length,
34775       iCell,
34776       cell,
34777       site,
34778       iHalfedge,
34779       halfedges,
34780       nHalfedges,
34781       start,
34782       startX,
34783       startY,
34784       end,
34785       endX,
34786       endY,
34787       cover = true;
34788
34789   for (iCell = 0; iCell < nCells; ++iCell) {
34790     if (cell = cells[iCell]) {
34791       site = cell.site;
34792       halfedges = cell.halfedges;
34793       iHalfedge = halfedges.length;
34794
34795       // Remove any dangling clipped edges.
34796       while (iHalfedge--) {
34797         if (!edges[halfedges[iHalfedge]]) {
34798           halfedges.splice(iHalfedge, 1);
34799         }
34800       }
34801
34802       // Insert any border edges as necessary.
34803       iHalfedge = 0, nHalfedges = halfedges.length;
34804       while (iHalfedge < nHalfedges) {
34805         end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1];
34806         start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1];
34807         if (Math.abs(endX - startX) > epsilon$4 || Math.abs(endY - startY) > epsilon$4) {
34808           halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end,
34809               Math.abs(endX - x0) < epsilon$4 && y1 - endY > epsilon$4 ? [x0, Math.abs(startX - x0) < epsilon$4 ? startY : y1]
34810               : Math.abs(endY - y1) < epsilon$4 && x1 - endX > epsilon$4 ? [Math.abs(startY - y1) < epsilon$4 ? startX : x1, y1]
34811               : Math.abs(endX - x1) < epsilon$4 && endY - y0 > epsilon$4 ? [x1, Math.abs(startX - x1) < epsilon$4 ? startY : y0]
34812               : Math.abs(endY - y0) < epsilon$4 && endX - x0 > epsilon$4 ? [Math.abs(startY - y0) < epsilon$4 ? startX : x0, y0]
34813               : null)) - 1);
34814           ++nHalfedges;
34815         }
34816       }
34817
34818       if (nHalfedges) cover = false;
34819     }
34820   }
34821
34822   // If there weren’t any edges, have the closest site cover the extent.
34823   // It doesn’t matter which corner of the extent we measure!
34824   if (cover) {
34825     var dx, dy, d2, dc = Infinity;
34826
34827     for (iCell = 0, cover = null; iCell < nCells; ++iCell) {
34828       if (cell = cells[iCell]) {
34829         site = cell.site;
34830         dx = site[0] - x0;
34831         dy = site[1] - y0;
34832         d2 = dx * dx + dy * dy;
34833         if (d2 < dc) dc = d2, cover = cell;
34834       }
34835     }
34836
34837     if (cover) {
34838       var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0];
34839       cover.halfedges.push(
34840         edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1,
34841         edges.push(createBorderEdge(site, v01, v11)) - 1,
34842         edges.push(createBorderEdge(site, v11, v10)) - 1,
34843         edges.push(createBorderEdge(site, v10, v00)) - 1
34844       );
34845     }
34846   }
34847
34848   // Lastly delete any cells with no edges; these were entirely clipped.
34849   for (iCell = 0; iCell < nCells; ++iCell) {
34850     if (cell = cells[iCell]) {
34851       if (!cell.halfedges.length) {
34852         delete cells[iCell];
34853       }
34854     }
34855   }
34856 }
34857
34858 var circlePool = [];
34859
34860 var firstCircle;
34861
34862 function Circle() {
34863   RedBlackNode(this);
34864   this.x =
34865   this.y =
34866   this.arc =
34867   this.site =
34868   this.cy = null;
34869 }
34870
34871 function attachCircle(arc) {
34872   var lArc = arc.P,
34873       rArc = arc.N;
34874
34875   if (!lArc || !rArc) return;
34876
34877   var lSite = lArc.site,
34878       cSite = arc.site,
34879       rSite = rArc.site;
34880
34881   if (lSite === rSite) return;
34882
34883   var bx = cSite[0],
34884       by = cSite[1],
34885       ax = lSite[0] - bx,
34886       ay = lSite[1] - by,
34887       cx = rSite[0] - bx,
34888       cy = rSite[1] - by;
34889
34890   var d = 2 * (ax * cy - ay * cx);
34891   if (d >= -epsilon2$2) return;
34892
34893   var ha = ax * ax + ay * ay,
34894       hc = cx * cx + cy * cy,
34895       x = (cy * ha - ay * hc) / d,
34896       y = (ax * hc - cx * ha) / d;
34897
34898   var circle = circlePool.pop() || new Circle;
34899   circle.arc = arc;
34900   circle.site = cSite;
34901   circle.x = x + bx;
34902   circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom
34903
34904   arc.circle = circle;
34905
34906   var before = null,
34907       node = circles._;
34908
34909   while (node) {
34910     if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) {
34911       if (node.L) node = node.L;
34912       else { before = node.P; break; }
34913     } else {
34914       if (node.R) node = node.R;
34915       else { before = node; break; }
34916     }
34917   }
34918
34919   circles.insert(before, circle);
34920   if (!before) firstCircle = circle;
34921 }
34922
34923 function detachCircle(arc) {
34924   var circle = arc.circle;
34925   if (circle) {
34926     if (!circle.P) firstCircle = circle.N;
34927     circles.remove(circle);
34928     circlePool.push(circle);
34929     RedBlackNode(circle);
34930     arc.circle = null;
34931   }
34932 }
34933
34934 var beachPool = [];
34935
34936 function Beach() {
34937   RedBlackNode(this);
34938   this.edge =
34939   this.site =
34940   this.circle = null;
34941 }
34942
34943 function createBeach(site) {
34944   var beach = beachPool.pop() || new Beach;
34945   beach.site = site;
34946   return beach;
34947 }
34948
34949 function detachBeach(beach) {
34950   detachCircle(beach);
34951   beaches.remove(beach);
34952   beachPool.push(beach);
34953   RedBlackNode(beach);
34954 }
34955
34956 function removeBeach(beach) {
34957   var circle = beach.circle,
34958       x = circle.x,
34959       y = circle.cy,
34960       vertex = [x, y],
34961       previous = beach.P,
34962       next = beach.N,
34963       disappearing = [beach];
34964
34965   detachBeach(beach);
34966
34967   var lArc = previous;
34968   while (lArc.circle
34969       && Math.abs(x - lArc.circle.x) < epsilon$4
34970       && Math.abs(y - lArc.circle.cy) < epsilon$4) {
34971     previous = lArc.P;
34972     disappearing.unshift(lArc);
34973     detachBeach(lArc);
34974     lArc = previous;
34975   }
34976
34977   disappearing.unshift(lArc);
34978   detachCircle(lArc);
34979
34980   var rArc = next;
34981   while (rArc.circle
34982       && Math.abs(x - rArc.circle.x) < epsilon$4
34983       && Math.abs(y - rArc.circle.cy) < epsilon$4) {
34984     next = rArc.N;
34985     disappearing.push(rArc);
34986     detachBeach(rArc);
34987     rArc = next;
34988   }
34989
34990   disappearing.push(rArc);
34991   detachCircle(rArc);
34992
34993   var nArcs = disappearing.length,
34994       iArc;
34995   for (iArc = 1; iArc < nArcs; ++iArc) {
34996     rArc = disappearing[iArc];
34997     lArc = disappearing[iArc - 1];
34998     setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
34999   }
35000
35001   lArc = disappearing[0];
35002   rArc = disappearing[nArcs - 1];
35003   rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
35004
35005   attachCircle(lArc);
35006   attachCircle(rArc);
35007 }
35008
35009 function addBeach(site) {
35010   var x = site[0],
35011       directrix = site[1],
35012       lArc,
35013       rArc,
35014       dxl,
35015       dxr,
35016       node = beaches._;
35017
35018   while (node) {
35019     dxl = leftBreakPoint(node, directrix) - x;
35020     if (dxl > epsilon$4) node = node.L; else {
35021       dxr = x - rightBreakPoint(node, directrix);
35022       if (dxr > epsilon$4) {
35023         if (!node.R) {
35024           lArc = node;
35025           break;
35026         }
35027         node = node.R;
35028       } else {
35029         if (dxl > -epsilon$4) {
35030           lArc = node.P;
35031           rArc = node;
35032         } else if (dxr > -epsilon$4) {
35033           lArc = node;
35034           rArc = node.N;
35035         } else {
35036           lArc = rArc = node;
35037         }
35038         break;
35039       }
35040     }
35041   }
35042
35043   createCell(site);
35044   var newArc = createBeach(site);
35045   beaches.insert(lArc, newArc);
35046
35047   if (!lArc && !rArc) return;
35048
35049   if (lArc === rArc) {
35050     detachCircle(lArc);
35051     rArc = createBeach(lArc.site);
35052     beaches.insert(newArc, rArc);
35053     newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
35054     attachCircle(lArc);
35055     attachCircle(rArc);
35056     return;
35057   }
35058
35059   if (!rArc) { // && lArc
35060     newArc.edge = createEdge(lArc.site, newArc.site);
35061     return;
35062   }
35063
35064   // else lArc !== rArc
35065   detachCircle(lArc);
35066   detachCircle(rArc);
35067
35068   var lSite = lArc.site,
35069       ax = lSite[0],
35070       ay = lSite[1],
35071       bx = site[0] - ax,
35072       by = site[1] - ay,
35073       rSite = rArc.site,
35074       cx = rSite[0] - ax,
35075       cy = rSite[1] - ay,
35076       d = 2 * (bx * cy - by * cx),
35077       hb = bx * bx + by * by,
35078       hc = cx * cx + cy * cy,
35079       vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
35080
35081   setEdgeEnd(rArc.edge, lSite, rSite, vertex);
35082   newArc.edge = createEdge(lSite, site, null, vertex);
35083   rArc.edge = createEdge(site, rSite, null, vertex);
35084   attachCircle(lArc);
35085   attachCircle(rArc);
35086 }
35087
35088 function leftBreakPoint(arc, directrix) {
35089   var site = arc.site,
35090       rfocx = site[0],
35091       rfocy = site[1],
35092       pby2 = rfocy - directrix;
35093
35094   if (!pby2) return rfocx;
35095
35096   var lArc = arc.P;
35097   if (!lArc) return -Infinity;
35098
35099   site = lArc.site;
35100   var lfocx = site[0],
35101       lfocy = site[1],
35102       plby2 = lfocy - directrix;
35103
35104   if (!plby2) return lfocx;
35105
35106   var hl = lfocx - rfocx,
35107       aby2 = 1 / pby2 - 1 / plby2,
35108       b = hl / plby2;
35109
35110   if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
35111
35112   return (rfocx + lfocx) / 2;
35113 }
35114
35115 function rightBreakPoint(arc, directrix) {
35116   var rArc = arc.N;
35117   if (rArc) return leftBreakPoint(rArc, directrix);
35118   var site = arc.site;
35119   return site[1] === directrix ? site[0] : Infinity;
35120 }
35121
35122 var epsilon$4 = 1e-6;
35123 var epsilon2$2 = 1e-12;
35124 var beaches;
35125 var cells;
35126 var circles;
35127 var edges;
35128
35129 function triangleArea(a, b, c) {
35130   return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
35131 }
35132
35133 function lexicographic(a, b) {
35134   return b[1] - a[1]
35135       || b[0] - a[0];
35136 }
35137
35138 function Diagram(sites, extent) {
35139   var site = sites.sort(lexicographic).pop(),
35140       x,
35141       y,
35142       circle;
35143
35144   edges = [];
35145   cells = new Array(sites.length);
35146   beaches = new RedBlackTree;
35147   circles = new RedBlackTree;
35148
35149   while (true) {
35150     circle = firstCircle;
35151     if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
35152       if (site[0] !== x || site[1] !== y) {
35153         addBeach(site);
35154         x = site[0], y = site[1];
35155       }
35156       site = sites.pop();
35157     } else if (circle) {
35158       removeBeach(circle.arc);
35159     } else {
35160       break;
35161     }
35162   }
35163
35164   sortCellHalfedges();
35165
35166   if (extent) {
35167     var x0 = +extent[0][0],
35168         y0 = +extent[0][1],
35169         x1 = +extent[1][0],
35170         y1 = +extent[1][1];
35171     clipEdges(x0, y0, x1, y1);
35172     clipCells(x0, y0, x1, y1);
35173   }
35174
35175   this.edges = edges;
35176   this.cells = cells;
35177
35178   beaches =
35179   circles =
35180   edges =
35181   cells = null;
35182 }
35183
35184 Diagram.prototype = {
35185   constructor: Diagram,
35186
35187   polygons: function() {
35188     var edges = this.edges;
35189
35190     return this.cells.map(function(cell) {
35191       var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
35192       polygon.data = cell.site.data;
35193       return polygon;
35194     });
35195   },
35196
35197   triangles: function() {
35198     var triangles = [],
35199         edges = this.edges;
35200
35201     this.cells.forEach(function(cell, i) {
35202       if (!(m = (halfedges = cell.halfedges).length)) return;
35203       var site = cell.site,
35204           halfedges,
35205           j = -1,
35206           m,
35207           s0,
35208           e1 = edges[halfedges[m - 1]],
35209           s1 = e1.left === site ? e1.right : e1.left;
35210
35211       while (++j < m) {
35212         s0 = s1;
35213         e1 = edges[halfedges[j]];
35214         s1 = e1.left === site ? e1.right : e1.left;
35215         if (s0 && s1 && i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
35216           triangles.push([site.data, s0.data, s1.data]);
35217         }
35218       }
35219     });
35220
35221     return triangles;
35222   },
35223
35224   links: function() {
35225     return this.edges.filter(function(edge) {
35226       return edge.right;
35227     }).map(function(edge) {
35228       return {
35229         source: edge.left.data,
35230         target: edge.right.data
35231       };
35232     });
35233   },
35234
35235   find: function(x, y, radius) {
35236     var that = this, i0, i1 = that._found || 0, n = that.cells.length, cell;
35237
35238     // Use the previously-found cell, or start with an arbitrary one.
35239     while (!(cell = that.cells[i1])) if (++i1 >= n) return null;
35240     var dx = x - cell.site[0], dy = y - cell.site[1], d2 = dx * dx + dy * dy;
35241
35242     // Traverse the half-edges to find a closer cell, if any.
35243     do {
35244       cell = that.cells[i0 = i1], i1 = null;
35245       cell.halfedges.forEach(function(e) {
35246         var edge = that.edges[e], v = edge.left;
35247         if ((v === cell.site || !v) && !(v = edge.right)) return;
35248         var vx = x - v[0], vy = y - v[1], v2 = vx * vx + vy * vy;
35249         if (v2 < d2) d2 = v2, i1 = v.index;
35250       });
35251     } while (i1 !== null);
35252
35253     that._found = i0;
35254
35255     return radius == null || d2 <= radius * radius ? cell.site : null;
35256   }
35257 };
35258
35259 var voronoi = function() {
35260   var x = x$4,
35261       y = y$4,
35262       extent = null;
35263
35264   function voronoi(data) {
35265     return new Diagram(data.map(function(d, i) {
35266       var s = [Math.round(x(d, i, data) / epsilon$4) * epsilon$4, Math.round(y(d, i, data) / epsilon$4) * epsilon$4];
35267       s.index = i;
35268       s.data = d;
35269       return s;
35270     }), extent);
35271   }
35272
35273   voronoi.polygons = function(data) {
35274     return voronoi(data).polygons();
35275   };
35276
35277   voronoi.links = function(data) {
35278     return voronoi(data).links();
35279   };
35280
35281   voronoi.triangles = function(data) {
35282     return voronoi(data).triangles();
35283   };
35284
35285   voronoi.x = function(_) {
35286     return arguments.length ? (x = typeof _ === "function" ? _ : constant$11(+_), voronoi) : x;
35287   };
35288
35289   voronoi.y = function(_) {
35290     return arguments.length ? (y = typeof _ === "function" ? _ : constant$11(+_), voronoi) : y;
35291   };
35292
35293   voronoi.extent = function(_) {
35294     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]]];
35295   };
35296
35297   voronoi.size = function(_) {
35298     return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0] - extent[0][0], extent[1][1] - extent[0][1]];
35299   };
35300
35301   return voronoi;
35302 };
35303
35304 var constant$12 = function(x) {
35305   return function() {
35306     return x;
35307   };
35308 };
35309
35310 function ZoomEvent(target, type, transform) {
35311   this.target = target;
35312   this.type = type;
35313   this.transform = transform;
35314 }
35315
35316 function Transform(k, x, y) {
35317   this.k = k;
35318   this.x = x;
35319   this.y = y;
35320 }
35321
35322 Transform.prototype = {
35323   constructor: Transform,
35324   scale: function(k) {
35325     return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
35326   },
35327   translate: function(x, y) {
35328     return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
35329   },
35330   apply: function(point) {
35331     return [point[0] * this.k + this.x, point[1] * this.k + this.y];
35332   },
35333   applyX: function(x) {
35334     return x * this.k + this.x;
35335   },
35336   applyY: function(y) {
35337     return y * this.k + this.y;
35338   },
35339   invert: function(location) {
35340     return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
35341   },
35342   invertX: function(x) {
35343     return (x - this.x) / this.k;
35344   },
35345   invertY: function(y) {
35346     return (y - this.y) / this.k;
35347   },
35348   rescaleX: function(x) {
35349     return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
35350   },
35351   rescaleY: function(y) {
35352     return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
35353   },
35354   toString: function() {
35355     return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
35356   }
35357 };
35358
35359 var identity$8 = new Transform(1, 0, 0);
35360
35361 transform$1.prototype = Transform.prototype;
35362
35363 function transform$1(node) {
35364   return node.__zoom || identity$8;
35365 }
35366
35367 function nopropagation$2() {
35368   event.stopImmediatePropagation();
35369 }
35370
35371 var noevent$2 = function() {
35372   event.preventDefault();
35373   event.stopImmediatePropagation();
35374 };
35375
35376 // Ignore right-click, since that should open the context menu.
35377 function defaultFilter$2() {
35378   return !event.button;
35379 }
35380
35381 function defaultExtent$1() {
35382   var e = this, w, h;
35383   if (e instanceof SVGElement) {
35384     e = e.ownerSVGElement || e;
35385     w = e.width.baseVal.value;
35386     h = e.height.baseVal.value;
35387   } else {
35388     w = e.clientWidth;
35389     h = e.clientHeight;
35390   }
35391   return [[0, 0], [w, h]];
35392 }
35393
35394 function defaultTransform() {
35395   return this.__zoom || identity$8;
35396 }
35397
35398 function defaultWheelDelta() {
35399   return -event.deltaY * (event.deltaMode ? 120 : 1) / 500;
35400 }
35401
35402 function touchable$1() {
35403   return "ontouchstart" in this;
35404 }
35405
35406 var zoom = function() {
35407   var filter = defaultFilter$2,
35408       extent = defaultExtent$1,
35409       wheelDelta = defaultWheelDelta,
35410       k0 = 0,
35411       k1 = Infinity,
35412       x0 = -k1,
35413       x1 = k1,
35414       y0 = x0,
35415       y1 = x1,
35416       duration = 250,
35417       interpolate = interpolateZoom,
35418       gestures = [],
35419       listeners = dispatch("start", "zoom", "end"),
35420       touchstarting,
35421       touchending,
35422       touchDelay = 500,
35423       wheelDelay = 150,
35424       clickDistance2 = 0;
35425
35426   function zoom(selection$$1) {
35427     selection$$1
35428         .property("__zoom", defaultTransform)
35429         .on("wheel.zoom", wheeled)
35430         .on("mousedown.zoom", mousedowned)
35431         .on("dblclick.zoom", dblclicked)
35432       .filter(touchable$1)
35433         .on("touchstart.zoom", touchstarted)
35434         .on("touchmove.zoom", touchmoved)
35435         .on("touchend.zoom touchcancel.zoom", touchended)
35436         .style("touch-action", "none")
35437         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
35438   }
35439
35440   zoom.transform = function(collection, transform$$1) {
35441     var selection$$1 = collection.selection ? collection.selection() : collection;
35442     selection$$1.property("__zoom", defaultTransform);
35443     if (collection !== selection$$1) {
35444       schedule(collection, transform$$1);
35445     } else {
35446       selection$$1.interrupt().each(function() {
35447         gesture(this, arguments)
35448             .start()
35449             .zoom(null, typeof transform$$1 === "function" ? transform$$1.apply(this, arguments) : transform$$1)
35450             .end();
35451       });
35452     }
35453   };
35454
35455   zoom.scaleBy = function(selection$$1, k) {
35456     zoom.scaleTo(selection$$1, function() {
35457       var k0 = this.__zoom.k,
35458           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35459       return k0 * k1;
35460     });
35461   };
35462
35463   zoom.scaleTo = function(selection$$1, k) {
35464     zoom.transform(selection$$1, function() {
35465       var e = extent.apply(this, arguments),
35466           t0 = this.__zoom,
35467           p0 = centroid(e),
35468           p1 = t0.invert(p0),
35469           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35470       return constrain(translate(scale(t0, k1), p0, p1), e);
35471     });
35472   };
35473
35474   zoom.translateBy = function(selection$$1, x, y) {
35475     zoom.transform(selection$$1, function() {
35476       return constrain(this.__zoom.translate(
35477         typeof x === "function" ? x.apply(this, arguments) : x,
35478         typeof y === "function" ? y.apply(this, arguments) : y
35479       ), extent.apply(this, arguments));
35480     });
35481   };
35482
35483   zoom.translateTo = function(selection$$1, x, y) {
35484     zoom.transform(selection$$1, function() {
35485       var e = extent.apply(this, arguments),
35486           t = this.__zoom,
35487           p = centroid(e);
35488       return constrain(identity$8.translate(p[0], p[1]).scale(t.k).translate(
35489         typeof x === "function" ? -x.apply(this, arguments) : -x,
35490         typeof y === "function" ? -y.apply(this, arguments) : -y
35491       ), e);
35492     });
35493   };
35494
35495   function scale(transform$$1, k) {
35496     k = Math.max(k0, Math.min(k1, k));
35497     return k === transform$$1.k ? transform$$1 : new Transform(k, transform$$1.x, transform$$1.y);
35498   }
35499
35500   function translate(transform$$1, p0, p1) {
35501     var x = p0[0] - p1[0] * transform$$1.k, y = p0[1] - p1[1] * transform$$1.k;
35502     return x === transform$$1.x && y === transform$$1.y ? transform$$1 : new Transform(transform$$1.k, x, y);
35503   }
35504
35505   function constrain(transform$$1, extent) {
35506     var dx0 = transform$$1.invertX(extent[0][0]) - x0,
35507         dx1 = transform$$1.invertX(extent[1][0]) - x1,
35508         dy0 = transform$$1.invertY(extent[0][1]) - y0,
35509         dy1 = transform$$1.invertY(extent[1][1]) - y1;
35510     return transform$$1.translate(
35511       dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
35512       dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
35513     );
35514   }
35515
35516   function centroid(extent) {
35517     return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
35518   }
35519
35520   function schedule(transition$$1, transform$$1, center) {
35521     transition$$1
35522         .on("start.zoom", function() { gesture(this, arguments).start(); })
35523         .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).end(); })
35524         .tween("zoom", function() {
35525           var that = this,
35526               args = arguments,
35527               g = gesture(that, args),
35528               e = extent.apply(that, args),
35529               p = center || centroid(e),
35530               w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
35531               a = that.__zoom,
35532               b = typeof transform$$1 === "function" ? transform$$1.apply(that, args) : transform$$1,
35533               i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
35534           return function(t) {
35535             if (t === 1) t = b; // Avoid rounding error on end.
35536             else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); }
35537             g.zoom(null, t);
35538           };
35539         });
35540   }
35541
35542   function gesture(that, args) {
35543     for (var i = 0, n = gestures.length, g; i < n; ++i) {
35544       if ((g = gestures[i]).that === that) {
35545         return g;
35546       }
35547     }
35548     return new Gesture(that, args);
35549   }
35550
35551   function Gesture(that, args) {
35552     this.that = that;
35553     this.args = args;
35554     this.index = -1;
35555     this.active = 0;
35556     this.extent = extent.apply(that, args);
35557   }
35558
35559   Gesture.prototype = {
35560     start: function() {
35561       if (++this.active === 1) {
35562         this.index = gestures.push(this) - 1;
35563         this.emit("start");
35564       }
35565       return this;
35566     },
35567     zoom: function(key, transform$$1) {
35568       if (this.mouse && key !== "mouse") this.mouse[1] = transform$$1.invert(this.mouse[0]);
35569       if (this.touch0 && key !== "touch") this.touch0[1] = transform$$1.invert(this.touch0[0]);
35570       if (this.touch1 && key !== "touch") this.touch1[1] = transform$$1.invert(this.touch1[0]);
35571       this.that.__zoom = transform$$1;
35572       this.emit("zoom");
35573       return this;
35574     },
35575     end: function() {
35576       if (--this.active === 0) {
35577         gestures.splice(this.index, 1);
35578         this.index = -1;
35579         this.emit("end");
35580       }
35581       return this;
35582     },
35583     emit: function(type) {
35584       customEvent(new ZoomEvent(zoom, type, this.that.__zoom), listeners.apply, listeners, [type, this.that, this.args]);
35585     }
35586   };
35587
35588   function wheeled() {
35589     if (!filter.apply(this, arguments)) return;
35590     var g = gesture(this, arguments),
35591         t = this.__zoom,
35592         k = Math.max(k0, Math.min(k1, t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
35593         p = mouse(this);
35594
35595     // If the mouse is in the same location as before, reuse it.
35596     // If there were recent wheel events, reset the wheel idle timeout.
35597     if (g.wheel) {
35598       if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
35599         g.mouse[1] = t.invert(g.mouse[0] = p);
35600       }
35601       clearTimeout(g.wheel);
35602     }
35603
35604     // If this wheel event won’t trigger a transform change, ignore it.
35605     else if (t.k === k) return;
35606
35607     // Otherwise, capture the mouse point and location at the start.
35608     else {
35609       g.mouse = [p, t.invert(p)];
35610       interrupt(this);
35611       g.start();
35612     }
35613
35614     noevent$2();
35615     g.wheel = setTimeout(wheelidled, wheelDelay);
35616     g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent));
35617
35618     function wheelidled() {
35619       g.wheel = null;
35620       g.end();
35621     }
35622   }
35623
35624   function mousedowned() {
35625     if (touchending || !filter.apply(this, arguments)) return;
35626     var g = gesture(this, arguments),
35627         v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
35628         p = mouse(this),
35629         x0 = event.clientX,
35630         y0 = event.clientY;
35631
35632     dragDisable(event.view);
35633     nopropagation$2();
35634     g.mouse = [p, this.__zoom.invert(p)];
35635     interrupt(this);
35636     g.start();
35637
35638     function mousemoved() {
35639       noevent$2();
35640       if (!g.moved) {
35641         var dx = event.clientX - x0, dy = event.clientY - y0;
35642         g.moved = dx * dx + dy * dy > clickDistance2;
35643       }
35644       g.zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = mouse(g.that), g.mouse[1]), g.extent));
35645     }
35646
35647     function mouseupped() {
35648       v.on("mousemove.zoom mouseup.zoom", null);
35649       yesdrag(event.view, g.moved);
35650       noevent$2();
35651       g.end();
35652     }
35653   }
35654
35655   function dblclicked() {
35656     if (!filter.apply(this, arguments)) return;
35657     var t0 = this.__zoom,
35658         p0 = mouse(this),
35659         p1 = t0.invert(p0),
35660         k1 = t0.k * (event.shiftKey ? 0.5 : 2),
35661         t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, arguments));
35662
35663     noevent$2();
35664     if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0);
35665     else select(this).call(zoom.transform, t1);
35666   }
35667
35668   function touchstarted() {
35669     if (!filter.apply(this, arguments)) return;
35670     var g = gesture(this, arguments),
35671         touches$$1 = event.changedTouches,
35672         started,
35673         n = touches$$1.length, i, t, p;
35674
35675     nopropagation$2();
35676     for (i = 0; i < n; ++i) {
35677       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35678       p = [p, this.__zoom.invert(p), t.identifier];
35679       if (!g.touch0) g.touch0 = p, started = true;
35680       else if (!g.touch1) g.touch1 = p;
35681     }
35682
35683     // If this is a dbltap, reroute to the (optional) dblclick.zoom handler.
35684     if (touchstarting) {
35685       touchstarting = clearTimeout(touchstarting);
35686       if (!g.touch1) {
35687         g.end();
35688         p = select(this).on("dblclick.zoom");
35689         if (p) p.apply(this, arguments);
35690         return;
35691       }
35692     }
35693
35694     if (started) {
35695       touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);
35696       interrupt(this);
35697       g.start();
35698     }
35699   }
35700
35701   function touchmoved() {
35702     var g = gesture(this, arguments),
35703         touches$$1 = event.changedTouches,
35704         n = touches$$1.length, i, t, p, l;
35705
35706     noevent$2();
35707     if (touchstarting) touchstarting = clearTimeout(touchstarting);
35708     for (i = 0; i < n; ++i) {
35709       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35710       if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;
35711       else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
35712     }
35713     t = g.that.__zoom;
35714     if (g.touch1) {
35715       var p0 = g.touch0[0], l0 = g.touch0[1],
35716           p1 = g.touch1[0], l1 = g.touch1[1],
35717           dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
35718           dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
35719       t = scale(t, Math.sqrt(dp / dl));
35720       p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
35721       l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
35722     }
35723     else if (g.touch0) p = g.touch0[0], l = g.touch0[1];
35724     else return;
35725     g.zoom("touch", constrain(translate(t, p, l), g.extent));
35726   }
35727
35728   function touchended() {
35729     var g = gesture(this, arguments),
35730         touches$$1 = event.changedTouches,
35731         n = touches$$1.length, i, t;
35732
35733     nopropagation$2();
35734     if (touchending) clearTimeout(touchending);
35735     touchending = setTimeout(function() { touchending = null; }, touchDelay);
35736     for (i = 0; i < n; ++i) {
35737       t = touches$$1[i];
35738       if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;
35739       else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
35740     }
35741     if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
35742     if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);
35743     else g.end();
35744   }
35745
35746   zoom.wheelDelta = function(_) {
35747     return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant$12(+_), zoom) : wheelDelta;
35748   };
35749
35750   zoom.filter = function(_) {
35751     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$12(!!_), zoom) : filter;
35752   };
35753
35754   zoom.extent = function(_) {
35755     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$12([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
35756   };
35757
35758   zoom.scaleExtent = function(_) {
35759     return arguments.length ? (k0 = +_[0], k1 = +_[1], zoom) : [k0, k1];
35760   };
35761
35762   zoom.translateExtent = function(_) {
35763     return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], zoom) : [[x0, y0], [x1, y1]];
35764   };
35765
35766   zoom.duration = function(_) {
35767     return arguments.length ? (duration = +_, zoom) : duration;
35768   };
35769
35770   zoom.interpolate = function(_) {
35771     return arguments.length ? (interpolate = _, zoom) : interpolate;
35772   };
35773
35774   zoom.on = function() {
35775     var value = listeners.on.apply(listeners, arguments);
35776     return value === listeners ? zoom : value;
35777   };
35778
35779   zoom.clickDistance = function(_) {
35780     return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
35781   };
35782
35783   return zoom;
35784 };
35785
35786
35787
35788 var index$2 = Object.freeze({
35789         version: version,
35790         bisect: bisectRight,
35791         bisectRight: bisectRight,
35792         bisectLeft: bisectLeft,
35793         ascending: ascending,
35794         bisector: bisector,
35795         cross: cross,
35796         descending: descending,
35797         deviation: deviation,
35798         extent: extent,
35799         histogram: histogram,
35800         thresholdFreedmanDiaconis: freedmanDiaconis,
35801         thresholdScott: scott,
35802         thresholdSturges: sturges,
35803         max: max,
35804         mean: mean,
35805         median: median,
35806         merge: merge,
35807         min: min,
35808         pairs: pairs,
35809         permute: permute,
35810         quantile: threshold,
35811         range: sequence,
35812         scan: scan,
35813         shuffle: shuffle,
35814         sum: sum,
35815         ticks: ticks,
35816         tickIncrement: tickIncrement,
35817         tickStep: tickStep,
35818         transpose: transpose,
35819         variance: variance,
35820         zip: zip,
35821         axisTop: axisTop,
35822         axisRight: axisRight,
35823         axisBottom: axisBottom,
35824         axisLeft: axisLeft,
35825         brush: brush,
35826         brushX: brushX,
35827         brushY: brushY,
35828         brushSelection: brushSelection,
35829         chord: chord,
35830         ribbon: ribbon,
35831         nest: nest,
35832         set: set$2,
35833         map: map$1,
35834         keys: keys,
35835         values: values,
35836         entries: entries,
35837         color: color,
35838         rgb: rgb,
35839         hsl: hsl,
35840         lab: lab,
35841         hcl: hcl,
35842         cubehelix: cubehelix,
35843         dispatch: dispatch,
35844         drag: drag,
35845         dragDisable: dragDisable,
35846         dragEnable: yesdrag,
35847         dsvFormat: dsv,
35848         csvParse: csvParse,
35849         csvParseRows: csvParseRows,
35850         csvFormat: csvFormat,
35851         csvFormatRows: csvFormatRows,
35852         tsvParse: tsvParse,
35853         tsvParseRows: tsvParseRows,
35854         tsvFormat: tsvFormat,
35855         tsvFormatRows: tsvFormatRows,
35856         easeLinear: linear$1,
35857         easeQuad: quadInOut,
35858         easeQuadIn: quadIn,
35859         easeQuadOut: quadOut,
35860         easeQuadInOut: quadInOut,
35861         easeCubic: cubicInOut,
35862         easeCubicIn: cubicIn,
35863         easeCubicOut: cubicOut,
35864         easeCubicInOut: cubicInOut,
35865         easePoly: polyInOut,
35866         easePolyIn: polyIn,
35867         easePolyOut: polyOut,
35868         easePolyInOut: polyInOut,
35869         easeSin: sinInOut,
35870         easeSinIn: sinIn,
35871         easeSinOut: sinOut,
35872         easeSinInOut: sinInOut,
35873         easeExp: expInOut,
35874         easeExpIn: expIn,
35875         easeExpOut: expOut,
35876         easeExpInOut: expInOut,
35877         easeCircle: circleInOut,
35878         easeCircleIn: circleIn,
35879         easeCircleOut: circleOut,
35880         easeCircleInOut: circleInOut,
35881         easeBounce: bounceOut,
35882         easeBounceIn: bounceIn,
35883         easeBounceOut: bounceOut,
35884         easeBounceInOut: bounceInOut,
35885         easeBack: backInOut,
35886         easeBackIn: backIn,
35887         easeBackOut: backOut,
35888         easeBackInOut: backInOut,
35889         easeElastic: elasticOut,
35890         easeElasticIn: elasticIn,
35891         easeElasticOut: elasticOut,
35892         easeElasticInOut: elasticInOut,
35893         forceCenter: center$1,
35894         forceCollide: collide,
35895         forceLink: link,
35896         forceManyBody: manyBody,
35897         forceSimulation: simulation,
35898         forceX: x$2,
35899         forceY: y$2,
35900         formatDefaultLocale: defaultLocale,
35901         get format () { return format; },
35902         get formatPrefix () { return formatPrefix; },
35903         formatLocale: formatLocale,
35904         formatSpecifier: formatSpecifier,
35905         precisionFixed: precisionFixed,
35906         precisionPrefix: precisionPrefix,
35907         precisionRound: precisionRound,
35908         geoArea: area,
35909         geoBounds: bounds,
35910         geoCentroid: d3GeoCentroid,
35911         geoCircle: circle,
35912         geoClipExtent: extent$1,
35913         geoContains: contains,
35914         geoDistance: distance,
35915         geoGraticule: graticule,
35916         geoGraticule10: graticule10,
35917         geoInterpolate: interpolate$1,
35918         geoLength: d3GeoLength,
35919         geoPath: index$4,
35920         geoAlbers: albers,
35921         geoAlbersUsa: albersUsa,
35922         geoAzimuthalEqualArea: azimuthalEqualArea,
35923         geoAzimuthalEqualAreaRaw: azimuthalEqualAreaRaw,
35924         geoAzimuthalEquidistant: azimuthalEquidistant,
35925         geoAzimuthalEquidistantRaw: azimuthalEquidistantRaw,
35926         geoConicConformal: conicConformal,
35927         geoConicConformalRaw: conicConformalRaw,
35928         geoConicEqualArea: conicEqualArea,
35929         geoConicEqualAreaRaw: conicEqualAreaRaw,
35930         geoConicEquidistant: conicEquidistant,
35931         geoConicEquidistantRaw: conicEquidistantRaw,
35932         geoEquirectangular: equirectangular,
35933         geoEquirectangularRaw: equirectangularRaw,
35934         geoGnomonic: gnomonic,
35935         geoGnomonicRaw: gnomonicRaw,
35936         geoIdentity: identity$5,
35937         geoProjection: projection,
35938         geoProjectionMutator: projectionMutator,
35939         geoMercator: mercator,
35940         geoMercatorRaw: mercatorRaw,
35941         geoOrthographic: orthographic,
35942         geoOrthographicRaw: orthographicRaw,
35943         geoStereographic: stereographic,
35944         geoStereographicRaw: stereographicRaw,
35945         geoTransverseMercator: transverseMercator,
35946         geoTransverseMercatorRaw: transverseMercatorRaw,
35947         geoRotation: rotation,
35948         geoStream: geoStream,
35949         geoTransform: transform,
35950         cluster: cluster,
35951         hierarchy: hierarchy,
35952         pack: index$5,
35953         packSiblings: siblings,
35954         packEnclose: enclose,
35955         partition: partition,
35956         stratify: stratify,
35957         tree: tree,
35958         treemap: index$6,
35959         treemapBinary: binary,
35960         treemapDice: treemapDice,
35961         treemapSlice: treemapSlice,
35962         treemapSliceDice: sliceDice,
35963         treemapSquarify: squarify,
35964         treemapResquarify: resquarify,
35965         interpolate: interpolateValue,
35966         interpolateArray: array$1,
35967         interpolateBasis: basis$1,
35968         interpolateBasisClosed: basisClosed,
35969         interpolateDate: date,
35970         interpolateNumber: reinterpolate,
35971         interpolateObject: object,
35972         interpolateRound: interpolateRound,
35973         interpolateString: interpolateString,
35974         interpolateTransformCss: interpolateTransformCss,
35975         interpolateTransformSvg: interpolateTransformSvg,
35976         interpolateZoom: interpolateZoom,
35977         interpolateRgb: interpolateRgb,
35978         interpolateRgbBasis: rgbBasis,
35979         interpolateRgbBasisClosed: rgbBasisClosed,
35980         interpolateHsl: hsl$2,
35981         interpolateHslLong: hslLong,
35982         interpolateLab: lab$1,
35983         interpolateHcl: hcl$2,
35984         interpolateHclLong: hclLong,
35985         interpolateCubehelix: cubehelix$2,
35986         interpolateCubehelixLong: cubehelixLong,
35987         quantize: quantize,
35988         path: path,
35989         polygonArea: d3polygonArea,
35990         polygonCentroid: d3polygonCentroid,
35991         polygonHull: d3polygonHull,
35992         polygonContains: contains$1,
35993         polygonLength: length$1,
35994         quadtree: quadtree,
35995         queue: queue,
35996         randomUniform: uniform,
35997         randomNormal: normal,
35998         randomLogNormal: logNormal,
35999         randomBates: bates,
36000         randomIrwinHall: irwinHall,
36001         randomExponential: exponential$1,
36002         request: request,
36003         html: html,
36004         json: json,
36005         text: text,
36006         xml: xml,
36007         csv: csv$1,
36008         tsv: tsv$1,
36009         scaleBand: band,
36010         scalePoint: point$1,
36011         scaleIdentity: identity$6,
36012         scaleLinear: linear$2,
36013         scaleLog: log$1,
36014         scaleOrdinal: ordinal,
36015         scaleImplicit: implicit,
36016         scalePow: pow$1,
36017         scaleSqrt: sqrt$1,
36018         scaleQuantile: quantile,
36019         scaleQuantize: quantize$1,
36020         scaleThreshold: threshold$1,
36021         scaleTime: time,
36022         scaleUtc: utcTime,
36023         schemeCategory10: category10,
36024         schemeCategory20b: category20b,
36025         schemeCategory20c: category20c,
36026         schemeCategory20: category20,
36027         interpolateCubehelixDefault: cubehelix$3,
36028         interpolateRainbow: rainbow$1,
36029         interpolateWarm: warm,
36030         interpolateCool: cool,
36031         interpolateViridis: viridis,
36032         interpolateMagma: magma,
36033         interpolateInferno: inferno,
36034         interpolatePlasma: plasma,
36035         scaleSequential: sequential,
36036         creator: creator,
36037         local: local$1,
36038         matcher: matcher$1,
36039         mouse: mouse,
36040         namespace: namespace,
36041         namespaces: namespaces,
36042         select: select,
36043         selectAll: selectAll,
36044         selection: selection,
36045         selector: selector,
36046         selectorAll: selectorAll,
36047         style: styleValue,
36048         touch: touch,
36049         touches: touches,
36050         window: defaultView,
36051         get event () { return event; },
36052         customEvent: customEvent,
36053         arc: arc,
36054         area: area$1,
36055         line: line,
36056         pie: pie,
36057         areaRadial: areaRadial,
36058         radialArea: areaRadial,
36059         lineRadial: lineRadial$1,
36060         radialLine: lineRadial$1,
36061         pointRadial: pointRadial,
36062         linkHorizontal: linkHorizontal,
36063         linkVertical: linkVertical,
36064         linkRadial: linkRadial,
36065         symbol: symbol,
36066         symbols: symbols,
36067         symbolCircle: circle$2,
36068         symbolCross: cross$2,
36069         symbolDiamond: diamond,
36070         symbolSquare: square,
36071         symbolStar: star,
36072         symbolTriangle: triangle,
36073         symbolWye: wye,
36074         curveBasisClosed: basisClosed$1,
36075         curveBasisOpen: basisOpen,
36076         curveBasis: basis$2,
36077         curveBundle: bundle,
36078         curveCardinalClosed: cardinalClosed,
36079         curveCardinalOpen: cardinalOpen,
36080         curveCardinal: cardinal,
36081         curveCatmullRomClosed: catmullRomClosed,
36082         curveCatmullRomOpen: catmullRomOpen,
36083         curveCatmullRom: catmullRom,
36084         curveLinearClosed: linearClosed,
36085         curveLinear: curveLinear,
36086         curveMonotoneX: monotoneX,
36087         curveMonotoneY: monotoneY,
36088         curveNatural: natural,
36089         curveStep: step,
36090         curveStepAfter: stepAfter,
36091         curveStepBefore: stepBefore,
36092         stack: stack,
36093         stackOffsetExpand: expand,
36094         stackOffsetDiverging: diverging,
36095         stackOffsetNone: none$1,
36096         stackOffsetSilhouette: silhouette,
36097         stackOffsetWiggle: wiggle,
36098         stackOrderAscending: ascending$2,
36099         stackOrderDescending: descending$2,
36100         stackOrderInsideOut: insideOut,
36101         stackOrderNone: none$2,
36102         stackOrderReverse: reverse,
36103         timeInterval: newInterval,
36104         timeMillisecond: millisecond,
36105         timeMilliseconds: milliseconds,
36106         utcMillisecond: millisecond,
36107         utcMilliseconds: milliseconds,
36108         timeSecond: second,
36109         timeSeconds: seconds,
36110         utcSecond: second,
36111         utcSeconds: seconds,
36112         timeMinute: minute,
36113         timeMinutes: minutes,
36114         timeHour: hour,
36115         timeHours: hours,
36116         timeDay: day,
36117         timeDays: days,
36118         timeWeek: sunday,
36119         timeWeeks: sundays,
36120         timeSunday: sunday,
36121         timeSundays: sundays,
36122         timeMonday: monday,
36123         timeMondays: mondays,
36124         timeTuesday: tuesday,
36125         timeTuesdays: tuesdays,
36126         timeWednesday: wednesday,
36127         timeWednesdays: wednesdays,
36128         timeThursday: thursday,
36129         timeThursdays: thursdays,
36130         timeFriday: friday,
36131         timeFridays: fridays,
36132         timeSaturday: saturday,
36133         timeSaturdays: saturdays,
36134         timeMonth: month,
36135         timeMonths: months,
36136         timeYear: year,
36137         timeYears: years,
36138         utcMinute: utcMinute,
36139         utcMinutes: utcMinutes,
36140         utcHour: utcHour,
36141         utcHours: utcHours,
36142         utcDay: utcDay,
36143         utcDays: utcDays,
36144         utcWeek: utcSunday,
36145         utcWeeks: utcSundays,
36146         utcSunday: utcSunday,
36147         utcSundays: utcSundays,
36148         utcMonday: utcMonday,
36149         utcMondays: utcMondays,
36150         utcTuesday: utcTuesday,
36151         utcTuesdays: utcTuesdays,
36152         utcWednesday: utcWednesday,
36153         utcWednesdays: utcWednesdays,
36154         utcThursday: utcThursday,
36155         utcThursdays: utcThursdays,
36156         utcFriday: utcFriday,
36157         utcFridays: utcFridays,
36158         utcSaturday: utcSaturday,
36159         utcSaturdays: utcSaturdays,
36160         utcMonth: utcMonth,
36161         utcMonths: utcMonths,
36162         utcYear: utcYear,
36163         utcYears: utcYears,
36164         timeFormatDefaultLocale: defaultLocale$1,
36165         get timeFormat () { return timeFormat; },
36166         get timeParse () { return timeParse; },
36167         get utcFormat () { return utcFormat; },
36168         get utcParse () { return utcParse; },
36169         timeFormatLocale: formatLocale$1,
36170         isoFormat: formatIso,
36171         isoParse: parseIso,
36172         now: now,
36173         timer: timer,
36174         timerFlush: timerFlush,
36175         timeout: timeout$1,
36176         interval: interval$1,
36177         transition: transition,
36178         active: active,
36179         interrupt: interrupt,
36180         voronoi: voronoi,
36181         zoom: zoom,
36182         zoomTransform: transform$1,
36183         zoomIdentity: identity$8
36184 });
36185
36186 /*
36187     Bypasses features of D3's default projection stream pipeline that are unnecessary:
36188     * Antimeridian clipping
36189     * Spherical rotation
36190     * Resampling
36191 */
36192 function geoRawMercator() {
36193     var project = mercatorRaw,
36194         k = 512 / Math.PI, // scale
36195         x = 0, y = 0, // translate
36196         clipExtent = [[0, 0], [0, 0]];
36197
36198
36199     function projection$$1(point) {
36200         point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
36201         return [point[0] * k + x, y - point[1] * k];
36202     }
36203
36204
36205     projection$$1.invert = function(point) {
36206         point = project.invert((point[0] - x) / k, (y - point[1]) / k);
36207         return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
36208     };
36209
36210
36211     projection$$1.scale = function(_) {
36212         if (!arguments.length) return k;
36213         k = +_;
36214         return projection$$1;
36215     };
36216
36217
36218     projection$$1.translate = function(_) {
36219         if (!arguments.length) return [x, y];
36220         x = +_[0];
36221         y = +_[1];
36222         return projection$$1;
36223     };
36224
36225
36226     projection$$1.clipExtent = function(_) {
36227         if (!arguments.length) return clipExtent;
36228         clipExtent = _;
36229         return projection$$1;
36230     };
36231
36232
36233     projection$$1.transform = function(_) {
36234         if (!arguments.length) return identity$8.translate(x, y).scale(k);
36235         x = +_.x;
36236         y = +_.y;
36237         k = +_.k;
36238         return projection$$1;
36239     };
36240
36241
36242     projection$$1.stream = transform({
36243         point: function(x, y) {
36244             x = projection$$1([x, y]);
36245             this.stream.point(x[0], x[1]);
36246         }
36247     }).stream;
36248
36249
36250     return projection$$1;
36251 }
36252
36253 function osmChangeset() {
36254     if (!(this instanceof osmChangeset)) {
36255         return (new osmChangeset()).initialize(arguments);
36256     } else if (arguments.length) {
36257         this.initialize(arguments);
36258     }
36259 }
36260
36261
36262 osmEntity$$1.changeset = osmChangeset;
36263
36264 osmChangeset.prototype = Object.create(osmEntity$$1.prototype);
36265
36266 lodash.extend(osmChangeset.prototype, {
36267
36268     type: 'changeset',
36269
36270
36271     extent: function() {
36272         return new geoExtent$$1();
36273     },
36274
36275
36276     geometry: function() {
36277         return 'changeset';
36278     },
36279
36280
36281     asJXON: function() {
36282         return {
36283             osm: {
36284                 changeset: {
36285                     tag: lodash.map(this.tags, function(value, key) {
36286                         return { '@k': key, '@v': value };
36287                     }),
36288                     '@version': 0.6,
36289                     '@generator': 'iD'
36290                 }
36291             }
36292         };
36293     },
36294
36295
36296     // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
36297     // XML. Returns a string.
36298     osmChangeJXON: function(changes) {
36299         var changeset_id = this.id;
36300
36301         function nest(x, order) {
36302             var groups = {};
36303             for (var i = 0; i < x.length; i++) {
36304                 var tagName = Object.keys(x[i])[0];
36305                 if (!groups[tagName]) groups[tagName] = [];
36306                 groups[tagName].push(x[i][tagName]);
36307             }
36308             var ordered = {};
36309             order.forEach(function(o) {
36310                 if (groups[o]) ordered[o] = groups[o];
36311             });
36312             return ordered;
36313         }
36314
36315
36316         // sort relations in a changeset by dependencies
36317         function sort(changes) {
36318
36319             // find a referenced relation in the current changeset
36320             function resolve(item) {
36321                 return lodash.find(relations, function(relation) {
36322                     return item.keyAttributes.type === 'relation'
36323                         && item.keyAttributes.ref === relation['@id'];
36324                 });
36325             }
36326
36327             // a new item is an item that has not been already processed
36328             function isNew(item) {
36329                 return !sorted[ item['@id'] ] && !lodash.find(processing, function(proc) {
36330                     return proc['@id'] === item['@id'];
36331                 });
36332             }
36333
36334             var processing = [],
36335                 sorted = {},
36336                 relations = changes.relation;
36337
36338             if (!relations) return changes;
36339
36340             for (var i = 0; i < relations.length; i++) {
36341                 var relation = relations[i];
36342
36343                 // skip relation if already sorted
36344                 if (!sorted[relation['@id']]) {
36345                     processing.push(relation);
36346                 }
36347
36348                 while (processing.length > 0) {
36349                     var next = processing[0],
36350                     deps = lodash.filter(lodash.compact(next.member.map(resolve)), isNew);
36351                     if (deps.length === 0) {
36352                         sorted[next['@id']] = next;
36353                         processing.shift();
36354                     } else {
36355                         processing = deps.concat(processing);
36356                     }
36357                 }
36358             }
36359
36360             changes.relation = lodash.values(sorted);
36361             return changes;
36362         }
36363
36364         function rep(entity) {
36365             return entity.asJXON(changeset_id);
36366         }
36367
36368         return {
36369             osmChange: {
36370                 '@version': 0.6,
36371                 '@generator': 'iD',
36372                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
36373                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
36374                 'delete': lodash.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), { '@if-unused': true })
36375             }
36376         };
36377     },
36378
36379
36380     asGeoJSON: function() {
36381         return {};
36382     }
36383
36384 });
36385
36386 function osmNode() {
36387     if (!(this instanceof osmNode)) {
36388         return (new osmNode()).initialize(arguments);
36389     } else if (arguments.length) {
36390         this.initialize(arguments);
36391     }
36392 }
36393
36394 osmEntity$$1.node = osmNode;
36395
36396 osmNode.prototype = Object.create(osmEntity$$1.prototype);
36397
36398 lodash.extend(osmNode.prototype, {
36399
36400     type: 'node',
36401
36402
36403     extent: function() {
36404         return new geoExtent$$1(this.loc);
36405     },
36406
36407
36408     geometry: function(graph) {
36409         return graph.transient(this, 'geometry', function() {
36410             return graph.isPoi(this) ? 'point' : 'vertex';
36411         });
36412     },
36413
36414
36415     move: function(loc) {
36416         return this.update({loc: loc});
36417     },
36418
36419
36420     isDegenerate: function() {
36421         return !(
36422             Array.isArray(this.loc) && this.loc.length === 2 &&
36423             this.loc[0] >= -180 && this.loc[0] <= 180 &&
36424             this.loc[1] >= -90 && this.loc[1] <= 90
36425         );
36426     },
36427
36428
36429     isEndpoint: function(resolver) {
36430         return resolver.transient(this, 'isEndpoint', function() {
36431             var id = this.id;
36432             return resolver.parentWays(this).filter(function(parent) {
36433                 return !parent.isClosed() && !!parent.affix(id);
36434             }).length > 0;
36435         });
36436     },
36437
36438
36439     isConnected: function(resolver) {
36440         return resolver.transient(this, 'isConnected', function() {
36441             var parents = resolver.parentWays(this);
36442
36443             function isLine(entity) {
36444                 return entity.geometry(resolver) === 'line' &&
36445                     entity.hasInterestingTags();
36446             }
36447
36448             // vertex is connected to multiple parent lines
36449             if (parents.length > 1 && lodash.some(parents, isLine)) {
36450                 return true;
36451
36452             } else if (parents.length === 1) {
36453                 var way = parents[0],
36454                     nodes = way.nodes.slice();
36455                 if (way.isClosed()) { nodes.pop(); }  // ignore connecting node if closed
36456
36457                 // return true if vertex appears multiple times (way is self intersecting)
36458                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
36459             }
36460
36461             return false;
36462         });
36463     },
36464
36465
36466     isIntersection: function(resolver) {
36467         return resolver.transient(this, 'isIntersection', function() {
36468             return resolver.parentWays(this).filter(function(parent) {
36469                 return (parent.tags.highway ||
36470                     parent.tags.waterway ||
36471                     parent.tags.railway ||
36472                     parent.tags.aeroway) &&
36473                     parent.geometry(resolver) === 'line';
36474             }).length > 1;
36475         });
36476     },
36477
36478
36479     isHighwayIntersection: function(resolver) {
36480         return resolver.transient(this, 'isHighwayIntersection', function() {
36481             return resolver.parentWays(this).filter(function(parent) {
36482                 return parent.tags.highway && parent.geometry(resolver) === 'line';
36483             }).length > 1;
36484         });
36485     },
36486
36487
36488     isOnAddressLine: function(resolver) {
36489         return resolver.transient(this, 'isOnAddressLine', function() {
36490             return resolver.parentWays(this).filter(function(parent) {
36491                 return parent.tags.hasOwnProperty('addr:interpolation') &&
36492                     parent.geometry(resolver) === 'line';
36493             }).length > 0;
36494         });
36495     },
36496
36497
36498     asJXON: function(changeset_id) {
36499         var r = {
36500             node: {
36501                 '@id': this.osmId(),
36502                 '@lon': this.loc[0],
36503                 '@lat': this.loc[1],
36504                 '@version': (this.version || 0),
36505                 tag: lodash.map(this.tags, function(v, k) {
36506                     return { keyAttributes: { k: k, v: v } };
36507                 })
36508             }
36509         };
36510         if (changeset_id) r.node['@changeset'] = changeset_id;
36511         return r;
36512     },
36513
36514
36515     asGeoJSON: function() {
36516         return {
36517             type: 'Point',
36518             coordinates: this.loc
36519         };
36520     }
36521 });
36522
36523 /*
36524   Order the nodes of a way in reverse order and reverse any direction dependent tags
36525   other than `oneway`. (We assume that correcting a backwards oneway is the primary
36526   reason for reversing a way.)
36527
36528   The following transforms are performed:
36529
36530     Keys:
36531           *:right=* ⟺ *:left=*
36532         *:forward=* ⟺ *:backward=*
36533        direction=up ⟺ direction=down
36534          incline=up ⟺ incline=down
36535             *=right ⟺ *=left
36536
36537     Relation members:
36538        role=forward ⟺ role=backward
36539          role=north ⟺ role=south
36540           role=east ⟺ role=west
36541
36542    In addition, numeric-valued `incline` tags are negated.
36543
36544    The JOSM implementation was used as a guide, but transformations that were of unclear benefit
36545    or adjusted tags that don't seem to be used in practice were omitted.
36546
36547    Also, each node on the way is examined for its own tags and the following transformations are performed
36548    in order to ensure associated nodes (eg a Stop Sign) is also reversed
36549
36550     Node Keys:
36551         direction=forward ⟺ direction=backward
36552         direction=left ⟺ direction=right
36553         *:forward=* ⟺ *:backward=*
36554         *:left=* ⟺ *:right=*
36555
36556    References:
36557       http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
36558       http://wiki.openstreetmap.org/wiki/Key:direction#Steps
36559       http://wiki.openstreetmap.org/wiki/Key:incline
36560       http://wiki.openstreetmap.org/wiki/Route#Members
36561       http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
36562       http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
36563       http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
36564  */
36565 function actionReverse(wayId, options) {
36566     var replacements = [
36567             [/:right$/, ':left'], [/:left$/, ':right'],
36568             [/:forward$/, ':backward'], [/:backward$/, ':forward']
36569         ],
36570         numeric = /^([+\-]?)(?=[\d.])/,
36571         roleReversals = {
36572             forward: 'backward',
36573             backward: 'forward',
36574             north: 'south',
36575             south: 'north',
36576             east: 'west',
36577             west: 'east'
36578         };
36579
36580
36581     function reverseKey(key) {
36582         for (var i = 0; i < replacements.length; ++i) {
36583             var replacement = replacements[i];
36584             if (replacement[0].test(key)) {
36585                 return key.replace(replacement[0], replacement[1]);
36586             }
36587         }
36588         return key;
36589     }
36590
36591
36592     function reverseValue(key, value) {
36593         if (key === 'incline' && numeric.test(value)) {
36594             return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
36595         } else if (key === 'incline' || key === 'direction') {
36596             return {up: 'down', down: 'up'}[value] || value;
36597         } else if (options && options.reverseOneway && key === 'oneway') {
36598             return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
36599         } else {
36600             return {left: 'right', right: 'left'}[value] || value;
36601         }
36602     }
36603
36604
36605     function reverseDirectionTags(node) {
36606         // Update the direction based tags as appropriate then return an updated node
36607         return node.update({tags: lodash.transform(node.tags, function(acc, tagValue, tagKey) {
36608             // See if this is a direction tag and reverse (or use existing value if not recognised)
36609             if (tagKey === 'direction') {
36610                 acc[tagKey] = {forward: 'backward', backward: 'forward', left: 'right', right: 'left'}[tagValue] || tagValue;
36611             } else {
36612                 // Use the reverseKey method to cater for situations such as traffic_sign:forward=stop
36613                 // This will pass through other tags unchanged
36614                 acc[reverseKey(tagKey)] = tagValue;
36615             }
36616             return acc;
36617         }, {})});
36618     }
36619
36620
36621     function reverseTagsOnNodes(graph, nodeIds) {
36622         // Reverse the direction of appropriate tags attached to the nodes (#3076)
36623         return lodash(nodeIds)
36624             // Get each node from the graph
36625             .map(function(nodeId) { return graph.entity(nodeId);})
36626             // Check tags on the node, if there aren't any, we can skip
36627             .filter(function(existingNode) { return existingNode.tags !== undefined;})
36628             // Get a new version of each node with the appropriate tags reversed
36629             .map(function(existingNode) { return reverseDirectionTags(existingNode);})
36630             // Chain together consecutive updates to the graph for each updated node and return
36631             .reduce(function (accGraph, value) { return accGraph.replace(value); }, graph);
36632     }
36633
36634
36635     return function(graph) {
36636         var way = graph.entity(wayId),
36637             nodes = way.nodes.slice().reverse(),
36638             tags = {}, key, role;
36639
36640         for (key in way.tags) {
36641             tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
36642         }
36643
36644         graph.parentRelations(way).forEach(function(relation) {
36645             relation.members.forEach(function(member, index) {
36646                 if (member.id === way.id && (role = roleReversals[member.role])) {
36647                     relation = relation.updateMember({role: role}, index);
36648                     graph = graph.replace(relation);
36649                 }
36650             });
36651         });
36652
36653         // Reverse any associated directions on nodes on the way and then replace
36654         // the way itself with the reversed node ids and updated way tags
36655         return reverseTagsOnNodes(graph, nodes).replace(way.update({nodes: nodes, tags: tags}));
36656     };
36657 }
36658
36659 // For fixing up rendering of multipolygons with tags on the outer member.
36660 // https://github.com/openstreetmap/iD/issues/613
36661 function osmIsSimpleMultipolygonOuterMember(entity, graph) {
36662     if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0)
36663         return false;
36664
36665     var parents = graph.parentRelations(entity);
36666     if (parents.length !== 1)
36667         return false;
36668
36669     var parent = parents[0];
36670     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36671         return false;
36672
36673     var members = parent.members, member;
36674     for (var i = 0; i < members.length; i++) {
36675         member = members[i];
36676         if (member.id === entity.id && member.role && member.role !== 'outer')
36677             return false; // Not outer member
36678         if (member.id !== entity.id && (!member.role || member.role === 'outer'))
36679             return false; // Not a simple multipolygon
36680     }
36681
36682     return parent;
36683 }
36684
36685
36686 function osmSimpleMultipolygonOuterMember(entity, graph) {
36687     if (entity.type !== 'way')
36688         return false;
36689
36690     var parents = graph.parentRelations(entity);
36691     if (parents.length !== 1)
36692         return false;
36693
36694     var parent = parents[0];
36695     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36696         return false;
36697
36698     var members = parent.members, member, outerMember;
36699     for (var i = 0; i < members.length; i++) {
36700         member = members[i];
36701         if (!member.role || member.role === 'outer') {
36702             if (outerMember)
36703                 return false; // Not a simple multipolygon
36704             outerMember = member;
36705         }
36706     }
36707
36708     if (!outerMember)
36709         return false;
36710
36711     var outerEntity = graph.hasEntity(outerMember.id);
36712     if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length)
36713         return false;
36714
36715     return outerEntity;
36716 }
36717
36718
36719 // Join `array` into sequences of connecting ways.
36720 //
36721 // Segments which share identical start/end nodes will, as much as possible,
36722 // be connected with each other.
36723 //
36724 // The return value is a nested array. Each constituent array contains elements
36725 // of `array` which have been determined to connect. Each consitituent array
36726 // also has a `nodes` property whose value is an ordered array of member nodes,
36727 // with appropriate order reversal and start/end coordinate de-duplication.
36728 //
36729 // Members of `array` must have, at minimum, `type` and `id` properties.
36730 // Thus either an array of `osmWay`s or a relation member array may be
36731 // used.
36732 //
36733 // If an member has a `tags` property, its tags will be reversed via
36734 // `actionReverse` in the output.
36735 //
36736 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
36737 // false) and non-way members are ignored.
36738 //
36739 function osmJoinWays(array, graph) {
36740     var joined = [], member, current, nodes, first, last, i, how, what;
36741
36742     array = array.filter(function(member) {
36743         return member.type === 'way' && graph.hasEntity(member.id);
36744     });
36745
36746     function resolve(member) {
36747         return graph.childNodes(graph.entity(member.id));
36748     }
36749
36750     function reverse(member) {
36751         return member.tags ? actionReverse(member.id, { reverseOneway: true })(graph).entity(member.id) : member;
36752     }
36753
36754     while (array.length) {
36755         member = array.shift();
36756         current = [member];
36757         current.nodes = nodes = resolve(member).slice();
36758         joined.push(current);
36759
36760         while (array.length && lodash.first(nodes) !== lodash.last(nodes)) {
36761             first = lodash.first(nodes);
36762             last  = lodash.last(nodes);
36763
36764             for (i = 0; i < array.length; i++) {
36765                 member = array[i];
36766                 what = resolve(member);
36767
36768                 if (last === lodash.first(what)) {
36769                     how  = nodes.push;
36770                     what = what.slice(1);
36771                     break;
36772                 } else if (last === lodash.last(what)) {
36773                     how  = nodes.push;
36774                     what = what.slice(0, -1).reverse();
36775                     member = reverse(member);
36776                     break;
36777                 } else if (first === lodash.last(what)) {
36778                     how  = nodes.unshift;
36779                     what = what.slice(0, -1);
36780                     break;
36781                 } else if (first === lodash.first(what)) {
36782                     how  = nodes.unshift;
36783                     what = what.slice(1).reverse();
36784                     member = reverse(member);
36785                     break;
36786                 } else {
36787                     what = how = null;
36788                 }
36789             }
36790
36791             if (!what)
36792                 break; // No more joinable ways.
36793
36794             how.apply(current, [member]);
36795             how.apply(nodes, what);
36796
36797             array.splice(i, 1);
36798         }
36799     }
36800
36801     return joined;
36802 }
36803
36804 function osmRelation() {
36805     if (!(this instanceof osmRelation)) {
36806         return (new osmRelation()).initialize(arguments);
36807     } else if (arguments.length) {
36808         this.initialize(arguments);
36809     }
36810 }
36811
36812
36813 osmEntity$$1.relation = osmRelation;
36814
36815 osmRelation.prototype = Object.create(osmEntity$$1.prototype);
36816
36817
36818 osmRelation.creationOrder = function(a, b) {
36819     var aId = parseInt(osmEntity$$1.id.toOSM(a.id), 10);
36820     var bId = parseInt(osmEntity$$1.id.toOSM(b.id), 10);
36821
36822     if (aId < 0 || bId < 0) return aId - bId;
36823     return bId - aId;
36824 };
36825
36826
36827 lodash.extend(osmRelation.prototype, {
36828     type: 'relation',
36829     members: [],
36830
36831
36832     copy: function(resolver, copies) {
36833         if (copies[this.id])
36834             return copies[this.id];
36835
36836         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
36837
36838         var members = this.members.map(function(member) {
36839             return lodash.extend({}, member, { id: resolver.entity(member.id).copy(resolver, copies).id });
36840         });
36841
36842         copy = copy.update({members: members});
36843         copies[this.id] = copy;
36844
36845         return copy;
36846     },
36847
36848
36849     extent: function(resolver, memo) {
36850         return resolver.transient(this, 'extent', function() {
36851             if (memo && memo[this.id]) return geoExtent$$1();
36852             memo = memo || {};
36853             memo[this.id] = true;
36854
36855             var extent$$1 = geoExtent$$1();
36856             for (var i = 0; i < this.members.length; i++) {
36857                 var member = resolver.hasEntity(this.members[i].id);
36858                 if (member) {
36859                     extent$$1._extend(member.extent(resolver, memo));
36860                 }
36861             }
36862             return extent$$1;
36863         });
36864     },
36865
36866
36867     geometry: function(graph) {
36868         return graph.transient(this, 'geometry', function() {
36869             return this.isMultipolygon() ? 'area' : 'relation';
36870         });
36871     },
36872
36873
36874     isDegenerate: function() {
36875         return this.members.length === 0;
36876     },
36877
36878
36879     // Return an array of members, each extended with an 'index' property whose value
36880     // is the member index.
36881     indexedMembers: function() {
36882         var result = new Array(this.members.length);
36883         for (var i = 0; i < this.members.length; i++) {
36884             result[i] = lodash.extend({}, this.members[i], {index: i});
36885         }
36886         return result;
36887     },
36888
36889
36890     // Return the first member with the given role. A copy of the member object
36891     // is returned, extended with an 'index' property whose value is the member index.
36892     memberByRole: function(role) {
36893         for (var i = 0; i < this.members.length; i++) {
36894             if (this.members[i].role === role) {
36895                 return lodash.extend({}, this.members[i], {index: i});
36896             }
36897         }
36898     },
36899
36900
36901     // Return the first member with the given id. A copy of the member object
36902     // is returned, extended with an 'index' property whose value is the member index.
36903     memberById: function(id) {
36904         for (var i = 0; i < this.members.length; i++) {
36905             if (this.members[i].id === id) {
36906                 return lodash.extend({}, this.members[i], {index: i});
36907             }
36908         }
36909     },
36910
36911
36912     // Return the first member with the given id and role. A copy of the member object
36913     // is returned, extended with an 'index' property whose value is the member index.
36914     memberByIdAndRole: function(id, role) {
36915         for (var i = 0; i < this.members.length; i++) {
36916             if (this.members[i].id === id && this.members[i].role === role) {
36917                 return lodash.extend({}, this.members[i], {index: i});
36918             }
36919         }
36920     },
36921
36922
36923     addMember: function(member, index) {
36924         var members = this.members.slice();
36925         members.splice(index === undefined ? members.length : index, 0, member);
36926         return this.update({members: members});
36927     },
36928
36929
36930     updateMember: function(member, index) {
36931         var members = this.members.slice();
36932         members.splice(index, 1, lodash.extend({}, members[index], member));
36933         return this.update({members: members});
36934     },
36935
36936
36937     removeMember: function(index) {
36938         var members = this.members.slice();
36939         members.splice(index, 1);
36940         return this.update({members: members});
36941     },
36942
36943
36944     removeMembersWithID: function(id) {
36945         var members = lodash.reject(this.members, function(m) { return m.id === id; });
36946         return this.update({members: members});
36947     },
36948
36949
36950     // Wherever a member appears with id `needle.id`, replace it with a member
36951     // with id `replacement.id`, type `replacement.type`, and the original role,
36952     // unless a member already exists with that id and role. Return an updated
36953     // relation.
36954     replaceMember: function(needle, replacement) {
36955         if (!this.memberById(needle.id))
36956             return this;
36957
36958         var members = [];
36959
36960         for (var i = 0; i < this.members.length; i++) {
36961             var member = this.members[i];
36962             if (member.id !== needle.id) {
36963                 members.push(member);
36964             } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
36965                 members.push({id: replacement.id, type: replacement.type, role: member.role});
36966             }
36967         }
36968
36969         return this.update({members: members});
36970     },
36971
36972
36973     asJXON: function(changeset_id) {
36974         var r = {
36975             relation: {
36976                 '@id': this.osmId(),
36977                 '@version': this.version || 0,
36978                 member: lodash.map(this.members, function(member) {
36979                     return {
36980                         keyAttributes: {
36981                             type: member.type,
36982                             role: member.role,
36983                             ref: osmEntity$$1.id.toOSM(member.id)
36984                         }
36985                     };
36986                 }),
36987                 tag: lodash.map(this.tags, function(v, k) {
36988                     return { keyAttributes: { k: k, v: v } };
36989                 })
36990             }
36991         };
36992         if (changeset_id) r.relation['@changeset'] = changeset_id;
36993         return r;
36994     },
36995
36996
36997     asGeoJSON: function(resolver) {
36998         return resolver.transient(this, 'GeoJSON', function () {
36999             if (this.isMultipolygon()) {
37000                 return {
37001                     type: 'MultiPolygon',
37002                     coordinates: this.multipolygon(resolver)
37003                 };
37004             } else {
37005                 return {
37006                     type: 'FeatureCollection',
37007                     properties: this.tags,
37008                     features: this.members.map(function (member) {
37009                         return lodash.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
37010                     })
37011                 };
37012             }
37013         });
37014     },
37015
37016
37017     area: function(resolver) {
37018         return resolver.transient(this, 'area', function() {
37019             return area(this.asGeoJSON(resolver));
37020         });
37021     },
37022
37023
37024     isMultipolygon: function() {
37025         return this.tags.type === 'multipolygon';
37026     },
37027
37028
37029     isComplete: function(resolver) {
37030         for (var i = 0; i < this.members.length; i++) {
37031             if (!resolver.hasEntity(this.members[i].id)) {
37032                 return false;
37033             }
37034         }
37035         return true;
37036     },
37037
37038
37039     isRestriction: function() {
37040         return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
37041     },
37042
37043
37044     // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
37045     // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
37046     //
37047     // This corresponds to the structure needed for rendering a multipolygon path using a
37048     // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
37049     //
37050     // In the case of invalid geometries, this function will still return a result which
37051     // includes the nodes of all way members, but some Nds may be unclosed and some inner
37052     // rings not matched with the intended outer ring.
37053     //
37054     multipolygon: function(resolver) {
37055         var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
37056             inners = this.members.filter(function(m) { return 'inner' === m.role; });
37057
37058         outers = osmJoinWays(outers, resolver);
37059         inners = osmJoinWays(inners, resolver);
37060
37061         outers = outers.map(function(outer) { return lodash.map(outer.nodes, 'loc'); });
37062         inners = inners.map(function(inner) { return lodash.map(inner.nodes, 'loc'); });
37063
37064         var result = outers.map(function(o) {
37065             // Heuristic for detecting counterclockwise winding order. Assumes
37066             // that OpenStreetMap polygons are not hemisphere-spanning.
37067             return [area({ type: 'Polygon', coordinates: [o] }) > 2 * Math.PI ? o.reverse() : o];
37068         });
37069
37070         function findOuter(inner) {
37071             var o, outer;
37072
37073             for (o = 0; o < outers.length; o++) {
37074                 outer = outers[o];
37075                 if (geoPolygonContainsPolygon(outer, inner))
37076                     return o;
37077             }
37078
37079             for (o = 0; o < outers.length; o++) {
37080                 outer = outers[o];
37081                 if (geoPolygonIntersectsPolygon(outer, inner, false))
37082                     return o;
37083             }
37084         }
37085
37086         for (var i = 0; i < inners.length; i++) {
37087             var inner = inners[i];
37088
37089             if (area({ type: 'Polygon', coordinates: [inner] }) < 2 * Math.PI) {
37090                 inner = inner.reverse();
37091             }
37092
37093             var o = findOuter(inners[i]);
37094             if (o !== undefined)
37095                 result[o].push(inners[i]);
37096             else
37097                 result.push([inners[i]]); // Invalid geometry
37098         }
37099
37100         return result;
37101     }
37102 });
37103
37104 function osmLanes(entity) {
37105     if (entity.type !== 'way') return null;
37106     if (!entity.tags.highway) return null;
37107
37108     var tags = entity.tags;
37109     var isOneWay = entity.isOneWay();
37110     var laneCount = getLaneCount(tags, isOneWay);
37111     var maxspeed = parseMaxspeed(tags);
37112
37113     var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
37114     var forward = laneDirections.forward;
37115     var backward = laneDirections.backward;
37116     var bothways = laneDirections.bothways;
37117
37118     // parse the piped string 'x|y|z' format
37119     var turnLanes = {};
37120     turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
37121     turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
37122     turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
37123
37124     var maxspeedLanes = {};
37125     maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
37126     maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
37127     maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
37128
37129     var psvLanes = {};
37130     psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
37131     psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
37132     psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
37133
37134     var busLanes = {};
37135     busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
37136     busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
37137     busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
37138
37139     var taxiLanes = {};
37140     taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
37141     taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
37142     taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
37143
37144     var hovLanes = {};
37145     hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
37146     hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
37147     hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
37148
37149     var hgvLanes = {};
37150     hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
37151     hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
37152     hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
37153
37154     var bicyclewayLanes = {};
37155     bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
37156     bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
37157     bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
37158
37159     var lanesObj = {
37160         forward: [],
37161         backward: [],
37162         unspecified: []
37163     };
37164
37165     // map forward/backward/unspecified of each lane type to lanesObj
37166     mapToLanesObj(lanesObj, turnLanes, 'turnLane');
37167     mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
37168     mapToLanesObj(lanesObj, psvLanes, 'psv');
37169     mapToLanesObj(lanesObj, busLanes, 'bus');
37170     mapToLanesObj(lanesObj, taxiLanes, 'taxi');
37171     mapToLanesObj(lanesObj, hovLanes, 'hov');
37172     mapToLanesObj(lanesObj, hgvLanes, 'hgv');
37173     mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
37174
37175     return {
37176         metadata: {
37177             count: laneCount,
37178             oneway: isOneWay,
37179             forward: forward,
37180             backward: backward,
37181             bothways: bothways,
37182             turnLanes: turnLanes,
37183             maxspeed: maxspeed,
37184             maxspeedLanes: maxspeedLanes,
37185             psvLanes: psvLanes,
37186             busLanes: busLanes,
37187             taxiLanes: taxiLanes,
37188             hovLanes: hovLanes,
37189             hgvLanes: hgvLanes,
37190             bicyclewayLanes: bicyclewayLanes
37191         },
37192         lanes: lanesObj
37193     };
37194 }
37195
37196
37197 function getLaneCount(tags, isOneWay) {
37198     var count;
37199     if (tags.lanes) {
37200         count = parseInt(tags.lanes, 10);
37201         if (count > 0) {
37202             return count;
37203         }
37204     }
37205
37206
37207     switch (tags.highway) {
37208         case 'trunk':
37209         case 'motorway':
37210             count = isOneWay ? 2 : 4;
37211             break;
37212         default:
37213             count = isOneWay ? 1 : 2;
37214             break;
37215     }
37216
37217     return count;
37218 }
37219
37220
37221 function parseMaxspeed(tags) {
37222     var maxspeed = tags.maxspeed;
37223     if (lodash.isNumber(maxspeed)) return maxspeed;
37224     if (lodash.isString(maxspeed)) {
37225         maxspeed = maxspeed.match(/^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/g);
37226         if (!maxspeed) return;
37227         return parseInt(maxspeed, 10);
37228     }
37229 }
37230
37231
37232 function parseLaneDirections(tags, isOneWay, laneCount) {
37233     var forward = parseInt(tags['lanes:forward'], 10);
37234     var backward = parseInt(tags['lanes:backward'], 10);
37235     var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
37236
37237     if (parseInt(tags.oneway, 10) === -1) {
37238         forward = 0;
37239         bothways = 0;
37240         backward = laneCount;
37241     }
37242     else if (isOneWay) {
37243         forward = laneCount;
37244         bothways = 0;
37245         backward = 0;
37246     }
37247     else if (lodash.isNaN(forward) && lodash.isNaN(backward)) {
37248         backward = Math.floor((laneCount - bothways) / 2);
37249         forward = laneCount - bothways - backward;
37250     }
37251     else if (lodash.isNaN(forward)) {
37252         if (backward > laneCount - bothways) {
37253             backward = laneCount - bothways;
37254         }
37255         forward = laneCount - bothways - backward;
37256     }
37257     else if (lodash.isNaN(backward)) {
37258         if (forward > laneCount - bothways) {
37259             forward = laneCount - bothways;
37260         }
37261         backward = laneCount - bothways - forward;
37262     }
37263     return {
37264         forward: forward,
37265         backward: backward,
37266         bothways: bothways
37267     };
37268 }
37269
37270
37271 function parseTurnLanes(tag){
37272     if (!tag) return;
37273
37274     var validValues = [
37275         'left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right',
37276         'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'
37277     ];
37278
37279     return tag.split('|')
37280         .map(function (s) {
37281             if (s === '') s = 'none';
37282             return s.split(';')
37283                 .map(function (d) {
37284                     return validValues.indexOf(d) === -1 ? 'unknown': d;
37285                 });
37286         });
37287 }
37288
37289
37290 function parseMaxspeedLanes(tag, maxspeed) {
37291     if (!tag) return;
37292
37293     return tag.split('|')
37294         .map(function (s) {
37295             if (s === 'none') return s;
37296             var m = parseInt(s, 10);
37297             if (s === '' || m === maxspeed) return null;
37298             return lodash.isNaN(m) ? 'unknown': m;
37299         });
37300 }
37301
37302
37303 function parseMiscLanes(tag) {
37304     if (!tag) return;
37305
37306     var validValues = [
37307         'yes', 'no', 'designated'
37308     ];
37309
37310     return tag.split('|')
37311         .map(function (s) {
37312             if (s === '') s = 'no';
37313             return validValues.indexOf(s) === -1 ? 'unknown': s;
37314         });
37315 }
37316
37317
37318 function parseBicycleWay(tag) {
37319     if (!tag) return;
37320
37321     var validValues = [
37322         'yes', 'no', 'designated', 'lane'
37323     ];
37324
37325     return tag.split('|')
37326         .map(function (s) {
37327             if (s === '') s = 'no';
37328             return validValues.indexOf(s) === -1 ? 'unknown': s;
37329         });
37330 }
37331
37332
37333 function mapToLanesObj(lanesObj, data, key) {
37334     if (data.forward) data.forward.forEach(function(l, i) {
37335         if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
37336         lanesObj.forward[i][key] = l;
37337     });
37338     if (data.backward) data.backward.forEach(function(l, i) {
37339         if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
37340         lanesObj.backward[i][key] = l;
37341     });
37342     if (data.unspecified) data.unspecified.forEach(function(l, i) {
37343         if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
37344         lanesObj.unspecified[i][key] = l;
37345     });
37346 }
37347
37348 var translations = Object.create(null);
37349
37350 var currentLocale = 'en';
37351 var textDirection = 'ltr';
37352
37353 function setLocale(_) {
37354     if (translations[_] !== undefined) {
37355         currentLocale = _;
37356     } else if (translations[_.split('-')[0]]) {
37357         currentLocale = _.split('-')[0];
37358     }
37359 }
37360
37361 function addTranslation(id, value) {
37362     translations[id] = value;
37363 }
37364
37365 /**
37366  * Given a string identifier, try to find that string in the current
37367  * language, and return it.
37368  *
37369  * @param {string} s string identifier
37370  * @returns {string?} locale string
37371  */
37372 function t(s, o, loc) {
37373     loc = loc || currentLocale;
37374
37375     var path = s
37376         .split('.')
37377         .map(function(s) { return s.replace('<TX_DOT>', '.'); })
37378         .reverse();
37379
37380     var rep = translations[loc];
37381
37382     while (rep !== undefined && path.length) rep = rep[path.pop()];
37383
37384     if (rep !== undefined) {
37385         if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
37386         return rep;
37387     }
37388
37389     if (loc !== 'en') {
37390         return t(s, o, 'en');
37391     }
37392
37393     if (o && 'default' in o) {
37394         return o.default;
37395     }
37396
37397     var missing = 'Missing ' + loc + ' translation: ' + s;
37398     if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
37399
37400     return missing;
37401 }
37402
37403 /**
37404  * Given string 'ltr' or 'rtl', save that setting
37405  *
37406  * @param {string} s ltr or rtl
37407  */
37408
37409 function setTextDirection(dir) {
37410     textDirection = dir;
37411 }
37412
37413 var detected;
37414
37415 function utilDetect(force) {
37416     if (detected && !force) return detected;
37417     detected = {};
37418
37419     var ua = navigator.userAgent,
37420         m = null;
37421
37422     m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i);   // Edge
37423     if (m !== null) {
37424         detected.browser = m[1];
37425         detected.version = m[2];
37426     }
37427     if (!detected.browser) {
37428         m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i);   // IE11
37429         if (m !== null) {
37430             detected.browser = 'msie';
37431             detected.version = m[1];
37432         }
37433     }
37434     if (!detected.browser) {
37435         m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);   // Opera 15+
37436         if (m !== null) {
37437             detected.browser = 'Opera';
37438             detected.version = m[2];
37439         }
37440     }
37441     if (!detected.browser) {
37442         m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
37443         if (m !== null) {
37444             detected.browser = m[1];
37445             detected.version = m[2];
37446             m = ua.match(/version\/([\.\d]+)/i);
37447             if (m !== null) detected.version = m[1];
37448         }
37449     }
37450     if (!detected.browser) {
37451         detected.browser = navigator.appName;
37452         detected.version = navigator.appVersion;
37453     }
37454
37455     // keep major.minor version only..
37456     detected.version = detected.version.split(/\W/).slice(0,2).join('.');
37457
37458     if (detected.browser.toLowerCase() === 'msie') {
37459         detected.ie = true;
37460         detected.browser = 'Internet Explorer';
37461         detected.support = parseFloat(detected.version) >= 11;
37462     } else {
37463         detected.ie = false;
37464         detected.support = true;
37465     }
37466
37467     // Added due to incomplete svg style support. See #715
37468     detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
37469
37470     detected.locale = (navigator.language || navigator.userLanguage || 'en-US');
37471     detected.language = detected.locale.split('-')[0];
37472
37473     // Search `navigator.languages` for a better locale.. Prefer the first language,
37474     // unless the second language is a culture-specific version of the first one, see #3842
37475     if (navigator.languages && navigator.languages.length > 0) {
37476         var code0 = navigator.languages[0],
37477             parts0 = code0.split('-');
37478
37479         detected.locale = code0;
37480         detected.language = parts0[0];
37481
37482         if (navigator.languages.length > 1 && parts0.length === 1) {
37483             var code1 = navigator.languages[1],
37484                 parts1 = code1.split('-');
37485
37486             if (parts1[0] === parts0[0]) {
37487                 detected.locale = code1;
37488             }
37489         }
37490     }
37491
37492     // Loaded locale is stored in currentLocale
37493     // return that instead (except in the situation where 'en' might override 'en-US')
37494     var loadedLocale = currentLocale || 'en';
37495     if (loadedLocale !== 'en') {
37496         detected.locale = loadedLocale;
37497         detected.language = detected.locale.split('-')[0];
37498     }
37499
37500     // detect text direction
37501     var q = utilStringQs(window.location.hash.substring(1));
37502     var lang = dataLocales[detected.locale];
37503     if ((lang && lang.rtl) || q.hasOwnProperty('rtl')) {
37504         detected.textDirection = 'rtl';
37505     } else {
37506         detected.textDirection = 'ltr';
37507     }
37508     setTextDirection(detected.textDirection);
37509
37510     // detect host
37511     var loc = window.top.location;
37512     var origin = loc.origin;
37513     if (!origin) {  // for unpatched IE11
37514         origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port: '');
37515     }
37516
37517     detected.host = origin + loc.pathname;
37518
37519     detected.filedrop = (window.FileReader && 'ondrop' in window);
37520
37521     function nav(x) {
37522         return navigator.userAgent.indexOf(x) !== -1;
37523     }
37524
37525     if (nav('Win')) {
37526         detected.os = 'win';
37527         detected.platform = 'Windows';
37528     }
37529     else if (nav('Mac')) {
37530         detected.os = 'mac';
37531         detected.platform = 'Macintosh';
37532     }
37533     else if (nav('X11') || nav('Linux')) {
37534         detected.os = 'linux';
37535         detected.platform = 'Linux';
37536     }
37537     else {
37538         detected.os = 'win';
37539         detected.platform = 'Unknown';
37540     }
37541
37542     return detected;
37543 }
37544
37545 var remove$1 = removeDiacritics;
37546
37547 var replacementList = [
37548   {
37549     base: ' ',
37550     chars: "\u00A0",
37551   }, {
37552     base: '0',
37553     chars: "\u07C0",
37554   }, {
37555     base: 'A',
37556     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",
37557   }, {
37558     base: 'AA',
37559     chars: "\uA732",
37560   }, {
37561     base: 'AE',
37562     chars: "\u00C6\u01FC\u01E2",
37563   }, {
37564     base: 'AO',
37565     chars: "\uA734",
37566   }, {
37567     base: 'AU',
37568     chars: "\uA736",
37569   }, {
37570     base: 'AV',
37571     chars: "\uA738\uA73A",
37572   }, {
37573     base: 'AY',
37574     chars: "\uA73C",
37575   }, {
37576     base: 'B',
37577     chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181",
37578   }, {
37579     base: 'C',
37580     chars: "\u24b8\uff23\uA73E\u1E08\u0106\u0043\u0108\u010A\u010C\u00C7\u0187\u023B",
37581   }, {
37582     base: 'D',
37583     chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779",
37584   }, {
37585     base: 'Dh',
37586     chars: "\u00D0",
37587   }, {
37588     base: 'DZ',
37589     chars: "\u01F1\u01C4",
37590   }, {
37591     base: 'Dz',
37592     chars: "\u01F2\u01C5",
37593   }, {
37594     base: 'E',
37595     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",
37596   }, {
37597     base: 'F',
37598     chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B",
37599   }, {
37600     base: 'G',
37601     chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262",
37602   }, {
37603     base: 'H',
37604     chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D",
37605   }, {
37606     base: 'I',
37607     chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197",
37608   }, {
37609     base: 'J',
37610     chars: "\u24BF\uFF2A\u0134\u0248\u0237",
37611   }, {
37612     base: 'K',
37613     chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2",
37614   }, {
37615     base: 'L',
37616     chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780",
37617   }, {
37618     base: 'LJ',
37619     chars: "\u01C7",
37620   }, {
37621     base: 'Lj',
37622     chars: "\u01C8",
37623   }, {
37624     base: 'M',
37625     chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB",
37626   }, {
37627     base: 'N',
37628     chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E",
37629   }, {
37630     base: 'NJ',
37631     chars: "\u01CA",
37632   }, {
37633     base: 'Nj',
37634     chars: "\u01CB",
37635   }, {
37636     base: 'O',
37637     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",
37638   }, {
37639     base: 'OE',
37640     chars: "\u0152",
37641   }, {
37642     base: 'OI',
37643     chars: "\u01A2",
37644   }, {
37645     base: 'OO',
37646     chars: "\uA74E",
37647   }, {
37648     base: 'OU',
37649     chars: "\u0222",
37650   }, {
37651     base: 'P',
37652     chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754",
37653   }, {
37654     base: 'Q',
37655     chars: "\u24C6\uFF31\uA756\uA758\u024A",
37656   }, {
37657     base: 'R',
37658     chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782",
37659   }, {
37660     base: 'S',
37661     chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784",
37662   }, {
37663     base: 'T',
37664     chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786",
37665   }, {
37666     base: 'Th',
37667     chars: "\u00DE",
37668   }, {
37669     base: 'TZ',
37670     chars: "\uA728",
37671   }, {
37672     base: 'U',
37673     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",
37674   }, {
37675     base: 'V',
37676     chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245",
37677   }, {
37678     base: 'VY',
37679     chars: "\uA760",
37680   }, {
37681     base: 'W',
37682     chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72",
37683   }, {
37684     base: 'X',
37685     chars: "\u24CD\uFF38\u1E8A\u1E8C",
37686   }, {
37687     base: 'Y',
37688     chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE",
37689   }, {
37690     base: 'Z',
37691     chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762",
37692   }, {
37693     base: 'a',
37694     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",
37695   }, {
37696     base: 'aa',
37697     chars: "\uA733",
37698   }, {
37699     base: 'ae',
37700     chars: "\u00E6\u01FD\u01E3",
37701   }, {
37702     base: 'ao',
37703     chars: "\uA735",
37704   }, {
37705     base: 'au',
37706     chars: "\uA737",
37707   }, {
37708     base: 'av',
37709     chars: "\uA739\uA73B",
37710   }, {
37711     base: 'ay',
37712     chars: "\uA73D",
37713   }, {
37714     base: 'b',
37715     chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182",
37716   }, {
37717     base: 'c',
37718     chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184",
37719   }, {
37720     base: 'd',
37721     chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA",
37722   }, {
37723     base: 'dh',
37724     chars: "\u00F0",
37725   }, {
37726     base: 'dz',
37727     chars: "\u01F3\u01C6",
37728   }, {
37729     base: 'e',
37730     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",
37731   }, {
37732     base: 'f',
37733     chars: "\u24D5\uFF46\u1E1F\u0192",
37734   }, {
37735     base: 'ff',
37736     chars: "\uFB00",
37737   }, {
37738     base: 'fi',
37739     chars: "\uFB01",
37740   }, {
37741     base: 'fl',
37742     chars: "\uFB02",
37743   }, {
37744     base: 'ffi',
37745     chars: "\uFB03",
37746   }, {
37747     base: 'ffl',
37748     chars: "\uFB04",
37749   }, {
37750     base: 'g',
37751     chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79",
37752   }, {
37753     base: 'h',
37754     chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265",
37755   }, {
37756     base: 'hv',
37757     chars: "\u0195",
37758   }, {
37759     base: 'i',
37760     chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131",
37761   }, {
37762     base: 'j',
37763     chars: "\u24D9\uFF4A\u0135\u01F0\u0249",
37764   }, {
37765     base: 'k',
37766     chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3",
37767   }, {
37768     base: 'l',
37769     chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D",
37770   }, {
37771     base: 'lj',
37772     chars: "\u01C9",
37773   }, {
37774     base: 'm',
37775     chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F",
37776   }, {
37777     base: 'n',
37778     chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509",
37779   }, {
37780     base: 'nj',
37781     chars: "\u01CC",
37782   }, {
37783     base: 'o',
37784     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",
37785   }, {
37786     base: 'oe',
37787     chars: "\u0153",
37788   }, {
37789     base: 'oi',
37790     chars: "\u01A3",
37791   }, {
37792     base: 'oo',
37793     chars: "\uA74F",
37794   }, {
37795     base: 'ou',
37796     chars: "\u0223",
37797   }, {
37798     base: 'p',
37799     chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1",
37800   }, {
37801     base: 'q',
37802     chars: "\u24E0\uFF51\u024B\uA757\uA759",
37803   }, {
37804     base: 'r',
37805     chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783",
37806   }, {
37807     base: 's',
37808     chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282",
37809   }, {
37810     base: 'ss',
37811     chars: "\xDF",
37812   }, {
37813     base: 't',
37814     chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787",
37815   }, {
37816     base: 'th',
37817     chars: "\u00FE",
37818   }, {
37819     base: 'tz',
37820     chars: "\uA729",
37821   }, {
37822     base: 'u',
37823     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",
37824   }, {
37825     base: 'v',
37826     chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C",
37827   }, {
37828     base: 'vy',
37829     chars: "\uA761",
37830   }, {
37831     base: 'w',
37832     chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73",
37833   }, {
37834     base: 'x',
37835     chars: "\u24E7\uFF58\u1E8B\u1E8D",
37836   }, {
37837     base: 'y',
37838     chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF",
37839   }, {
37840     base: 'z',
37841     chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763",
37842   }
37843 ];
37844
37845 var diacriticsMap = {};
37846 for (var i = 0; i < replacementList.length; i += 1) {
37847   var chars = replacementList[i].chars;
37848   for (var j = 0; j < chars.length; j += 1) {
37849     diacriticsMap[chars[j]] = replacementList[i].base;
37850   }
37851 }
37852
37853 function removeDiacritics(str) {
37854   return str.replace(/[^\u0000-\u007e]/g, function(c) {
37855     return diacriticsMap[c] || c;
37856   });
37857 }
37858
37859 // see https://github.com/openstreetmap/iD/pull/3707
37860 // https://gist.github.com/mapmeld/556b09ddec07a2044c76e1ef45f01c60
37861
37862 var chars$1 = {
37863     // madda above alef
37864     1570: { initial: 'آ‎', isolated: 'ﺁ', medial: 'ﺁ', final: 'ﺂ' },
37865
37866     // hamza above and below alef
37867     1571: { initial: 'أ', isolated: 'ﺃ', medial: '', final: 'ﺄ' },
37868     // 1572 is ؤ
37869     1573: { initial: 'إ', isolated: 'ﺇ', medial: '', final: 'ﺈ' },
37870     // 1574 is ئ
37871     1575: { initial: 'ا', isolated: 'ا', medial: '', final: 'ﺎ' },
37872     1576: { initial: 'ﺑ', isolated: 'ﺏ', medial: 'ﺒ', final: 'ﺐ' },
37873
37874     // 1577 ة
37875     1577: { initial: '', isolated: 'ة', medial: '', final: 'ﺔ' },
37876
37877     1578: { initial: 'ﺗ', isolated: 'ﺕ', medial: 'ﺘ', final: 'ﺖ' },
37878     1579: { initial: 'ﺛ', isolated: 'ﺙ', medial: 'ﺜ', final: 'ﺚ' },
37879     1580: { initial: 'ﺟ', isolated: 'ﺝ', medial: 'ﺠ', final: 'ﺞ' },
37880     1581: { initial: 'ﺣ', isolated: 'ﺡ', medial: 'ﺤ', final: 'ﺢ' },
37881     1582: { initial: 'ﺧ', isolated: 'ﺥ', medial: 'ﺨ', final: 'ﺦ' },
37882     1583: { initial: 'ﺩ', isolated: 'ﺩ', medial: '', final: 'ﺪ' },
37883     1584: { initial: 'ﺫ', isolated: 'ﺫ', medial: '', final: 'ﺬ' },
37884     1585: { initial: 'ﺭ', isolated: 'ﺭ', medial: '', final: 'ﺮ' },
37885     1586: { initial: 'ﺯ', isolated: 'ﺯ', medial: '', final: 'ﺰ' },
37886     1688: { initial: 'ﮊ', isolated: 'ﮊ', medial: '', final: 'ﮋ' },
37887     1587: { initial: 'ﺳ', isolated: 'ﺱ', medial: 'ﺴ', final: 'ﺲ' },
37888     1588: { initial: 'ﺷ', isolated: 'ﺵ', medial: 'ﺸ', final: 'ﺶ' },
37889     1589: { initial: 'ﺻ', isolated: 'ﺹ', medial: 'ﺼ', final: 'ﺺ' },
37890     1590: { initial: 'ﺿ', isolated: 'ﺽ', medial: 'ﻀ', final: 'ﺾ' },
37891     1591: { initial: 'ﻃ', isolated: 'ﻁ', medial: 'ﻄ', final: 'ﻂ' },
37892     1592: { initial: 'ﻇ', isolated: 'ﻅ', medial: 'ﻈ', final: 'ﻆ' },
37893     1593: { initial: 'ﻋ', isolated: 'ﻉ', medial: 'ﻌ', final: 'ﻊ' },
37894     1594: { initial: 'ﻏ', isolated: 'ﻍ', medial: 'ﻐ', final: 'ﻎ' },
37895
37896     // 1595 ػ - may be very rare
37897
37898     1601: { initial: 'ﻓ', isolated: 'ﻑ', medial: 'ﻔ', final: 'ﻒ' },
37899     1602: { initial: 'ﻗ', isolated: 'ﻕ', medial: 'ﻘ', final: 'ﻖ' },
37900     1604: { initial: 'ﻟ', isolated: 'ﻝ', medial: 'ﻠ', final: 'ﻞ' },
37901     1605: { initial: 'ﻣ', isolated: 'ﻡ', medial: 'ﻤ', final: 'ﻢ' },
37902     1606: { initial: 'ﻧ', isolated: 'ﻥ', medial: 'ﻨ', final: 'ﻦ' },
37903     1607: { initial: 'ﻫ', isolated: 'ﻩ', medial: 'ﻬ', final: 'ﻪ' },
37904     1608: { initial: 'ﻭ', isolated: 'ﻭ', medial: '', final: 'ﻮ' },
37905
37906     // 1609 ى
37907     1609: { initial: 'ﯨ', isolated: 'ﻯ', medial: 'ﯩ', final: 'ﻰ' },
37908     // 1610 ي
37909     1610: { initial: 'ﻳ', isolated: 'ﻱ', medial: 'ﻴ', final: 'ﻲ' },
37910
37911     // short vowel sounds / tashkil markings
37912
37913     1662: { initial: 'ﭘ', isolated: 'ﭖ', medial: 'ﭙ', final: 'ﭗ' },
37914
37915     1670: { initial: 'ﭼ', isolated: 'ﭺ', medial: 'ﭽ', final: 'ﭻ' },
37916     1603: { initial: 'ﻛ', isolated: 'ﻙ', medial: 'ﻜ', final: 'ﻚ' },
37917     1705: { initial: 'ﻛ', isolated: 'ﮎ', medial: 'ﻜ', final: 'ﮏ' },
37918     1711: { initial: 'ﮔ', isolated: 'ﮒ', medial: 'ﮕ', final: 'ﮓ' },
37919     1740: { initial: 'ﻳ', isolated: 'ﻯ', medial: 'ﻴ', final: 'ﻰ' },
37920     5000: { initial: 'ﻻ', isolated: 'ﻻ', medial: '', final: 'ﻼ' }
37921 };
37922
37923 var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0780-\u07BF]/;
37924
37925 function fixRTLTextForSvg(inputText) {
37926     var context = true;
37927     var ret = '';
37928     var rtlBuffer = [];
37929     var arabicRegex = /[\u0600-\u06FF]/g;
37930     var arabicTashkil = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED]/;
37931     var thaanaVowel = /[\u07A6-\u07B0]/;
37932     var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/;
37933
37934     if (!arabicRegex.test(inputText)) {
37935         // Hebrew or Thaana RTL script
37936         for (var n = 0; n < inputText.length; n++) {
37937             var c = inputText[n];
37938             if ((thaanaVowel.test(c) || hebrewSign.test(c)) && rtlBuffer.length) {
37939                 rtlBuffer[rtlBuffer.length - 1] += c;
37940             } else if (rtlRegex.test(c)) {
37941                 rtlBuffer.push(c);
37942             } else if (c === ' ' && rtlBuffer.length) {
37943                 // whitespace within RTL text
37944                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37945             } else {
37946                 // non-RTL character
37947                 ret += rtlBuffer.reverse().join('') + c;
37948                 rtlBuffer = [];
37949             }
37950         }
37951     } else {
37952         for (var i = 0, l = inputText.length; i < l; i++) {
37953             var code = inputText[i].charCodeAt(0);
37954             var nextCode = inputText[i + 1] ? inputText[i + 1].charCodeAt(0) : 0;
37955
37956             if (!chars$1[code]) {
37957                 if (code === 32 && rtlBuffer.length) {
37958                     // whitespace
37959                     rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37960                 } else if (arabicTashkil.test(inputText[i]) && rtlBuffer.length) {
37961                     // tashkil mark
37962                     rtlBuffer[rtlBuffer.length - 1] += inputText[i];
37963                 } else {
37964                     // non-RTL character
37965                     ret += rtlBuffer.reverse().join('') + inputText[i];
37966                     rtlBuffer = [];
37967                 }
37968                 continue;
37969             }
37970             if (context) {
37971                 if (i === l - 1 || nextCode === 32) {
37972                     rtlBuffer.push(chars$1[code].isolated);
37973                 } else {
37974                     // special case for لا
37975                     if (code === 1604 && nextCode === 1575) {
37976                         rtlBuffer.push(chars$1[5000].initial);
37977                         i++;
37978                         context = true;
37979                         continue;
37980                     }
37981                     rtlBuffer.push(chars$1[code].initial);
37982                 }
37983             } else {
37984                 if (i === l - 1 || nextCode === 32){
37985                     rtlBuffer.push(chars$1[code].final);
37986                 } else {
37987                     // special case for ﻼ
37988                     if (code === 1604 && nextCode === 1575){
37989                         rtlBuffer.push(chars$1[5000].final);
37990                         i++;
37991                         context = true;
37992                         continue;
37993                     }
37994                     if (chars$1[code].medial === ''){
37995                         rtlBuffer.push(chars$1[code].final);
37996                     } else {
37997                         rtlBuffer.push(chars$1[code].medial);
37998                     }
37999                 }
38000             }
38001             context = (chars$1[code].medial === '') || nextCode === 32;
38002         }
38003     }
38004     ret += rtlBuffer.reverse().join('');
38005     return ret;
38006 }
38007
38008 function utilTagText(entity) {
38009     return entries(entity.tags).map(function(e) {
38010         return e.key + '=' + e.value;
38011     }).join(', ');
38012 }
38013
38014
38015 function utilEntitySelector(ids) {
38016     return ids.length ? '.' + ids.join(',.') : 'nothing';
38017 }
38018
38019
38020 function utilEntityOrMemberSelector(ids, graph) {
38021     var s = utilEntitySelector(ids);
38022
38023     ids.forEach(function(id) {
38024         var entity = graph.hasEntity(id);
38025         if (entity && entity.type === 'relation') {
38026             entity.members.forEach(function(member) {
38027                 s += ',.' + member.id;
38028             });
38029         }
38030     });
38031
38032     return s;
38033 }
38034
38035
38036 function utilGetAllNodes(ids, graph) {
38037     var seen = {};
38038     var nodes = [];
38039     ids.forEach(getNodes);
38040     return nodes;
38041
38042     function getNodes(id) {
38043         if (seen[id]) return;
38044         seen[id] = true;
38045
38046         var entity = graph.hasEntity(id);
38047         if (!entity) return;
38048
38049         if (entity.type === 'node') {
38050             nodes.push(entity);
38051         } else if (entity.type === 'way') {
38052             entity.nodes.forEach(getNodes);
38053         } else {
38054             entity.members.map(function(member) { return member.id; }).forEach(getNodes);
38055         }
38056     }
38057 }
38058
38059
38060 function utilDisplayName(entity) {
38061     var localizedNameKey = 'name:' + utilDetect().locale.toLowerCase().split('-')[0],
38062         name = entity.tags[localizedNameKey] || entity.tags.name || '',
38063         network = entity.tags.cycle_network || entity.tags.network;
38064
38065     if (!name && entity.tags.ref) {
38066         name = entity.tags.ref;
38067         if (network) {
38068             name = network + ' ' + name;
38069         }
38070     }
38071
38072     return name;
38073 }
38074
38075
38076 function utilDisplayNameForPath(entity) {
38077     var name = utilDisplayName(entity);
38078     var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
38079
38080     if (!isFirefox && name && rtlRegex.test(name)) {
38081         name = fixRTLTextForSvg(name);
38082     }
38083
38084     return name;
38085 }
38086
38087
38088 function utilDisplayType(id) {
38089     return {
38090         n: t('inspector.node'),
38091         w: t('inspector.way'),
38092         r: t('inspector.relation')
38093     }[id.charAt(0)];
38094 }
38095
38096
38097 function utilStringQs(str) {
38098     return str.split('&').reduce(function(obj, pair){
38099         var parts = pair.split('=');
38100         if (parts.length === 2) {
38101             obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
38102         }
38103         return obj;
38104     }, {});
38105 }
38106
38107
38108 function utilQsString(obj, noencode) {
38109     function softEncode(s) {
38110       // encode everything except special characters used in certain hash parameters:
38111       // "/" in map states, ":", ",", {" and "}" in background
38112       return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
38113     }
38114     return Object.keys(obj).sort().map(function(key) {
38115         return encodeURIComponent(key) + '=' + (
38116             noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
38117     }).join('&');
38118 }
38119
38120
38121 function utilPrefixDOMProperty(property) {
38122     var prefixes = ['webkit', 'ms', 'moz', 'o'],
38123         i = -1,
38124         n = prefixes.length,
38125         s = document.body;
38126
38127     if (property in s)
38128         return property;
38129
38130     property = property.substr(0, 1).toUpperCase() + property.substr(1);
38131
38132     while (++i < n)
38133         if (prefixes[i] + property in s)
38134             return prefixes[i] + property;
38135
38136     return false;
38137 }
38138
38139
38140 function utilPrefixCSSProperty(property) {
38141     var prefixes = ['webkit', 'ms', 'Moz', 'O'],
38142         i = -1,
38143         n = prefixes.length,
38144         s = document.body.style;
38145
38146     if (property.toLowerCase() in s)
38147         return property.toLowerCase();
38148
38149     while (++i < n)
38150         if (prefixes[i] + property in s)
38151             return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
38152
38153     return false;
38154 }
38155
38156
38157 var transformProperty;
38158 function utilSetTransform(el, x, y, scale) {
38159     var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform'),
38160         translate = utilDetect().opera ?
38161             'translate('   + x + 'px,' + y + 'px)' :
38162             'translate3d(' + x + 'px,' + y + 'px,0)';
38163     return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
38164 }
38165
38166
38167 // Calculates Levenshtein distance between two strings
38168 // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
38169 // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
38170 function utilEditDistance(a, b) {
38171     a = remove$1(a.toLowerCase());
38172     b = remove$1(b.toLowerCase());
38173     if (a.length === 0) return b.length;
38174     if (b.length === 0) return a.length;
38175     var matrix = [];
38176     for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
38177     for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
38178     for (i = 1; i <= b.length; i++) {
38179         for (j = 1; j <= a.length; j++) {
38180             if (b.charAt(i-1) === a.charAt(j-1)) {
38181                 matrix[i][j] = matrix[i-1][j-1];
38182             } else {
38183                 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
38184                     Math.min(matrix[i][j-1] + 1, // insertion
38185                     matrix[i-1][j] + 1)); // deletion
38186             }
38187         }
38188     }
38189     return matrix[b.length][a.length];
38190 }
38191
38192
38193 // a d3.mouse-alike which
38194 // 1. Only works on HTML elements, not SVG
38195 // 2. Does not cause style recalculation
38196 function utilFastMouse(container) {
38197     var rect = container.getBoundingClientRect(),
38198         rectLeft = rect.left,
38199         rectTop = rect.top,
38200         clientLeft = +container.clientLeft,
38201         clientTop = +container.clientTop;
38202     if (textDirection === 'rtl') {
38203         rectLeft = 0;
38204     }
38205     return function(e) {
38206         return [
38207             e.clientX - rectLeft - clientLeft,
38208             e.clientY - rectTop - clientTop];
38209     };
38210 }
38211
38212
38213 /* eslint-disable no-proto */
38214 var utilGetPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
38215 /* eslint-enable no-proto */
38216
38217
38218 function utilAsyncMap(inputs, func, callback) {
38219     var remaining = inputs.length,
38220         results = [],
38221         errors = [];
38222
38223     inputs.forEach(function(d, i) {
38224         func(d, function done(err, data) {
38225             errors[i] = err;
38226             results[i] = data;
38227             remaining--;
38228             if (!remaining) callback(errors, results);
38229         });
38230     });
38231 }
38232
38233
38234 // wraps an index to an interval [0..length-1]
38235 function utilWrap(index, length) {
38236     if (index < 0)
38237         index += Math.ceil(-index/length)*length;
38238     return index % length;
38239 }
38240
38241
38242 /**
38243  * a replacement for functor
38244  *
38245  * @param {*} value any value
38246  * @returns {Function} a function that returns that value or the value if it's a function
38247  */
38248 function utilFunctor(value) {
38249     if (typeof value === 'function') return value;
38250     return function() {
38251         return value;
38252     };
38253 }
38254
38255
38256 function utilNoAuto(selection$$1) {
38257     return selection$$1
38258         .attr('autocomplete', 'off')
38259         .attr('autocorrect', 'off')
38260         .attr('autocapitalize', 'off')
38261         .attr('spellcheck', 'false');
38262 }
38263
38264 // Like selection.property('value', ...), but avoids no-op value sets,
38265 // which can result in layout/repaint thrashing in some situations.
38266 function utilGetSetValue(selection, value) {
38267     function d3_selection_value(value) {
38268         function valueNull() {
38269             delete this.value;
38270         }
38271
38272         function valueConstant() {
38273             if (this.value !== value) {
38274                 this.value = value;
38275             }
38276         }
38277
38278         function valueFunction() {
38279             var x = value.apply(this, arguments);
38280             if (x == null) {
38281                 delete this.value;
38282             } else if (this.value !== x) {
38283                 this.value = x;
38284             }
38285         }
38286
38287         return value == null
38288             ? valueNull : (typeof value === 'function'
38289             ? valueFunction : valueConstant);
38290     }
38291
38292     if (arguments.length === 1) {
38293         return selection.property('value');
38294     }
38295
38296     return selection.each(d3_selection_value(value));
38297 }
38298
38299 // Copies a variable number of methods from source to target.
38300 function utilRebind(target, source) {
38301     var i = 1, n = arguments.length, method;
38302     while (++i < n) {
38303         target[method = arguments[i]] = d3_rebind(target, source, source[method]);
38304     }
38305     return target;
38306 }
38307
38308 // Method is assumed to be a standard D3 getter-setter:
38309 // If passed with no arguments, gets the value.
38310 // If passed with arguments, sets the value and returns the target.
38311 function d3_rebind(target, source, method) {
38312     return function() {
38313         var value = method.apply(source, arguments);
38314         return value === source ? target : value;
38315     };
38316 }
38317
38318 // A per-domain session mutex backed by a cookie and dead man's
38319 // switch. If the session crashes, the mutex will auto-release
38320 // after 5 seconds.
38321
38322 function utilSessionMutex(name) {
38323     var mutex = {},
38324         intervalID;
38325
38326     function renew() {
38327         var expires = new Date();
38328         expires.setSeconds(expires.getSeconds() + 5);
38329         document.cookie = name + '=1; expires=' + expires.toUTCString();
38330     }
38331
38332     mutex.lock = function() {
38333         if (intervalID) return true;
38334         var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
38335         if (cookie) return false;
38336         renew();
38337         intervalID = window.setInterval(renew, 4000);
38338         return true;
38339     };
38340
38341     mutex.unlock = function() {
38342         if (!intervalID) return;
38343         document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
38344         clearInterval(intervalID);
38345         intervalID = null;
38346     };
38347
38348     mutex.locked = function() {
38349         return !!intervalID;
38350     };
38351
38352     return mutex;
38353 }
38354
38355 function utilSuggestNames(preset, suggestions) {
38356     preset = preset.id.split('/', 2);
38357     var k = preset[0],
38358         v = preset[1];
38359
38360     return function(value, callback) {
38361         var result = [];
38362         if (value && value.length > 2) {
38363             if (suggestions[k] && suggestions[k][v]) {
38364                 for (var sugg in suggestions[k][v]) {
38365                     var dist = utilEditDistance(value, sugg.substring(0, value.length));
38366                     if (dist < 3) {
38367                         result.push({
38368                             title: sugg,
38369                             value: sugg,
38370                             dist: dist
38371                         });
38372                     }
38373                 }
38374             }
38375             result.sort(function(a, b) {
38376                 return a.dist - b.dist;
38377             });
38378         }
38379         result = result.slice(0,3);
38380         callback(result);
38381     };
38382 }
38383
38384 function utilTriggerEvent(target, type) {
38385     target.each(function() {
38386         var evt = document.createEvent('HTMLEvents');
38387         evt.initEvent(type, true, true);
38388         this.dispatchEvent(evt);
38389     });
38390 }
38391
38392 function validationDeprecatedTag() {
38393
38394     var validation = function(changes) {
38395         var warnings = [];
38396         for (var i = 0; i < changes.created.length; i++) {
38397             var change = changes.created[i],
38398                 deprecatedTags = change.deprecatedTags();
38399
38400             if (!lodash.isEmpty(deprecatedTags)) {
38401                 var tags = utilTagText({ tags: deprecatedTags });
38402                 warnings.push({
38403                     id: 'deprecated_tags',
38404                     message: t('validations.deprecated_tags', { tags: tags }),
38405                     entity: change
38406                 });
38407             }
38408         }
38409
38410         return warnings;
38411     };
38412
38413
38414     return validation;
38415 }
38416
38417 function validationDisconnectedHighway() {
38418
38419
38420     function isDisconnectedHighway(entity, graph) {
38421         if (!entity.tags.highway) return false;
38422         if (entity.geometry(graph) !== 'line') return false;
38423
38424         return graph.childNodes(entity)
38425             .every(function(vertex) {
38426                 var parents = graph.parentWays(vertex);
38427                 if (parents.length === 1) {  // standalone vertex
38428                     return true;
38429                 } else {                     // shared vertex
38430                     return !vertex.tags.entrance &&
38431                         parents.filter(function(parent) {
38432                             return parent.tags.highway && parent !== entity;
38433                         }).length === 0;
38434                 }
38435             });
38436     }
38437
38438
38439     var validation = function(changes, graph) {
38440         var warnings = [];
38441         for (var i = 0; i < changes.created.length; i++) {
38442             var entity = changes.created[i];
38443
38444             if (isDisconnectedHighway(entity, graph)) {
38445                 warnings.push({
38446                     id: 'disconnected_highway',
38447                     message: t('validations.disconnected_highway'),
38448                     tooltip: t('validations.disconnected_highway_tooltip'),
38449                     entity: entity
38450                 });
38451             }
38452         }
38453
38454         return warnings;
38455     };
38456
38457
38458     return validation;
38459 }
38460
38461 function validationManyDeletions() {
38462     var threshold = 100;
38463
38464     var validation = function(changes) {
38465         var warnings = [];
38466         if (changes.deleted.length > threshold) {
38467             warnings.push({
38468                 id: 'many_deletions',
38469                 message: t('validations.many_deletions', { n: changes.deleted.length })
38470             });
38471         }
38472
38473         return warnings;
38474     };
38475
38476
38477     return validation;
38478 }
38479
38480 function validationMissingTag() {
38481
38482     // Slightly stricter check than Entity#isUsed (#3091)
38483     function hasTags(entity, graph) {
38484         return lodash.without(Object.keys(entity.tags), 'area', 'name').length > 0 ||
38485             graph.parentRelations(entity).length > 0;
38486     }
38487
38488     var validation = function(changes, graph) {
38489         var types = ['point', 'line', 'area', 'relation'],
38490             warnings = [];
38491
38492         for (var i = 0; i < changes.created.length; i++) {
38493             var change = changes.created[i],
38494                 geometry = change.geometry(graph);
38495
38496             if (types.indexOf(geometry) !== -1 && !hasTags(change, graph)) {
38497                 warnings.push({
38498                     id: 'missing_tag',
38499                     message: t('validations.untagged_' + geometry),
38500                     tooltip: t('validations.untagged_' + geometry + '_tooltip'),
38501                     entity: change
38502                 });
38503             }
38504         }
38505
38506         return warnings;
38507     };
38508
38509
38510     return validation;
38511 }
38512
38513 function validationOldMultipolygon() {
38514
38515
38516     return function validation(changes, graph) {
38517         var warnings = [];
38518         for (var i = 0; i < changes.created.length; i++) {
38519             var entity = changes.created[i];
38520             var parent = osmIsSimpleMultipolygonOuterMember(entity, graph);
38521             if (parent) {
38522                 warnings.push({
38523                     id: 'old_multipolygon',
38524                     message: t('validations.old_multipolygon'),
38525                     tooltip: t('validations.old_multipolygon_tooltip'),
38526                     entity: parent
38527                 });
38528             }
38529         }
38530         return warnings;
38531     };
38532 }
38533
38534 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
38535 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
38536 function validationTagSuggestsArea() {
38537
38538     function tagSuggestsArea(tags) {
38539         if (lodash.isEmpty(tags)) return false;
38540
38541         var presence = ['landuse', 'amenities', 'tourism', 'shop'];
38542         for (var i = 0; i < presence.length; i++) {
38543             if (tags[presence[i]] !== undefined) {
38544                 return presence[i] + '=' + tags[presence[i]];
38545             }
38546         }
38547
38548         if (tags.building && tags.building === 'yes') return 'building=yes';
38549     }
38550
38551
38552     var validation = function(changes, graph) {
38553         var warnings = [];
38554         for (var i = 0; i < changes.created.length; i++) {
38555             var change = changes.created[i],
38556                 geometry = change.geometry(graph),
38557                 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
38558
38559             if (suggestion) {
38560                 warnings.push({
38561                     id: 'tag_suggests_area',
38562                     message: t('validations.tag_suggests_area', { tag: suggestion }),
38563                     entity: change
38564                 });
38565             }
38566         }
38567
38568         return warnings;
38569     };
38570
38571
38572     return validation;
38573 }
38574
38575
38576
38577 var Validations = Object.freeze({
38578         validationDeprecatedTag: validationDeprecatedTag,
38579         validationDisconnectedHighway: validationDisconnectedHighway,
38580         validationManyDeletions: validationManyDeletions,
38581         validationMissingTag: validationMissingTag,
38582         validationOldMultipolygon: validationOldMultipolygon,
38583         validationTagSuggestsArea: validationTagSuggestsArea
38584 });
38585
38586 /*
38587     iD.Difference represents the difference between two graphs.
38588     It knows how to calculate the set of entities that were
38589     created, modified, or deleted, and also contains the logic
38590     for recursively extending a difference to the complete set
38591     of entities that will require a redraw, taking into account
38592     child and parent relationships.
38593  */
38594 function coreDifference(base, head) {
38595     var changes = {},
38596         difference = {},
38597         length = 0;
38598
38599
38600     function changed(h, b) {
38601         return h !== b && !lodash.isEqual(lodash.omit(h, 'v'), lodash.omit(b, 'v'));
38602     }
38603
38604
38605     lodash.each(head.entities, function(h, id) {
38606         var b = base.entities[id];
38607         if (changed(h, b)) {
38608             changes[id] = {base: b, head: h};
38609             length++;
38610         }
38611     });
38612
38613
38614     lodash.each(base.entities, function(b, id) {
38615         var h = head.entities[id];
38616         if (!changes[id] && changed(h, b)) {
38617             changes[id] = {base: b, head: h};
38618             length++;
38619         }
38620     });
38621
38622
38623     function addParents(parents, result) {
38624         for (var i = 0; i < parents.length; i++) {
38625             var parent = parents[i];
38626
38627             if (parent.id in result)
38628                 continue;
38629
38630             result[parent.id] = parent;
38631             addParents(head.parentRelations(parent), result);
38632         }
38633     }
38634
38635
38636     difference.length = function() {
38637         return length;
38638     };
38639
38640
38641     difference.changes = function() {
38642         return changes;
38643     };
38644
38645
38646     difference.extantIDs = function() {
38647         var result = [];
38648         lodash.each(changes, function(change, id) {
38649             if (change.head) result.push(id);
38650         });
38651         return result;
38652     };
38653
38654
38655     difference.modified = function() {
38656         var result = [];
38657         lodash.each(changes, function(change) {
38658             if (change.base && change.head) result.push(change.head);
38659         });
38660         return result;
38661     };
38662
38663
38664     difference.created = function() {
38665         var result = [];
38666         lodash.each(changes, function(change) {
38667             if (!change.base && change.head) result.push(change.head);
38668         });
38669         return result;
38670     };
38671
38672
38673     difference.deleted = function() {
38674         var result = [];
38675         lodash.each(changes, function(change) {
38676             if (change.base && !change.head) result.push(change.base);
38677         });
38678         return result;
38679     };
38680
38681
38682     difference.summary = function() {
38683         var relevant = {};
38684
38685         function addEntity(entity, graph, changeType) {
38686             relevant[entity.id] = {
38687                 entity: entity,
38688                 graph: graph,
38689                 changeType: changeType
38690             };
38691         }
38692
38693         function addParents(entity) {
38694             var parents = head.parentWays(entity);
38695             for (var j = parents.length - 1; j >= 0; j--) {
38696                 var parent = parents[j];
38697                 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
38698             }
38699         }
38700
38701         lodash.each(changes, function(change) {
38702             if (change.head && change.head.geometry(head) !== 'vertex') {
38703                 addEntity(change.head, head, change.base ? 'modified' : 'created');
38704
38705             } else if (change.base && change.base.geometry(base) !== 'vertex') {
38706                 addEntity(change.base, base, 'deleted');
38707
38708             } else if (change.base && change.head) { // modified vertex
38709                 var moved    = !lodash.isEqual(change.base.loc,  change.head.loc),
38710                     retagged = !lodash.isEqual(change.base.tags, change.head.tags);
38711
38712                 if (moved) {
38713                     addParents(change.head);
38714                 }
38715
38716                 if (retagged || (moved && change.head.hasInterestingTags())) {
38717                     addEntity(change.head, head, 'modified');
38718                 }
38719
38720             } else if (change.head && change.head.hasInterestingTags()) { // created vertex
38721                 addEntity(change.head, head, 'created');
38722
38723             } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
38724                 addEntity(change.base, base, 'deleted');
38725             }
38726         });
38727
38728         return values(relevant);
38729     };
38730
38731
38732     difference.complete = function(extent$$1) {
38733         var result = {}, id, change;
38734
38735         for (id in changes) {
38736             change = changes[id];
38737
38738             var h = change.head,
38739                 b = change.base,
38740                 entity = h || b;
38741
38742             if (extent$$1 &&
38743                 (!h || !h.intersects(extent$$1, head)) &&
38744                 (!b || !b.intersects(extent$$1, base)))
38745                 continue;
38746
38747             result[id] = h;
38748
38749             if (entity.type === 'way') {
38750                 var nh = h ? h.nodes : [],
38751                     nb = b ? b.nodes : [],
38752                     diff, i;
38753
38754                 diff = lodash.difference(nh, nb);
38755                 for (i = 0; i < diff.length; i++) {
38756                     result[diff[i]] = head.hasEntity(diff[i]);
38757                 }
38758
38759                 diff = lodash.difference(nb, nh);
38760                 for (i = 0; i < diff.length; i++) {
38761                     result[diff[i]] = head.hasEntity(diff[i]);
38762                 }
38763             }
38764
38765             addParents(head.parentWays(entity), result);
38766             addParents(head.parentRelations(entity), result);
38767         }
38768
38769         return result;
38770     };
38771
38772
38773     return difference;
38774 }
38775
38776 function coreGraph$$1(other, mutable) {
38777     if (!(this instanceof coreGraph$$1)) return new coreGraph$$1(other, mutable);
38778
38779     if (other instanceof coreGraph$$1) {
38780         var base = other.base();
38781         this.entities = lodash.assign(Object.create(base.entities), other.entities);
38782         this._parentWays = lodash.assign(Object.create(base.parentWays), other._parentWays);
38783         this._parentRels = lodash.assign(Object.create(base.parentRels), other._parentRels);
38784
38785     } else {
38786         this.entities = Object.create({});
38787         this._parentWays = Object.create({});
38788         this._parentRels = Object.create({});
38789         this.rebase(other || [], [this]);
38790     }
38791
38792     this.transients = {};
38793     this._childNodes = {};
38794     this.frozen = !mutable;
38795 }
38796
38797
38798 coreGraph$$1.prototype = {
38799
38800     hasEntity: function(id) {
38801         return this.entities[id];
38802     },
38803
38804
38805     entity: function(id) {
38806         var entity = this.entities[id];
38807
38808         //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
38809         if (!entity) {
38810             entity = this.entities.__proto__[id];  // eslint-disable-line no-proto
38811         }
38812
38813         if (!entity) {
38814             throw new Error('entity ' + id + ' not found');
38815         }
38816         return entity;
38817     },
38818
38819
38820     transient: function(entity, key, fn) {
38821         var id = entity.id,
38822             transients = this.transients[id] ||
38823             (this.transients[id] = {});
38824
38825         if (transients[key] !== undefined) {
38826             return transients[key];
38827         }
38828
38829         transients[key] = fn.call(entity);
38830
38831         return transients[key];
38832     },
38833
38834
38835     parentWays: function(entity) {
38836         var parents = this._parentWays[entity.id],
38837             result = [];
38838
38839         if (parents) {
38840             for (var i = 0; i < parents.length; i++) {
38841                 result.push(this.entity(parents[i]));
38842             }
38843         }
38844         return result;
38845     },
38846
38847
38848     isPoi: function(entity) {
38849         var parentWays = this._parentWays[entity.id];
38850         return !parentWays || parentWays.length === 0;
38851     },
38852
38853
38854     isShared: function(entity) {
38855         var parentWays = this._parentWays[entity.id];
38856         return parentWays && parentWays.length > 1;
38857     },
38858
38859
38860     parentRelations: function(entity) {
38861         var parents = this._parentRels[entity.id],
38862             result = [];
38863
38864         if (parents) {
38865             for (var i = 0; i < parents.length; i++) {
38866                 result.push(this.entity(parents[i]));
38867             }
38868         }
38869         return result;
38870     },
38871
38872
38873     childNodes: function(entity) {
38874         if (this._childNodes[entity.id]) return this._childNodes[entity.id];
38875         if (!entity.nodes) return [];
38876
38877         var nodes = [];
38878         for (var i = 0; i < entity.nodes.length; i++) {
38879             nodes[i] = this.entity(entity.nodes[i]);
38880         }
38881
38882         if (debug) Object.freeze(nodes);
38883
38884         this._childNodes[entity.id] = nodes;
38885         return this._childNodes[entity.id];
38886     },
38887
38888
38889     base: function() {
38890         return {
38891             'entities': utilGetPrototypeOf(this.entities),
38892             'parentWays': utilGetPrototypeOf(this._parentWays),
38893             'parentRels': utilGetPrototypeOf(this._parentRels)
38894         };
38895     },
38896
38897
38898     // Unlike other graph methods, rebase mutates in place. This is because it
38899     // is used only during the history operation that merges newly downloaded
38900     // data into each state. To external consumers, it should appear as if the
38901     // graph always contained the newly downloaded data.
38902     rebase: function(entities, stack, force) {
38903         var base = this.base(),
38904             i, j, k, id;
38905
38906         for (i = 0; i < entities.length; i++) {
38907             var entity = entities[i];
38908
38909             if (!entity.visible || (!force && base.entities[entity.id]))
38910                 continue;
38911
38912             // Merging data into the base graph
38913             base.entities[entity.id] = entity;
38914             this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
38915
38916             // Restore provisionally-deleted nodes that are discovered to have an extant parent
38917             if (entity.type === 'way') {
38918                 for (j = 0; j < entity.nodes.length; j++) {
38919                     id = entity.nodes[j];
38920                     for (k = 1; k < stack.length; k++) {
38921                         var ents = stack[k].entities;
38922                         if (ents.hasOwnProperty(id) && ents[id] === undefined) {
38923                             delete ents[id];
38924                         }
38925                     }
38926                 }
38927             }
38928         }
38929
38930         for (i = 0; i < stack.length; i++) {
38931             stack[i]._updateRebased();
38932         }
38933     },
38934
38935
38936     _updateRebased: function() {
38937         var base = this.base(),
38938             i, k, child, id, keys;
38939
38940         keys = Object.keys(this._parentWays);
38941         for (i = 0; i < keys.length; i++) {
38942             child = keys[i];
38943             if (base.parentWays[child]) {
38944                 for (k = 0; k < base.parentWays[child].length; k++) {
38945                     id = base.parentWays[child][k];
38946                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentWays[child], id)) {
38947                         this._parentWays[child].push(id);
38948                     }
38949                 }
38950             }
38951         }
38952
38953         keys = Object.keys(this._parentRels);
38954         for (i = 0; i < keys.length; i++) {
38955             child = keys[i];
38956             if (base.parentRels[child]) {
38957                 for (k = 0; k < base.parentRels[child].length; k++) {
38958                     id = base.parentRels[child][k];
38959                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentRels[child], id)) {
38960                         this._parentRels[child].push(id);
38961                     }
38962                 }
38963             }
38964         }
38965
38966         this.transients = {};
38967
38968         // this._childNodes is not updated, under the assumption that
38969         // ways are always downloaded with their child nodes.
38970     },
38971
38972
38973     // Updates calculated properties (parentWays, parentRels) for the specified change
38974     _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
38975
38976         parentWays = parentWays || this._parentWays;
38977         parentRels = parentRels || this._parentRels;
38978
38979         var type = entity && entity.type || oldentity && oldentity.type,
38980             removed, added, ways, rels, i;
38981
38982
38983         if (type === 'way') {
38984
38985             // Update parentWays
38986             if (oldentity && entity) {
38987                 removed = lodash.difference(oldentity.nodes, entity.nodes);
38988                 added = lodash.difference(entity.nodes, oldentity.nodes);
38989             } else if (oldentity) {
38990                 removed = oldentity.nodes;
38991                 added = [];
38992             } else if (entity) {
38993                 removed = [];
38994                 added = entity.nodes;
38995             }
38996             for (i = 0; i < removed.length; i++) {
38997                 parentWays[removed[i]] = lodash.without(parentWays[removed[i]], oldentity.id);
38998             }
38999             for (i = 0; i < added.length; i++) {
39000                 ways = lodash.without(parentWays[added[i]], entity.id);
39001                 ways.push(entity.id);
39002                 parentWays[added[i]] = ways;
39003             }
39004
39005         } else if (type === 'relation') {
39006
39007             // Update parentRels
39008             if (oldentity && entity) {
39009                 removed = lodash.difference(oldentity.members, entity.members);
39010                 added = lodash.difference(entity.members, oldentity);
39011             } else if (oldentity) {
39012                 removed = oldentity.members;
39013                 added = [];
39014             } else if (entity) {
39015                 removed = [];
39016                 added = entity.members;
39017             }
39018             for (i = 0; i < removed.length; i++) {
39019                 parentRels[removed[i].id] = lodash.without(parentRels[removed[i].id], oldentity.id);
39020             }
39021             for (i = 0; i < added.length; i++) {
39022                 rels = lodash.without(parentRels[added[i].id], entity.id);
39023                 rels.push(entity.id);
39024                 parentRels[added[i].id] = rels;
39025             }
39026         }
39027     },
39028
39029
39030     replace: function(entity) {
39031         if (this.entities[entity.id] === entity)
39032             return this;
39033
39034         return this.update(function() {
39035             this._updateCalculated(this.entities[entity.id], entity);
39036             this.entities[entity.id] = entity;
39037         });
39038     },
39039
39040
39041     remove: function(entity) {
39042         return this.update(function() {
39043             this._updateCalculated(entity, undefined);
39044             this.entities[entity.id] = undefined;
39045         });
39046     },
39047
39048
39049     revert: function(id) {
39050         var baseEntity = this.base().entities[id],
39051             headEntity = this.entities[id];
39052
39053         if (headEntity === baseEntity)
39054             return this;
39055
39056         return this.update(function() {
39057             this._updateCalculated(headEntity, baseEntity);
39058             delete this.entities[id];
39059         });
39060     },
39061
39062
39063     update: function() {
39064         var graph = this.frozen ? coreGraph$$1(this, true) : this;
39065
39066         for (var i = 0; i < arguments.length; i++) {
39067             arguments[i].call(graph, graph);
39068         }
39069
39070         if (this.frozen) graph.frozen = true;
39071
39072         return graph;
39073     },
39074
39075
39076     // Obliterates any existing entities
39077     load: function(entities) {
39078         var base = this.base();
39079         this.entities = Object.create(base.entities);
39080
39081         for (var i in entities) {
39082             this.entities[i] = entities[i];
39083             this._updateCalculated(base.entities[i], this.entities[i]);
39084         }
39085
39086         return this;
39087     }
39088 };
39089
39090 var index$10 = partialSort;
39091
39092 // Floyd-Rivest selection algorithm:
39093 // Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right];
39094 // The k-th element will have the (k - left + 1)th smallest value in [left, right]
39095
39096 function partialSort(arr, k, left, right, compare) {
39097     left = left || 0;
39098     right = right || (arr.length - 1);
39099     compare = compare || defaultCompare;
39100
39101     while (right > left) {
39102         if (right - left > 600) {
39103             var n = right - left + 1;
39104             var m = k - left + 1;
39105             var z = Math.log(n);
39106             var s = 0.5 * Math.exp(2 * z / 3);
39107             var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
39108             var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
39109             var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
39110             partialSort(arr, k, newLeft, newRight, compare);
39111         }
39112
39113         var t = arr[k];
39114         var i = left;
39115         var j = right;
39116
39117         swap(arr, left, k);
39118         if (compare(arr[right], t) > 0) swap(arr, left, right);
39119
39120         while (i < j) {
39121             swap(arr, i, j);
39122             i++;
39123             j--;
39124             while (compare(arr[i], t) < 0) i++;
39125             while (compare(arr[j], t) > 0) j--;
39126         }
39127
39128         if (compare(arr[left], t) === 0) swap(arr, left, j);
39129         else {
39130             j++;
39131             swap(arr, j, right);
39132         }
39133
39134         if (j <= k) left = j + 1;
39135         if (k <= j) right = j - 1;
39136     }
39137 }
39138
39139 function swap(arr, i, j) {
39140     var tmp = arr[i];
39141     arr[i] = arr[j];
39142     arr[j] = tmp;
39143 }
39144
39145 function defaultCompare(a, b) {
39146     return a < b ? -1 : a > b ? 1 : 0;
39147 }
39148
39149 var index$9 = rbush;
39150
39151
39152
39153 function rbush(maxEntries, format) {
39154     if (!(this instanceof rbush)) return new rbush(maxEntries, format);
39155
39156     // max entries in a node is 9 by default; min node fill is 40% for best performance
39157     this._maxEntries = Math.max(4, maxEntries || 9);
39158     this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
39159
39160     if (format) {
39161         this._initFormat(format);
39162     }
39163
39164     this.clear();
39165 }
39166
39167 rbush.prototype = {
39168
39169     all: function () {
39170         return this._all(this.data, []);
39171     },
39172
39173     search: function (bbox) {
39174
39175         var node = this.data,
39176             result = [],
39177             toBBox = this.toBBox;
39178
39179         if (!intersects$1(bbox, node)) return result;
39180
39181         var nodesToSearch = [],
39182             i, len, child, childBBox;
39183
39184         while (node) {
39185             for (i = 0, len = node.children.length; i < len; i++) {
39186
39187                 child = node.children[i];
39188                 childBBox = node.leaf ? toBBox(child) : child;
39189
39190                 if (intersects$1(bbox, childBBox)) {
39191                     if (node.leaf) result.push(child);
39192                     else if (contains$2(bbox, childBBox)) this._all(child, result);
39193                     else nodesToSearch.push(child);
39194                 }
39195             }
39196             node = nodesToSearch.pop();
39197         }
39198
39199         return result;
39200     },
39201
39202     collides: function (bbox) {
39203
39204         var node = this.data,
39205             toBBox = this.toBBox;
39206
39207         if (!intersects$1(bbox, node)) return false;
39208
39209         var nodesToSearch = [],
39210             i, len, child, childBBox;
39211
39212         while (node) {
39213             for (i = 0, len = node.children.length; i < len; i++) {
39214
39215                 child = node.children[i];
39216                 childBBox = node.leaf ? toBBox(child) : child;
39217
39218                 if (intersects$1(bbox, childBBox)) {
39219                     if (node.leaf || contains$2(bbox, childBBox)) return true;
39220                     nodesToSearch.push(child);
39221                 }
39222             }
39223             node = nodesToSearch.pop();
39224         }
39225
39226         return false;
39227     },
39228
39229     load: function (data) {
39230         if (!(data && data.length)) return this;
39231
39232         if (data.length < this._minEntries) {
39233             for (var i = 0, len = data.length; i < len; i++) {
39234                 this.insert(data[i]);
39235             }
39236             return this;
39237         }
39238
39239         // recursively build the tree with the given data from stratch using OMT algorithm
39240         var node = this._build(data.slice(), 0, data.length - 1, 0);
39241
39242         if (!this.data.children.length) {
39243             // save as is if tree is empty
39244             this.data = node;
39245
39246         } else if (this.data.height === node.height) {
39247             // split root if trees have the same height
39248             this._splitRoot(this.data, node);
39249
39250         } else {
39251             if (this.data.height < node.height) {
39252                 // swap trees if inserted one is bigger
39253                 var tmpNode = this.data;
39254                 this.data = node;
39255                 node = tmpNode;
39256             }
39257
39258             // insert the small tree into the large tree at appropriate level
39259             this._insert(node, this.data.height - node.height - 1, true);
39260         }
39261
39262         return this;
39263     },
39264
39265     insert: function (item) {
39266         if (item) this._insert(item, this.data.height - 1);
39267         return this;
39268     },
39269
39270     clear: function () {
39271         this.data = createNode([]);
39272         return this;
39273     },
39274
39275     remove: function (item, equalsFn) {
39276         if (!item) return this;
39277
39278         var node = this.data,
39279             bbox = this.toBBox(item),
39280             path = [],
39281             indexes = [],
39282             i, parent, index, goingUp;
39283
39284         // depth-first iterative tree traversal
39285         while (node || path.length) {
39286
39287             if (!node) { // go up
39288                 node = path.pop();
39289                 parent = path[path.length - 1];
39290                 i = indexes.pop();
39291                 goingUp = true;
39292             }
39293
39294             if (node.leaf) { // check current node
39295                 index = findItem(item, node.children, equalsFn);
39296
39297                 if (index !== -1) {
39298                     // item found, remove the item and condense tree upwards
39299                     node.children.splice(index, 1);
39300                     path.push(node);
39301                     this._condense(path);
39302                     return this;
39303                 }
39304             }
39305
39306             if (!goingUp && !node.leaf && contains$2(node, bbox)) { // go down
39307                 path.push(node);
39308                 indexes.push(i);
39309                 i = 0;
39310                 parent = node;
39311                 node = node.children[0];
39312
39313             } else if (parent) { // go right
39314                 i++;
39315                 node = parent.children[i];
39316                 goingUp = false;
39317
39318             } else node = null; // nothing found
39319         }
39320
39321         return this;
39322     },
39323
39324     toBBox: function (item) { return item; },
39325
39326     compareMinX: compareNodeMinX,
39327     compareMinY: compareNodeMinY,
39328
39329     toJSON: function () { return this.data; },
39330
39331     fromJSON: function (data) {
39332         this.data = data;
39333         return this;
39334     },
39335
39336     _all: function (node, result) {
39337         var nodesToSearch = [];
39338         while (node) {
39339             if (node.leaf) result.push.apply(result, node.children);
39340             else nodesToSearch.push.apply(nodesToSearch, node.children);
39341
39342             node = nodesToSearch.pop();
39343         }
39344         return result;
39345     },
39346
39347     _build: function (items, left, right, height) {
39348
39349         var N = right - left + 1,
39350             M = this._maxEntries,
39351             node;
39352
39353         if (N <= M) {
39354             // reached leaf level; return leaf
39355             node = createNode(items.slice(left, right + 1));
39356             calcBBox(node, this.toBBox);
39357             return node;
39358         }
39359
39360         if (!height) {
39361             // target height of the bulk-loaded tree
39362             height = Math.ceil(Math.log(N) / Math.log(M));
39363
39364             // target number of root entries to maximize storage utilization
39365             M = Math.ceil(N / Math.pow(M, height - 1));
39366         }
39367
39368         node = createNode([]);
39369         node.leaf = false;
39370         node.height = height;
39371
39372         // split the items into M mostly square tiles
39373
39374         var N2 = Math.ceil(N / M),
39375             N1 = N2 * Math.ceil(Math.sqrt(M)),
39376             i, j, right2, right3;
39377
39378         multiSelect(items, left, right, N1, this.compareMinX);
39379
39380         for (i = left; i <= right; i += N1) {
39381
39382             right2 = Math.min(i + N1 - 1, right);
39383
39384             multiSelect(items, i, right2, N2, this.compareMinY);
39385
39386             for (j = i; j <= right2; j += N2) {
39387
39388                 right3 = Math.min(j + N2 - 1, right2);
39389
39390                 // pack each entry recursively
39391                 node.children.push(this._build(items, j, right3, height - 1));
39392             }
39393         }
39394
39395         calcBBox(node, this.toBBox);
39396
39397         return node;
39398     },
39399
39400     _chooseSubtree: function (bbox, node, level, path) {
39401
39402         var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
39403
39404         while (true) {
39405             path.push(node);
39406
39407             if (node.leaf || path.length - 1 === level) break;
39408
39409             minArea = minEnlargement = Infinity;
39410
39411             for (i = 0, len = node.children.length; i < len; i++) {
39412                 child = node.children[i];
39413                 area = bboxArea(child);
39414                 enlargement = enlargedArea(bbox, child) - area;
39415
39416                 // choose entry with the least area enlargement
39417                 if (enlargement < minEnlargement) {
39418                     minEnlargement = enlargement;
39419                     minArea = area < minArea ? area : minArea;
39420                     targetNode = child;
39421
39422                 } else if (enlargement === minEnlargement) {
39423                     // otherwise choose one with the smallest area
39424                     if (area < minArea) {
39425                         minArea = area;
39426                         targetNode = child;
39427                     }
39428                 }
39429             }
39430
39431             node = targetNode || node.children[0];
39432         }
39433
39434         return node;
39435     },
39436
39437     _insert: function (item, level, isNode) {
39438
39439         var toBBox = this.toBBox,
39440             bbox = isNode ? item : toBBox(item),
39441             insertPath = [];
39442
39443         // find the best node for accommodating the item, saving all nodes along the path too
39444         var node = this._chooseSubtree(bbox, this.data, level, insertPath);
39445
39446         // put the item into the node
39447         node.children.push(item);
39448         extend$1(node, bbox);
39449
39450         // split on node overflow; propagate upwards if necessary
39451         while (level >= 0) {
39452             if (insertPath[level].children.length > this._maxEntries) {
39453                 this._split(insertPath, level);
39454                 level--;
39455             } else break;
39456         }
39457
39458         // adjust bboxes along the insertion path
39459         this._adjustParentBBoxes(bbox, insertPath, level);
39460     },
39461
39462     // split overflowed node into two
39463     _split: function (insertPath, level) {
39464
39465         var node = insertPath[level],
39466             M = node.children.length,
39467             m = this._minEntries;
39468
39469         this._chooseSplitAxis(node, m, M);
39470
39471         var splitIndex = this._chooseSplitIndex(node, m, M);
39472
39473         var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
39474         newNode.height = node.height;
39475         newNode.leaf = node.leaf;
39476
39477         calcBBox(node, this.toBBox);
39478         calcBBox(newNode, this.toBBox);
39479
39480         if (level) insertPath[level - 1].children.push(newNode);
39481         else this._splitRoot(node, newNode);
39482     },
39483
39484     _splitRoot: function (node, newNode) {
39485         // split root node
39486         this.data = createNode([node, newNode]);
39487         this.data.height = node.height + 1;
39488         this.data.leaf = false;
39489         calcBBox(this.data, this.toBBox);
39490     },
39491
39492     _chooseSplitIndex: function (node, m, M) {
39493
39494         var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
39495
39496         minOverlap = minArea = Infinity;
39497
39498         for (i = m; i <= M - m; i++) {
39499             bbox1 = distBBox(node, 0, i, this.toBBox);
39500             bbox2 = distBBox(node, i, M, this.toBBox);
39501
39502             overlap = intersectionArea(bbox1, bbox2);
39503             area = bboxArea(bbox1) + bboxArea(bbox2);
39504
39505             // choose distribution with minimum overlap
39506             if (overlap < minOverlap) {
39507                 minOverlap = overlap;
39508                 index = i;
39509
39510                 minArea = area < minArea ? area : minArea;
39511
39512             } else if (overlap === minOverlap) {
39513                 // otherwise choose distribution with minimum area
39514                 if (area < minArea) {
39515                     minArea = area;
39516                     index = i;
39517                 }
39518             }
39519         }
39520
39521         return index;
39522     },
39523
39524     // sorts node children by the best axis for split
39525     _chooseSplitAxis: function (node, m, M) {
39526
39527         var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
39528             compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
39529             xMargin = this._allDistMargin(node, m, M, compareMinX),
39530             yMargin = this._allDistMargin(node, m, M, compareMinY);
39531
39532         // if total distributions margin value is minimal for x, sort by minX,
39533         // otherwise it's already sorted by minY
39534         if (xMargin < yMargin) node.children.sort(compareMinX);
39535     },
39536
39537     // total margin of all possible split distributions where each node is at least m full
39538     _allDistMargin: function (node, m, M, compare) {
39539
39540         node.children.sort(compare);
39541
39542         var toBBox = this.toBBox,
39543             leftBBox = distBBox(node, 0, m, toBBox),
39544             rightBBox = distBBox(node, M - m, M, toBBox),
39545             margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
39546             i, child;
39547
39548         for (i = m; i < M - m; i++) {
39549             child = node.children[i];
39550             extend$1(leftBBox, node.leaf ? toBBox(child) : child);
39551             margin += bboxMargin(leftBBox);
39552         }
39553
39554         for (i = M - m - 1; i >= m; i--) {
39555             child = node.children[i];
39556             extend$1(rightBBox, node.leaf ? toBBox(child) : child);
39557             margin += bboxMargin(rightBBox);
39558         }
39559
39560         return margin;
39561     },
39562
39563     _adjustParentBBoxes: function (bbox, path, level) {
39564         // adjust bboxes along the given tree path
39565         for (var i = level; i >= 0; i--) {
39566             extend$1(path[i], bbox);
39567         }
39568     },
39569
39570     _condense: function (path) {
39571         // go through the path, removing empty nodes and updating bboxes
39572         for (var i = path.length - 1, siblings; i >= 0; i--) {
39573             if (path[i].children.length === 0) {
39574                 if (i > 0) {
39575                     siblings = path[i - 1].children;
39576                     siblings.splice(siblings.indexOf(path[i]), 1);
39577
39578                 } else this.clear();
39579
39580             } else calcBBox(path[i], this.toBBox);
39581         }
39582     },
39583
39584     _initFormat: function (format) {
39585         // data format (minX, minY, maxX, maxY accessors)
39586
39587         // uses eval-type function compilation instead of just accepting a toBBox function
39588         // because the algorithms are very sensitive to sorting functions performance,
39589         // so they should be dead simple and without inner calls
39590
39591         var compareArr = ['return a', ' - b', ';'];
39592
39593         this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
39594         this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
39595
39596         this.toBBox = new Function('a',
39597             'return {minX: a' + format[0] +
39598             ', minY: a' + format[1] +
39599             ', maxX: a' + format[2] +
39600             ', maxY: a' + format[3] + '};');
39601     }
39602 };
39603
39604 function findItem(item, items, equalsFn) {
39605     if (!equalsFn) return items.indexOf(item);
39606
39607     for (var i = 0; i < items.length; i++) {
39608         if (equalsFn(item, items[i])) return i;
39609     }
39610     return -1;
39611 }
39612
39613 // calculate node's bbox from bboxes of its children
39614 function calcBBox(node, toBBox) {
39615     distBBox(node, 0, node.children.length, toBBox, node);
39616 }
39617
39618 // min bounding rectangle of node children from k to p-1
39619 function distBBox(node, k, p, toBBox, destNode) {
39620     if (!destNode) destNode = createNode(null);
39621     destNode.minX = Infinity;
39622     destNode.minY = Infinity;
39623     destNode.maxX = -Infinity;
39624     destNode.maxY = -Infinity;
39625
39626     for (var i = k, child; i < p; i++) {
39627         child = node.children[i];
39628         extend$1(destNode, node.leaf ? toBBox(child) : child);
39629     }
39630
39631     return destNode;
39632 }
39633
39634 function extend$1(a, b) {
39635     a.minX = Math.min(a.minX, b.minX);
39636     a.minY = Math.min(a.minY, b.minY);
39637     a.maxX = Math.max(a.maxX, b.maxX);
39638     a.maxY = Math.max(a.maxY, b.maxY);
39639     return a;
39640 }
39641
39642 function compareNodeMinX(a, b) { return a.minX - b.minX; }
39643 function compareNodeMinY(a, b) { return a.minY - b.minY; }
39644
39645 function bboxArea(a)   { return (a.maxX - a.minX) * (a.maxY - a.minY); }
39646 function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
39647
39648 function enlargedArea(a, b) {
39649     return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
39650            (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
39651 }
39652
39653 function intersectionArea(a, b) {
39654     var minX = Math.max(a.minX, b.minX),
39655         minY = Math.max(a.minY, b.minY),
39656         maxX = Math.min(a.maxX, b.maxX),
39657         maxY = Math.min(a.maxY, b.maxY);
39658
39659     return Math.max(0, maxX - minX) *
39660            Math.max(0, maxY - minY);
39661 }
39662
39663 function contains$2(a, b) {
39664     return a.minX <= b.minX &&
39665            a.minY <= b.minY &&
39666            b.maxX <= a.maxX &&
39667            b.maxY <= a.maxY;
39668 }
39669
39670 function intersects$1(a, b) {
39671     return b.minX <= a.maxX &&
39672            b.minY <= a.maxY &&
39673            b.maxX >= a.minX &&
39674            b.maxY >= a.minY;
39675 }
39676
39677 function createNode(children) {
39678     return {
39679         children: children,
39680         height: 1,
39681         leaf: true,
39682         minX: Infinity,
39683         minY: Infinity,
39684         maxX: -Infinity,
39685         maxY: -Infinity
39686     };
39687 }
39688
39689 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
39690 // combines selection algorithm with binary divide & conquer approach
39691
39692 function multiSelect(arr, left, right, n, compare) {
39693     var stack = [left, right],
39694         mid;
39695
39696     while (stack.length) {
39697         right = stack.pop();
39698         left = stack.pop();
39699
39700         if (right - left <= n) continue;
39701
39702         mid = left + Math.ceil((right - left) / n / 2) * n;
39703         index$10(arr, mid, left, right, compare);
39704
39705         stack.push(left, mid, mid, right);
39706     }
39707 }
39708
39709 function coreTree(head) {
39710     var rtree = index$9(),
39711         bboxes = {},
39712         tree = {};
39713
39714
39715     function entityBBox(entity) {
39716         var bbox = entity.extent(head).bbox();
39717         bbox.id = entity.id;
39718         bboxes[entity.id] = bbox;
39719         return bbox;
39720     }
39721
39722
39723     function updateParents(entity, insertions, memo) {
39724         head.parentWays(entity).forEach(function(way) {
39725             if (bboxes[way.id]) {
39726                 rtree.remove(bboxes[way.id]);
39727                 insertions[way.id] = way;
39728             }
39729             updateParents(way, insertions, memo);
39730         });
39731
39732         head.parentRelations(entity).forEach(function(relation) {
39733             if (memo[entity.id]) return;
39734             memo[entity.id] = true;
39735             if (bboxes[relation.id]) {
39736                 rtree.remove(bboxes[relation.id]);
39737                 insertions[relation.id] = relation;
39738             }
39739             updateParents(relation, insertions, memo);
39740         });
39741     }
39742
39743
39744     tree.rebase = function(entities, force) {
39745         var insertions = {};
39746
39747         for (var i = 0; i < entities.length; i++) {
39748             var entity = entities[i];
39749
39750             if (!entity.visible)
39751                 continue;
39752
39753             if (head.entities.hasOwnProperty(entity.id) || bboxes[entity.id]) {
39754                 if (!force) {
39755                     continue;
39756                 } else if (bboxes[entity.id]) {
39757                     rtree.remove(bboxes[entity.id]);
39758                 }
39759             }
39760
39761             insertions[entity.id] = entity;
39762             updateParents(entity, insertions, {});
39763         }
39764
39765         rtree.load(lodash.map(insertions, entityBBox));
39766
39767         return tree;
39768     };
39769
39770
39771     tree.intersects = function(extent, graph) {
39772         if (graph !== head) {
39773             var diff = coreDifference(head, graph),
39774                 insertions = {};
39775
39776             head = graph;
39777
39778             diff.deleted().forEach(function(entity) {
39779                 rtree.remove(bboxes[entity.id]);
39780                 delete bboxes[entity.id];
39781             });
39782
39783             diff.modified().forEach(function(entity) {
39784                 rtree.remove(bboxes[entity.id]);
39785                 insertions[entity.id] = entity;
39786                 updateParents(entity, insertions, {});
39787             });
39788
39789             diff.created().forEach(function(entity) {
39790                 insertions[entity.id] = entity;
39791             });
39792
39793             rtree.load(lodash.map(insertions, entityBBox));
39794         }
39795
39796         return rtree.search(extent.bbox()).map(function(bbox) {
39797             return head.entity(bbox.id);
39798         });
39799     };
39800
39801
39802     return tree;
39803 }
39804
39805 /*
39806  * This code is licensed under the MIT license.
39807  *
39808  * Copyright © 2013, iD authors.
39809  *
39810  * Portions copyright © 2011, Keith Cirkel
39811  * See https://github.com/keithamus/jwerty
39812  *
39813  */
39814 function d3keybinding(namespace$$1) {
39815     var bindings = [];
39816
39817
39818     function testBindings(isCapturing) {
39819         var didMatch = false,
39820             i, binding;
39821
39822         // Most key shortcuts will accept either lower or uppercase ('h' or 'H'),
39823         // so we don't strictly match on the shift key, but we prioritize
39824         // shifted bindings first, and fallback to unshifted only if no match.
39825         // (This lets us differentiate between '←'/'⇧←' or '⌘Z'/'⌘⇧Z')
39826
39827         // priority match shifted bindings first
39828         for (i = 0; i < bindings.length; i++) {
39829             binding = bindings[i];
39830             if (!binding.event.modifiers.shiftKey) continue;  // no shift
39831             if (!!binding.capture !== isCapturing) continue;
39832             if (matches(binding, true)) {
39833                 binding.callback();
39834                 didMatch = true;
39835             }
39836         }
39837
39838         // then unshifted bindings
39839         if (didMatch) return;
39840         for (i = 0; i < bindings.length; i++) {
39841             binding = bindings[i];
39842             if (binding.event.modifiers.shiftKey) continue;   // shift
39843             if (!!binding.capture !== isCapturing) continue;
39844             if (matches(binding, false)) {
39845                 binding.callback();
39846             }
39847         }
39848
39849
39850         function matches(binding, testShift) {
39851             var event$$1 = event;
39852             if (event$$1.key !== undefined) {
39853                 if (binding.event.key === undefined) {
39854                     return false;
39855                 } else if (lodash.isArray(binding.event.key)) {
39856                     if (binding.event.key.map(function(s) { return s.toLowerCase(); }).indexOf(event$$1.key.toLowerCase()) === -1)
39857                         return false;
39858                 } else {
39859                     if (event$$1.key.toLowerCase() !== binding.event.key.toLowerCase())
39860                         return false;
39861                 }
39862             } else {
39863                 // check keycodes if browser doesn't support KeyboardEvent.key
39864                 if (event$$1.keyCode !== binding.event.keyCode)
39865                     return false;
39866             }
39867
39868             // test modifier keys
39869             if (!(event$$1.ctrlKey && event$$1.altKey)) {  // if both are set, assume AltGr and skip it - #4096
39870                 if (event$$1.ctrlKey !== binding.event.modifiers.ctrlKey) return false;
39871                 if (event$$1.altKey !== binding.event.modifiers.altKey) return false;
39872             }
39873             if (event$$1.metaKey !== binding.event.modifiers.metaKey) return false;
39874             if (testShift && event$$1.shiftKey !== binding.event.modifiers.shiftKey) return false;
39875
39876             return true;
39877         }
39878     }
39879
39880
39881     function capture() {
39882         testBindings(true);
39883     }
39884
39885
39886     function bubble() {
39887         var tagName = select(event.target).node().tagName;
39888         if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
39889             return;
39890         }
39891         testBindings(false);
39892     }
39893
39894
39895     function keybinding(selection$$1) {
39896         selection$$1 = selection$$1 || select(document);
39897         selection$$1.on('keydown.capture' + namespace$$1, capture, true);
39898         selection$$1.on('keydown.bubble' + namespace$$1, bubble, false);
39899         return keybinding;
39900     }
39901
39902
39903     keybinding.off = function(selection$$1) {
39904         bindings = [];
39905         selection$$1 = selection$$1 || select(document);
39906         selection$$1.on('keydown.capture' + namespace$$1, null);
39907         selection$$1.on('keydown.bubble' + namespace$$1, null);
39908         return keybinding;
39909     };
39910
39911
39912     keybinding.on = function(codes, callback, capture) {
39913         var arr = [].concat(codes);
39914         for (var i = 0; i < arr.length; i++) {
39915             var code = arr[i];
39916             var binding = {
39917                 event: {
39918                     key: undefined,
39919                     keyCode: 0, // only for browsers that don't support KeyboardEvent.key
39920                     modifiers: {
39921                         shiftKey: false,
39922                         ctrlKey: false,
39923                         altKey: false,
39924                         metaKey: false
39925                     }
39926                 },
39927                 capture: capture,
39928                 callback: callback
39929             };
39930
39931             code = code.toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
39932
39933             for (var j = 0; j < code.length; j++) {
39934                 // Normalise matching errors
39935                 if (code[j] === '++') code[j] = '+';
39936
39937                 if (code[j] in d3keybinding.modifierCodes) {
39938                     binding.event.modifiers[d3keybinding.modifierProperties[d3keybinding.modifierCodes[code[j]]]] = true;
39939                 } else {
39940                     binding.event.key = d3keybinding.keys[code[j]] || code[j];
39941                     if (code[j] in d3keybinding.keyCodes) {
39942                         binding.event.keyCode = d3keybinding.keyCodes[code[j]];
39943                     }
39944                 }
39945             }
39946
39947             bindings.push(binding);
39948         }
39949
39950         return keybinding;
39951     };
39952
39953     return keybinding;
39954 }
39955
39956
39957 d3keybinding.modifierCodes = {
39958     // Shift key, ⇧
39959     '⇧': 16, shift: 16,
39960     // CTRL key, on Mac: ⌃
39961     '⌃': 17, ctrl: 17,
39962     // ALT key, on Mac: ⌥ (Alt)
39963     '⌥': 18, alt: 18, option: 18,
39964     // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
39965     '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
39966 };
39967
39968 d3keybinding.modifierProperties = {
39969     16: 'shiftKey',
39970     17: 'ctrlKey',
39971     18: 'altKey',
39972     91: 'metaKey'
39973 };
39974
39975 d3keybinding.keys = {
39976     // Backspace key, on Mac: ⌫ (Backspace)
39977     '⌫': 'Backspace', backspace: 'Backspace',
39978     // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
39979     '⇥': 'Tab', '⇆': 'Tab', tab: 'Tab',
39980     // Return key, ↩
39981     '↩': 'Enter', 'return': 'Enter', enter: 'Enter', '⌅': 'Enter',
39982     // Pause/Break key
39983     'pause': 'Pause', 'pause-break': 'Pause',
39984     // Caps Lock key, ⇪
39985     '⇪': 'CapsLock', caps: 'CapsLock', 'caps-lock': 'CapsLock',
39986     // Escape key, on Mac: ⎋, on Windows: Esc
39987     '⎋': ['Escape', 'Esc'], escape: ['Escape', 'Esc'], esc: ['Escape', 'Esc'],
39988     // Space key
39989     space: [' ', 'Spacebar'],
39990     // Page-Up key, or pgup, on Mac: ↖
39991     '↖': 'PageUp', pgup: 'PageUp', 'page-up': 'PageUp',
39992     // Page-Down key, or pgdown, on Mac: ↘
39993     '↘': 'PageDown', pgdown: 'PageDown', 'page-down': 'PageDown',
39994     // END key, on Mac: ⇟
39995     '⇟': 'End', end: 'End',
39996     // HOME key, on Mac: ⇞
39997     '⇞': 'Home', home: 'Home',
39998     // Insert key, or ins
39999     ins: 'Insert', insert: 'Insert',
40000     // Delete key, on Mac: ⌦ (Delete)
40001     '⌦': ['Delete', 'Del'], del: ['Delete', 'Del'], 'delete': ['Delete', 'Del'],
40002     // Left Arrow Key, or ←
40003     '←': ['ArrowLeft', 'Left'], left: ['ArrowLeft', 'Left'], 'arrow-left': ['ArrowLeft', 'Left'],
40004     // Up Arrow Key, or ↑
40005     '↑': ['ArrowUp', 'Up'], up: ['ArrowUp', 'Up'], 'arrow-up': ['ArrowUp', 'Up'],
40006     // Right Arrow Key, or →
40007     '→': ['ArrowRight', 'Right'], right: ['ArrowRight', 'Right'], 'arrow-right': ['ArrowRight', 'Right'],
40008     // Up Arrow Key, or ↓
40009     '↓': ['ArrowDown', 'Down'], down: ['ArrowDown', 'Down'], 'arrow-down': ['ArrowDown', 'Down'],
40010     // odities, stuff for backward compatibility (browsers and code):
40011     // Num-Multiply, or *
40012     '*': ['*', 'Multiply'], star: ['*', 'Multiply'], asterisk: ['*', 'Multiply'], multiply: ['*', 'Multiply'],
40013     // Num-Plus or +
40014     '+': ['+', 'Add'], 'plus': ['+', 'Add'],
40015     // Num-Subtract, or -
40016     '-': ['-', 'Subtract'], subtract: ['-', 'Subtract'], 'dash': ['-', 'Subtract'],
40017     // Semicolon
40018     semicolon: ';',
40019     // = or equals
40020     equals: '=',
40021     // Comma, or ,
40022     comma: ',',
40023     // Period, or ., or full-stop
40024     period: '.', 'full-stop': '.',
40025     // Slash, or /, or forward-slash
40026     slash: '/', 'forward-slash': '/',
40027     // Tick, or `, or back-quote
40028     tick: '`', 'back-quote': '`',
40029     // Open bracket, or [
40030     'open-bracket': '[',
40031     // Back slash, or \
40032     'back-slash': '\\',
40033     // Close backet, or ]
40034     'close-bracket': ']',
40035     // Apostrophe, or Quote, or '
40036     quote: '\'', apostrophe: '\'',
40037     // NUMPAD 0-9
40038     'num-0': '0',
40039     'num-1': '1',
40040     'num-2': '2',
40041     'num-3': '3',
40042     'num-4': '4',
40043     'num-5': '5',
40044     'num-6': '6',
40045     'num-7': '7',
40046     'num-8': '8',
40047     'num-9': '9',
40048     // F1-F25
40049     f1: 'F1',
40050     f2: 'F2',
40051     f3: 'F3',
40052     f4: 'F4',
40053     f5: 'F5',
40054     f6: 'F6',
40055     f7: 'F7',
40056     f8: 'F8',
40057     f9: 'F9',
40058     f10: 'F10',
40059     f11: 'F11',
40060     f12: 'F12',
40061     f13: 'F13',
40062     f14: 'F14',
40063     f15: 'F15',
40064     f16: 'F16',
40065     f17: 'F17',
40066     f18: 'F18',
40067     f19: 'F19',
40068     f20: 'F20',
40069     f21: 'F21',
40070     f22: 'F22',
40071     f23: 'F23',
40072     f24: 'F24',
40073     f25: 'F25'
40074 };
40075
40076 d3keybinding.keyCodes = {
40077     // Backspace key, on Mac: ⌫ (Backspace)
40078     '⌫': 8, backspace: 8,
40079     // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
40080     '⇥': 9, '⇆': 9, tab: 9,
40081     // Return key, ↩
40082     '↩': 13, 'return': 13, enter: 13, '⌅': 13,
40083     // Pause/Break key
40084     'pause': 19, 'pause-break': 19,
40085     // Caps Lock key, ⇪
40086     '⇪': 20, caps: 20, 'caps-lock': 20,
40087     // Escape key, on Mac: ⎋, on Windows: Esc
40088     '⎋': 27, escape: 27, esc: 27,
40089     // Space key
40090     space: 32,
40091     // Page-Up key, or pgup, on Mac: ↖
40092     '↖': 33, pgup: 33, 'page-up': 33,
40093     // Page-Down key, or pgdown, on Mac: ↘
40094     '↘': 34, pgdown: 34, 'page-down': 34,
40095     // END key, on Mac: ⇟
40096     '⇟': 35, end: 35,
40097     // HOME key, on Mac: ⇞
40098     '⇞': 36, home: 36,
40099     // Insert key, or ins
40100     ins: 45, insert: 45,
40101     // Delete key, on Mac: ⌦ (Delete)
40102     '⌦': 46, del: 46, 'delete': 46,
40103     // Left Arrow Key, or ←
40104     '←': 37, left: 37, 'arrow-left': 37,
40105     // Up Arrow Key, or ↑
40106     '↑': 38, up: 38, 'arrow-up': 38,
40107     // Right Arrow Key, or →
40108     '→': 39, right: 39, 'arrow-right': 39,
40109     // Up Arrow Key, or ↓
40110     '↓': 40, down: 40, 'arrow-down': 40,
40111     // odities, printing characters that come out wrong:
40112     // Firefox Equals
40113     'ffequals': 61,
40114     // Num-Multiply, or *
40115     '*': 106, star: 106, asterisk: 106, multiply: 106,
40116     // Num-Plus or +
40117     '+': 107, 'plus': 107,
40118     // Num-Subtract, or -
40119     '-': 109, subtract: 109,
40120     // Firefox Plus
40121     'ffplus': 171,
40122     // Firefox Minus
40123     'ffminus': 173,
40124     // Semicolon
40125     ';': 186, semicolon: 186,
40126     // = or equals
40127     '=': 187, 'equals': 187,
40128     // Comma, or ,
40129     ',': 188, comma: 188,
40130     // Dash / Underscore key
40131     'dash': 189,
40132     // Period, or ., or full-stop
40133     '.': 190, period: 190, 'full-stop': 190,
40134     // Slash, or /, or forward-slash
40135     '/': 191, slash: 191, 'forward-slash': 191,
40136     // Tick, or `, or back-quote
40137     '`': 192, tick: 192, 'back-quote': 192,
40138     // Open bracket, or [
40139     '[': 219, 'open-bracket': 219,
40140     // Back slash, or \
40141     '\\': 220, 'back-slash': 220,
40142     // Close backet, or ]
40143     ']': 221, 'close-bracket': 221,
40144     // Apostrophe, or Quote, or '
40145     '\'': 222, quote: 222, apostrophe: 222
40146 };
40147
40148 // NUMPAD 0-9
40149 var i$1 = 95;
40150 var n = 0;
40151 while (++i$1 < 106) {
40152     d3keybinding.keyCodes['num-' + n] = i$1;
40153     ++n;
40154 }
40155
40156 // 0-9
40157 i$1 = 47; n = 0;
40158 while (++i$1 < 58) {
40159     d3keybinding.keyCodes[n] = i$1;
40160     ++n;
40161 }
40162
40163 // F1-F25
40164 i$1 = 111; n = 1;
40165 while (++i$1 < 136) {
40166     d3keybinding.keyCodes['f' + n] = i$1;
40167     ++n;
40168 }
40169
40170 // a-z
40171 i$1 = 64;
40172 while (++i$1 < 91) {
40173     d3keybinding.keyCodes[String.fromCharCode(i$1).toLowerCase()] = i$1;
40174 }
40175
40176 function tooltip() {
40177   var tooltip = function(selection$$1) {
40178       selection$$1.each(setup);
40179     },
40180     animation = utilFunctor(false),
40181     html$$1 = utilFunctor(false),
40182     title = function() {
40183       var title = this.getAttribute('data-original-title');
40184       if (title) {
40185         return title;
40186       } else {
40187         title = this.getAttribute('title');
40188         this.removeAttribute('title');
40189         this.setAttribute('data-original-title', title);
40190       }
40191       return title;
40192     },
40193     over = 'mouseenter.tooltip',
40194     out = 'mouseleave.tooltip',
40195     placement = utilFunctor('top');
40196
40197
40198   tooltip.title = function(_) {
40199     if (arguments.length) {
40200       title = utilFunctor(_);
40201       return tooltip;
40202     } else {
40203       return title;
40204     }
40205   };
40206
40207
40208   tooltip.html = function(_) {
40209     if (arguments.length) {
40210       html$$1 = utilFunctor(_);
40211       return tooltip;
40212     } else {
40213       return html$$1;
40214     }
40215   };
40216
40217
40218   tooltip.placement = function(_) {
40219     if (arguments.length) {
40220       placement = utilFunctor(_);
40221       return tooltip;
40222     } else {
40223       return placement;
40224     }
40225   };
40226
40227
40228   tooltip.show = function(selection$$1) {
40229     selection$$1.each(show);
40230   };
40231
40232
40233   tooltip.hide = function(selection$$1) {
40234     selection$$1.each(hide);
40235   };
40236
40237
40238   tooltip.toggle = function(selection$$1) {
40239     selection$$1.each(toggle);
40240   };
40241
40242
40243   tooltip.destroy = function(selection$$1) {
40244     selection$$1
40245       .on(over, null)
40246       .on(out, null)
40247       .attr('title', function() {
40248         return this.getAttribute('data-original-title') || this.getAttribute('title');
40249       })
40250       .attr('data-original-title', null)
40251       .selectAll('.tooltip')
40252       .remove();
40253   };
40254
40255
40256   function setup() {
40257     var root = select(this),
40258         animate = animation.apply(this, arguments),
40259         tip = root.selectAll('.tooltip').data([0]);
40260
40261     var enter = tip.enter()
40262       .append('div')
40263       .attr('class', 'tooltip');
40264
40265     enter
40266       .append('div')
40267       .attr('class', 'tooltip-arrow');
40268
40269     enter
40270       .append('div')
40271       .attr('class', 'tooltip-inner');
40272
40273     tip = enter
40274       .merge(tip);
40275
40276     if (animate) {
40277       tip.classed('fade', true);
40278     }
40279
40280     var place = placement.apply(this, arguments);
40281     tip.classed(place, true);
40282
40283     root.on(over, show);
40284     root.on(out, hide);
40285   }
40286
40287
40288   function show() {
40289     var root = select(this),
40290       content = title.apply(this, arguments),
40291       tip = root.selectAll('.tooltip')
40292         .classed('in', true),
40293       markup = html$$1.apply(this, arguments);
40294
40295     tip.selectAll('.tooltip-inner')[markup ? 'html' : 'text'](content);
40296     var place = placement.apply(this, arguments),
40297       outer = getPosition(root.node()),
40298       inner = getPosition(tip.node()),
40299       pos;
40300
40301     switch (place) {
40302       case 'top':
40303         pos = {x: outer.x + (outer.w - inner.w) / 2, y: outer.y - inner.h};
40304         break;
40305       case 'right':
40306         pos = {x: outer.x + outer.w, y: outer.y + (outer.h - inner.h) / 2};
40307         break;
40308       case 'left':
40309         pos = {x: outer.x - inner.w, y: outer.y + (outer.h - inner.h) / 2};
40310         break;
40311       case 'bottom':
40312         pos = {x: Math.max(0, outer.x + (outer.w - inner.w) / 2), y: outer.y + outer.h};
40313         break;
40314     }
40315
40316     if (pos) {
40317       tip.style('left', ~~pos.x + 'px').style('top', ~~pos.y + 'px');
40318     } else {
40319       tip.style('left', null).style('top', null);
40320     }
40321
40322     this.tooltipVisible = true;
40323   }
40324
40325
40326   function hide() {
40327     select(this).selectAll('.tooltip')
40328       .classed('in', false);
40329
40330     this.tooltipVisible = false;
40331   }
40332
40333
40334   function toggle() {
40335     if (this.tooltipVisible) {
40336       hide.apply(this, arguments);
40337     } else {
40338       show.apply(this, arguments);
40339     }
40340   }
40341
40342   return tooltip;
40343 }
40344
40345
40346 function getPosition(node) {
40347   var mode = select(node).style('position');
40348   if (mode === 'absolute' || mode === 'static') {
40349     return {
40350       x: node.offsetLeft,
40351       y: node.offsetTop,
40352       w: node.offsetWidth,
40353       h: node.offsetHeight
40354     };
40355   } else {
40356     return {
40357       x: 0,
40358       y: 0,
40359       w: node.offsetWidth,
40360       h: node.offsetHeight
40361     };
40362   }
40363 }
40364
40365 function svgAreas$$1(projection$$1, context) {
40366     // Patterns only work in Firefox when set directly on element.
40367     // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
40368     var patterns = {
40369         beach: 'beach',
40370         cemetery: 'cemetery',
40371         construction: 'construction',
40372         farm: 'farmland',
40373         farmland: 'farmland',
40374         grave_yard: 'cemetery',
40375         meadow: 'meadow',
40376         military: 'construction',
40377         orchard: 'orchard',
40378         sand: 'beach',
40379         scrub: 'scrub',
40380         wetland: 'wetland',
40381     };
40382
40383     var patternKeys = ['landuse', 'natural', 'amenity'];
40384
40385
40386     function setPattern(d) {
40387         for (var i = 0; i < patternKeys.length; i++) {
40388             if (d.tags.building && d.tags.building !== 'no') continue;
40389
40390             if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
40391                 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
40392                 return;
40393             }
40394         }
40395         this.style.fill = this.style.stroke = '';
40396     }
40397
40398
40399     return function drawAreas(selection$$1, graph, entities, filter) {
40400         var path$$1 = svgPath(projection$$1, graph, true),
40401             areas = {},
40402             multipolygon;
40403
40404         for (var i = 0; i < entities.length; i++) {
40405             var entity = entities[i];
40406             if (entity.geometry(graph) !== 'area') continue;
40407
40408             multipolygon = osmIsSimpleMultipolygonOuterMember(entity, graph);
40409             if (multipolygon) {
40410                 areas[multipolygon.id] = {
40411                     entity: multipolygon.mergeTags(entity.tags),
40412                     area: Math.abs(entity.area(graph))
40413                 };
40414             } else if (!areas[entity.id]) {
40415                 areas[entity.id] = {
40416                     entity: entity,
40417                     area: Math.abs(entity.area(graph))
40418                 };
40419             }
40420         }
40421
40422         areas = values(areas).filter(function hasPath(a) { return path$$1(a.entity); });
40423         areas.sort(function areaSort(a, b) { return b.area - a.area; });
40424         areas = lodash.map(areas, 'entity');
40425
40426         var strokes = areas.filter(function(area$$1) {
40427             return area$$1.type === 'way';
40428         });
40429
40430         var data = {
40431             clip: areas,
40432             shadow: strokes,
40433             stroke: strokes,
40434             fill: areas
40435         };
40436
40437         var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath')
40438            .filter(filter)
40439            .data(data.clip, osmEntity$$1.key);
40440
40441         clipPaths.exit()
40442            .remove();
40443
40444         var clipPathsEnter = clipPaths.enter()
40445            .append('clipPath')
40446            .attr('class', 'clipPath')
40447            .attr('id', function(entity) { return entity.id + '-clippath'; });
40448
40449         clipPathsEnter
40450            .append('path');
40451
40452         clipPaths.merge(clipPathsEnter)
40453            .selectAll('path')
40454            .attr('d', path$$1);
40455
40456
40457         var layer = selection$$1.selectAll('.layer-areas');
40458
40459         var areagroup = layer
40460             .selectAll('g.areagroup')
40461             .data(['fill', 'shadow', 'stroke']);
40462
40463         areagroup = areagroup.enter()
40464             .append('g')
40465             .attr('class', function(d) { return 'areagroup area-' + d; })
40466             .merge(areagroup);
40467
40468         var paths = areagroup
40469             .selectAll('path')
40470             .filter(filter)
40471             .data(function(layer) { return data[layer]; }, osmEntity$$1.key);
40472
40473         paths.exit()
40474             .remove();
40475
40476         var fills = selection$$1.selectAll('.area-fill path.area').nodes();
40477
40478         var bisect = bisector(function(node) {
40479             return -node.__data__.area(graph);
40480         }).left;
40481
40482         function sortedByArea(entity) {
40483             if (this._parent.__data__ === 'fill') {
40484                 return fills[bisect(fills, -entity.area(graph))];
40485             }
40486         }
40487
40488         paths = paths.enter()
40489             .insert('path', sortedByArea)
40490             .merge(paths)
40491             .each(function(entity) {
40492                 var layer = this.parentNode.__data__;
40493
40494                 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
40495
40496                 if (layer === 'fill') {
40497                     this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
40498                     setPattern.apply(this, arguments);
40499                 }
40500             })
40501             .call(svgTagClasses())
40502             .attr('d', path$$1);
40503     };
40504 }
40505
40506 function svgDebug(projection$$1, context) {
40507
40508     function multipolygons(imagery) {
40509         return imagery.map(function(data$$1) {
40510             return {
40511                 type: 'MultiPolygon',
40512                 coordinates: [ data$$1.polygon ]
40513             };
40514         });
40515     }
40516
40517     function drawDebug(selection$$1) {
40518         var showsTile = context.getDebug('tile'),
40519             showsCollision = context.getDebug('collision'),
40520             showsImagery = context.getDebug('imagery'),
40521             showsImperial = context.getDebug('imperial'),
40522             showsDriveLeft = context.getDebug('driveLeft'),
40523             path$$1 = index$4(projection$$1);
40524
40525
40526         var debugData = [];
40527         if (showsTile) {
40528             debugData.push({ class: 'red', label: 'tile' });
40529         }
40530         if (showsCollision) {
40531             debugData.push({ class: 'yellow', label: 'collision' });
40532         }
40533         if (showsImagery) {
40534             debugData.push({ class: 'orange', label: 'imagery' });
40535         }
40536         if (showsImperial) {
40537             debugData.push({ class: 'cyan', label: 'imperial' });
40538         }
40539         if (showsDriveLeft) {
40540             debugData.push({ class: 'green', label: 'driveLeft' });
40541         }
40542
40543
40544         var legend = select('#content')
40545             .selectAll('.debug-legend')
40546             .data(debugData.length ? [0] : []);
40547
40548         legend.exit()
40549             .remove();
40550
40551         legend = legend.enter()
40552             .append('div')
40553             .attr('class', 'fillD debug-legend')
40554             .merge(legend);
40555
40556
40557         var legendItems = legend.selectAll('.debug-legend-item')
40558             .data(debugData, function(d) { return d.label; });
40559
40560         legendItems.exit()
40561             .remove();
40562
40563         legendItems.enter()
40564             .append('span')
40565             .attr('class', function(d) { return 'debug-legend-item ' + d.class; })
40566             .text(function(d) { return d.label; });
40567
40568
40569         var layer = selection$$1.selectAll('.layer-debug')
40570             .data(showsImagery || showsImperial || showsDriveLeft ? [0] : []);
40571
40572         layer.exit()
40573             .remove();
40574
40575         layer = layer.enter()
40576             .append('g')
40577             .attr('class', 'layer-debug')
40578             .merge(layer);
40579
40580
40581         var extent$$1 = context.map().extent(),
40582             dataImagery = data.imagery || [],
40583             availableImagery = showsImagery && multipolygons(dataImagery.filter(function(source) {
40584                 if (!source.polygon) return false;
40585                 return source.polygon.some(function(polygon) {
40586                     return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
40587                 });
40588             }));
40589
40590         var imagery = layer.selectAll('path.debug-imagery')
40591             .data(showsImagery ? availableImagery : []);
40592
40593         imagery.exit()
40594             .remove();
40595
40596         imagery.enter()
40597             .append('path')
40598             .attr('class', 'debug-imagery debug orange');
40599
40600
40601         var imperial = layer
40602             .selectAll('path.debug-imperial')
40603             .data(showsImperial ? [dataImperial] : []);
40604
40605         imperial.exit()
40606             .remove();
40607
40608         imperial.enter()
40609             .append('path')
40610             .attr('class', 'debug-imperial debug cyan');
40611
40612
40613         var driveLeft = layer
40614             .selectAll('path.debug-drive-left')
40615             .data(showsDriveLeft ? [dataDriveLeft] : []);
40616
40617         driveLeft.exit()
40618             .remove();
40619
40620         driveLeft.enter()
40621             .append('path')
40622             .attr('class', 'debug-drive-left debug green');
40623
40624
40625         // update
40626         layer.selectAll('path')
40627             .attr('d', path$$1);
40628     }
40629
40630
40631     // This looks strange because `enabled` methods on other layers are
40632     // chainable getter/setters, and this one is just a getter.
40633     drawDebug.enabled = function() {
40634         if (!arguments.length) {
40635             return context.getDebug('tile') ||
40636                 context.getDebug('collision') ||
40637                 context.getDebug('imagery') ||
40638                 context.getDebug('imperial') ||
40639                 context.getDebug('driveLeft');
40640         } else {
40641             return this;
40642         }
40643     };
40644
40645
40646     return drawDebug;
40647 }
40648
40649 /*
40650     A standalone SVG element that contains only a `defs` sub-element. To be
40651     used once globally, since defs IDs must be unique within a document.
40652 */
40653 function svgDefs(context) {
40654
40655     function SVGSpriteDefinition(id, href) {
40656         return function(defs) {
40657             request(href)
40658                 .mimeType('image/svg+xml')
40659                 .response(function(xhr) { return xhr.responseXML; })
40660                 .get(function(err, svg) {
40661                     if (err) return;
40662                     defs.node().appendChild(
40663                         select(svg.documentElement).attr('id', id).node()
40664                     );
40665                 });
40666         };
40667     }
40668
40669
40670     return function drawDefs(selection$$1) {
40671         var defs = selection$$1.append('defs');
40672
40673         // marker
40674         defs.append('marker')
40675             .attr('id', 'oneway-marker')
40676             .attr('viewBox', '0 0 10 10')
40677             .attr('refY', 2.5)
40678             .attr('refX', 5)
40679             .attr('markerWidth', 2)
40680             .attr('markerHeight', 2)
40681             .attr('markerUnits', 'strokeWidth')
40682             .attr('orient', 'auto')
40683
40684             .append('path')
40685             .attr('class', 'oneway')
40686             .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')
40687             .attr('stroke', 'none')
40688             .attr('fill', '#000')
40689             .attr('opacity', '0.75');
40690
40691         // patterns
40692         var patterns = defs.selectAll('pattern')
40693             .data([
40694                 // pattern name, pattern image name
40695                 ['wetland', 'wetland'],
40696                 ['construction', 'construction'],
40697                 ['cemetery', 'cemetery'],
40698                 ['orchard', 'orchard'],
40699                 ['farmland', 'farmland'],
40700                 ['beach', 'dots'],
40701                 ['scrub', 'dots'],
40702                 ['meadow', 'dots']
40703             ])
40704             .enter()
40705             .append('pattern')
40706             .attr('id', function (d) {
40707                 return 'pattern-' + d[0];
40708             })
40709             .attr('width', 32)
40710             .attr('height', 32)
40711             .attr('patternUnits', 'userSpaceOnUse');
40712
40713         patterns.append('rect')
40714             .attr('x', 0)
40715             .attr('y', 0)
40716             .attr('width', 32)
40717             .attr('height', 32)
40718             .attr('class', function (d) {
40719                     return 'pattern-color-' + d[0];
40720             });
40721
40722         patterns.append('image')
40723             .attr('x', 0)
40724             .attr('y', 0)
40725             .attr('width', 32)
40726             .attr('height', 32)
40727             .attr('xlink:href', function (d) {
40728                 return context.imagePath('pattern/' + d[1] + '.png');
40729             });
40730
40731         // clip paths
40732         defs.selectAll()
40733             .data([12, 18, 20, 32, 45])
40734             .enter()
40735             .append('clipPath')
40736             .attr('id', function (d) {
40737                 return 'clip-square-' + d;
40738             })
40739             .append('rect')
40740             .attr('x', 0)
40741             .attr('y', 0)
40742             .attr('width', function (d) {
40743                 return d;
40744             })
40745             .attr('height', function (d) {
40746                 return d;
40747             });
40748
40749         defs.call(SVGSpriteDefinition(
40750             'iD-sprite',
40751             context.imagePath('iD-sprite.svg')));
40752
40753         defs.call(SVGSpriteDefinition(
40754             'maki-sprite',
40755             context.imagePath('maki-sprite.svg')));
40756     };
40757 }
40758
40759 //[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]
40760 //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
40761 //[5]           Name       ::=          NameStartChar (NameChar)*
40762 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
40763 var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
40764 var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
40765 //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
40766 //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(',')
40767
40768 //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
40769 //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
40770 var S_TAG = 0;//tag name offerring
40771 var S_ATTR = 1;//attr name offerring 
40772 var S_ATTR_SPACE=2;//attr name end and space offer
40773 var S_EQ = 3;//=space?
40774 var S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)
40775 var S_ATTR_END = 5;//attr value end and no space(quot end)
40776 var S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)
40777 var S_TAG_CLOSE = 7;//closed el<el />
40778
40779 function XMLReader(){
40780         
40781 }
40782
40783 XMLReader.prototype = {
40784         parse:function(source,defaultNSMap,entityMap){
40785                 var domBuilder = this.domBuilder;
40786                 domBuilder.startDocument();
40787                 _copy(defaultNSMap ,defaultNSMap = {});
40788                 parse(source,defaultNSMap,entityMap,
40789                                 domBuilder,this.errorHandler);
40790                 domBuilder.endDocument();
40791         }
40792 };
40793 function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
40794         function fixedFromCharCode(code) {
40795                 // String.prototype.fromCharCode does not supports
40796                 // > 2 bytes unicode chars directly
40797                 if (code > 0xffff) {
40798                         code -= 0x10000;
40799                         var surrogate1 = 0xd800 + (code >> 10)
40800                                 , surrogate2 = 0xdc00 + (code & 0x3ff);
40801
40802                         return String.fromCharCode(surrogate1, surrogate2);
40803                 } else {
40804                         return String.fromCharCode(code);
40805                 }
40806         }
40807         function entityReplacer(a){
40808                 var k = a.slice(1,-1);
40809                 if(k in entityMap){
40810                         return entityMap[k]; 
40811                 }else if(k.charAt(0) === '#'){
40812                         return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))
40813                 }else{
40814                         errorHandler.error('entity not found:'+a);
40815                         return a;
40816                 }
40817         }
40818         function appendText(end){//has some bugs
40819                 if(end>start){
40820                         var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer);
40821                         locator&&position(start);
40822                         domBuilder.characters(xt,0,end-start);
40823                         start = end;
40824                 }
40825         }
40826         function position(p,m){
40827                 while(p>=lineEnd && (m = linePattern.exec(source))){
40828                         lineStart = m.index;
40829                         lineEnd = lineStart + m[0].length;
40830                         locator.lineNumber++;
40831                         //console.log('line++:',locator,startPos,endPos)
40832                 }
40833                 locator.columnNumber = p-lineStart+1;
40834         }
40835         var lineStart = 0;
40836         var lineEnd = 0;
40837         var linePattern = /.*(?:\r\n?|\n)|.*$/g;
40838         var locator = domBuilder.locator;
40839         
40840         var parseStack = [{currentNSMap:defaultNSMapCopy}];
40841         var closeMap = {};
40842         var start = 0;
40843         while(true){
40844                 try{
40845                         var tagStart = source.indexOf('<',start);
40846                         if(tagStart<0){
40847                                 if(!source.substr(start).match(/^\s*$/)){
40848                                         var doc = domBuilder.doc;
40849                                 var text = doc.createTextNode(source.substr(start));
40850                                 doc.appendChild(text);
40851                                 domBuilder.currentElement = text;
40852                                 }
40853                                 return;
40854                         }
40855                         if(tagStart>start){
40856                                 appendText(tagStart);
40857                         }
40858                         switch(source.charAt(tagStart+1)){
40859                         case '/':
40860                                 var end = source.indexOf('>',tagStart+3);
40861                                 var tagName = source.substring(tagStart+2,end);
40862                                 var config = parseStack.pop();
40863                                 if(end<0){
40864                                         
40865                                 tagName = source.substring(tagStart+2).replace(/[\s<].*/,'');
40866                                 //console.error('#@@@@@@'+tagName)
40867                                 errorHandler.error("end tag name: "+tagName+' is not complete:'+config.tagName);
40868                                 end = tagStart+1+tagName.length;
40869                         }else if(tagName.match(/\s</)){
40870                                 tagName = tagName.replace(/[\s<].*/,'');
40871                                 errorHandler.error("end tag name: "+tagName+' maybe not complete');
40872                                 end = tagStart+1+tagName.length;
40873                                 }
40874                                 //console.error(parseStack.length,parseStack)
40875                                 //console.error(config);
40876                                 var localNSMap = config.localNSMap;
40877                                 var endMatch = config.tagName == tagName;
40878                                 var endIgnoreCaseMach = endMatch || config.tagName&&config.tagName.toLowerCase() == tagName.toLowerCase();
40879                         if(endIgnoreCaseMach){
40880                                 domBuilder.endElement(config.uri,config.localName,tagName);
40881                                         if(localNSMap){
40882                                                 for(var prefix in localNSMap){
40883                                                         domBuilder.endPrefixMapping(prefix) ;
40884                                                 }
40885                                         }
40886                                         if(!endMatch){
40887                                 errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName );
40888                                         }
40889                         }else{
40890                                 parseStack.push(config);
40891                         }
40892                                 
40893                                 end++;
40894                                 break;
40895                                 // end elment
40896                         case '?':// <?...?>
40897                                 locator&&position(tagStart);
40898                                 end = parseInstruction(source,tagStart,domBuilder);
40899                                 break;
40900                         case '!':// <!doctype,<![CDATA,<!--
40901                                 locator&&position(tagStart);
40902                                 end = parseDCC(source,tagStart,domBuilder,errorHandler);
40903                                 break;
40904                         default:
40905                                 locator&&position(tagStart);
40906                                 var el = new ElementAttributes();
40907                                 var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
40908                                 //elStartEnd
40909                                 var end = parseElementStartPart(source,tagStart,el,currentNSMap,entityReplacer,errorHandler);
40910                                 var len = el.length;
40911                                 
40912                                 
40913                                 if(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){
40914                                         el.closed = true;
40915                                         if(!entityMap.nbsp){
40916                                                 errorHandler.warning('unclosed xml attribute');
40917                                         }
40918                                 }
40919                                 if(locator && len){
40920                                         var locator2 = copyLocator(locator,{});
40921                                         //try{//attribute position fixed
40922                                         for(var i = 0;i<len;i++){
40923                                                 var a = el[i];
40924                                                 position(a.offset);
40925                                                 a.locator = copyLocator(locator,{});
40926                                         }
40927                                         //}catch(e){console.error('@@@@@'+e)}
40928                                         domBuilder.locator = locator2;
40929                                         if(appendElement(el,domBuilder,currentNSMap)){
40930                                                 parseStack.push(el);
40931                                         }
40932                                         domBuilder.locator = locator;
40933                                 }else{
40934                                         if(appendElement(el,domBuilder,currentNSMap)){
40935                                                 parseStack.push(el);
40936                                         }
40937                                 }
40938                                 
40939                                 
40940                                 
40941                                 if(el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed){
40942                                         end = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder);
40943                                 }else{
40944                                         end++;
40945                                 }
40946                         }
40947                 }catch(e){
40948                         errorHandler.error('element parse error: '+e);
40949                         //errorHandler.error('element parse error: '+e);
40950                         end = -1;
40951                         //throw e;
40952                 }
40953                 if(end>start){
40954                         start = end;
40955                 }else{
40956                         //TODO: 这里有可能sax回退,有位置错误风险
40957                         appendText(Math.max(tagStart,start)+1);
40958                 }
40959         }
40960 }
40961 function copyLocator(f,t){
40962         t.lineNumber = f.lineNumber;
40963         t.columnNumber = f.columnNumber;
40964         return t;
40965 }
40966
40967 /**
40968  * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
40969  * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
40970  */
40971 function parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){
40972         var attrName;
40973         var value;
40974         var p = ++start;
40975         var s = S_TAG;//status
40976         while(true){
40977                 var c = source.charAt(p);
40978                 switch(c){
40979                 case '=':
40980                         if(s === S_ATTR){//attrName
40981                                 attrName = source.slice(start,p);
40982                                 s = S_EQ;
40983                         }else if(s === S_ATTR_SPACE){
40984                                 s = S_EQ;
40985                         }else{
40986                                 //fatalError: equal must after attrName or space after attrName
40987                                 throw new Error('attribute equal must after attrName');
40988                         }
40989                         break;
40990                 case '\'':
40991                 case '"':
40992                         if(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
40993                                 ){//equal
40994                                 if(s === S_ATTR){
40995                                         errorHandler.warning('attribute value must after "="');
40996                                         attrName = source.slice(start,p);
40997                                 }
40998                                 start = p+1;
40999                                 p = source.indexOf(c,start);
41000                                 if(p>0){
41001                                         value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
41002                                         el.add(attrName,value,start-1);
41003                                         s = S_ATTR_END;
41004                                 }else{
41005                                         //fatalError: no end quot match
41006                                         throw new Error('attribute value no end \''+c+'\' match');
41007                                 }
41008                         }else if(s == S_ATTR_NOQUOT_VALUE){
41009                                 value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
41010                                 //console.log(attrName,value,start,p)
41011                                 el.add(attrName,value,start);
41012                                 //console.dir(el)
41013                                 errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
41014                                 start = p+1;
41015                                 s = S_ATTR_END;
41016                         }else{
41017                                 //fatalError: no equal before
41018                                 throw new Error('attribute value must after "="');
41019                         }
41020                         break;
41021                 case '/':
41022                         switch(s){
41023                         case S_TAG:
41024                                 el.setTagName(source.slice(start,p));
41025                         case S_ATTR_END:
41026                         case S_TAG_SPACE:
41027                         case S_TAG_CLOSE:
41028                                 s =S_TAG_CLOSE;
41029                                 el.closed = true;
41030                         case S_ATTR_NOQUOT_VALUE:
41031                         case S_ATTR:
41032                         case S_ATTR_SPACE:
41033                                 break;
41034                         //case S_EQ:
41035                         default:
41036                                 throw new Error("attribute invalid close char('/')")
41037                         }
41038                         break;
41039                 case ''://end document
41040                         //throw new Error('unexpected end of input')
41041                         errorHandler.error('unexpected end of input');
41042                         if(s == S_TAG){
41043                                 el.setTagName(source.slice(start,p));
41044                         }
41045                         return p;
41046                 case '>':
41047                         switch(s){
41048                         case S_TAG:
41049                                 el.setTagName(source.slice(start,p));
41050                         case S_ATTR_END:
41051                         case S_TAG_SPACE:
41052                         case S_TAG_CLOSE:
41053                                 break;//normal
41054                         case S_ATTR_NOQUOT_VALUE://Compatible state
41055                         case S_ATTR:
41056                                 value = source.slice(start,p);
41057                                 if(value.slice(-1) === '/'){
41058                                         el.closed  = true;
41059                                         value = value.slice(0,-1);
41060                                 }
41061                         case S_ATTR_SPACE:
41062                                 if(s === S_ATTR_SPACE){
41063                                         value = attrName;
41064                                 }
41065                                 if(s == S_ATTR_NOQUOT_VALUE){
41066                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
41067                                         el.add(attrName,value.replace(/&#?\w+;/g,entityReplacer),start);
41068                                 }else{
41069                                         if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)){
41070                                                 errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!');
41071                                         }
41072                                         el.add(value,value,start);
41073                                 }
41074                                 break;
41075                         case S_EQ:
41076                                 throw new Error('attribute value missed!!');
41077                         }
41078 //                      console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
41079                         return p;
41080                 /*xml space '\x20' | #x9 | #xD | #xA; */
41081                 case '\u0080':
41082                         c = ' ';
41083                 default:
41084                         if(c<= ' '){//space
41085                                 switch(s){
41086                                 case S_TAG:
41087                                         el.setTagName(source.slice(start,p));//tagName
41088                                         s = S_TAG_SPACE;
41089                                         break;
41090                                 case S_ATTR:
41091                                         attrName = source.slice(start,p);
41092                                         s = S_ATTR_SPACE;
41093                                         break;
41094                                 case S_ATTR_NOQUOT_VALUE:
41095                                         var value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
41096                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
41097                                         el.add(attrName,value,start);
41098                                 case S_ATTR_END:
41099                                         s = S_TAG_SPACE;
41100                                         break;
41101                                 //case S_TAG_SPACE:
41102                                 //case S_EQ:
41103                                 //case S_ATTR_SPACE:
41104                                 //      void();break;
41105                                 //case S_TAG_CLOSE:
41106                                         //ignore warning
41107                                 }
41108                         }else{//not space
41109 //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
41110 //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
41111                                 switch(s){
41112                                 //case S_TAG:void();break;
41113                                 //case S_ATTR:void();break;
41114                                 //case S_ATTR_NOQUOT_VALUE:void();break;
41115                                 case S_ATTR_SPACE:
41116                                         var tagName =  el.tagName;
41117                                         if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)){
41118                                                 errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead2!!');
41119                                         }
41120                                         el.add(attrName,attrName,start);
41121                                         start = p;
41122                                         s = S_ATTR;
41123                                         break;
41124                                 case S_ATTR_END:
41125                                         errorHandler.warning('attribute space is required"'+attrName+'"!!');
41126                                 case S_TAG_SPACE:
41127                                         s = S_ATTR;
41128                                         start = p;
41129                                         break;
41130                                 case S_EQ:
41131                                         s = S_ATTR_NOQUOT_VALUE;
41132                                         start = p;
41133                                         break;
41134                                 case S_TAG_CLOSE:
41135                                         throw new Error("elements closed character '/' and '>' must be connected to");
41136                                 }
41137                         }
41138                 }//end outer switch
41139                 //console.log('p++',p)
41140                 p++;
41141         }
41142 }
41143 /**
41144  * @return true if has new namespace define
41145  */
41146 function appendElement(el,domBuilder,currentNSMap){
41147         var tagName = el.tagName;
41148         var localNSMap = null;
41149         //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
41150         var i = el.length;
41151         while(i--){
41152                 var a = el[i];
41153                 var qName = a.qName;
41154                 var value = a.value;
41155                 var nsp = qName.indexOf(':');
41156                 if(nsp>0){
41157                         var prefix = a.prefix = qName.slice(0,nsp);
41158                         var localName = qName.slice(nsp+1);
41159                         var nsPrefix = prefix === 'xmlns' && localName;
41160                 }else{
41161                         localName = qName;
41162                         prefix = null;
41163                         nsPrefix = qName === 'xmlns' && '';
41164                 }
41165                 //can not set prefix,because prefix !== ''
41166                 a.localName = localName ;
41167                 //prefix == null for no ns prefix attribute 
41168                 if(nsPrefix !== false){//hack!!
41169                         if(localNSMap == null){
41170                                 localNSMap = {};
41171                                 //console.log(currentNSMap,0)
41172                                 _copy(currentNSMap,currentNSMap={});
41173                                 //console.log(currentNSMap,1)
41174                         }
41175                         currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
41176                         a.uri = 'http://www.w3.org/2000/xmlns/';
41177                         domBuilder.startPrefixMapping(nsPrefix, value); 
41178                 }
41179         }
41180         var i = el.length;
41181         while(i--){
41182                 a = el[i];
41183                 var prefix = a.prefix;
41184                 if(prefix){//no prefix attribute has no namespace
41185                         if(prefix === 'xml'){
41186                                 a.uri = 'http://www.w3.org/XML/1998/namespace';
41187                         }if(prefix !== 'xmlns'){
41188                                 a.uri = currentNSMap[prefix || ''];
41189                                 
41190                                 //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
41191                         }
41192                 }
41193         }
41194         var nsp = tagName.indexOf(':');
41195         if(nsp>0){
41196                 prefix = el.prefix = tagName.slice(0,nsp);
41197                 localName = el.localName = tagName.slice(nsp+1);
41198         }else{
41199                 prefix = null;//important!!
41200                 localName = el.localName = tagName;
41201         }
41202         //no prefix element has default namespace
41203         var ns = el.uri = currentNSMap[prefix || ''];
41204         domBuilder.startElement(ns,localName,tagName,el);
41205         //endPrefixMapping and startPrefixMapping have not any help for dom builder
41206         //localNSMap = null
41207         if(el.closed){
41208                 domBuilder.endElement(ns,localName,tagName);
41209                 if(localNSMap){
41210                         for(prefix in localNSMap){
41211                                 domBuilder.endPrefixMapping(prefix); 
41212                         }
41213                 }
41214         }else{
41215                 el.currentNSMap = currentNSMap;
41216                 el.localNSMap = localNSMap;
41217                 //parseStack.push(el);
41218                 return true;
41219         }
41220 }
41221 function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
41222         if(/^(?:script|textarea)$/i.test(tagName)){
41223                 var elEndStart =  source.indexOf('</'+tagName+'>',elStartEnd);
41224                 var text = source.substring(elStartEnd+1,elEndStart);
41225                 if(/[&<]/.test(text)){
41226                         if(/^script$/i.test(tagName)){
41227                                 //if(!/\]\]>/.test(text)){
41228                                         //lexHandler.startCDATA();
41229                                         domBuilder.characters(text,0,text.length);
41230                                         //lexHandler.endCDATA();
41231                                         return elEndStart;
41232                                 //}
41233                         }//}else{//text area
41234                                 text = text.replace(/&#?\w+;/g,entityReplacer);
41235                                 domBuilder.characters(text,0,text.length);
41236                                 return elEndStart;
41237                         //}
41238                         
41239                 }
41240         }
41241         return elStartEnd+1;
41242 }
41243 function fixSelfClosed(source,elStartEnd,tagName,closeMap){
41244         //if(tagName in closeMap){
41245         var pos = closeMap[tagName];
41246         if(pos == null){
41247                 //console.log(tagName)
41248                 pos =  source.lastIndexOf('</'+tagName+'>');
41249                 if(pos<elStartEnd){//忘记闭合
41250                         pos = source.lastIndexOf('</'+tagName);
41251                 }
41252                 closeMap[tagName] =pos;
41253         }
41254         return pos<elStartEnd;
41255         //} 
41256 }
41257 function _copy(source,target){
41258         for(var n in source){target[n] = source[n];}
41259 }
41260 function parseDCC(source,start,domBuilder,errorHandler){//sure start with '<!'
41261         var next= source.charAt(start+2);
41262         switch(next){
41263         case '-':
41264                 if(source.charAt(start + 3) === '-'){
41265                         var end = source.indexOf('-->',start+4);
41266                         //append comment source.substring(4,end)//<!--
41267                         if(end>start){
41268                                 domBuilder.comment(source,start+4,end-start-4);
41269                                 return end+3;
41270                         }else{
41271                                 errorHandler.error("Unclosed comment");
41272                                 return -1;
41273                         }
41274                 }else{
41275                         //error
41276                         return -1;
41277                 }
41278         default:
41279                 if(source.substr(start+3,6) == 'CDATA['){
41280                         var end = source.indexOf(']]>',start+9);
41281                         domBuilder.startCDATA();
41282                         domBuilder.characters(source,start+9,end-start-9);
41283                         domBuilder.endCDATA(); 
41284                         return end+3;
41285                 }
41286                 //<!DOCTYPE
41287                 //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
41288                 var matchs = split(source,start);
41289                 var len = matchs.length;
41290                 if(len>1 && /!doctype/i.test(matchs[0][0])){
41291                         var name = matchs[1][0];
41292                         var pubid = len>3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
41293                         var sysid = len>4 && matchs[4][0];
41294                         var lastMatch = matchs[len-1];
41295                         domBuilder.startDTD(name,pubid && pubid.replace(/^(['"])(.*?)\1$/,'$2'),
41296                                         sysid && sysid.replace(/^(['"])(.*?)\1$/,'$2'));
41297                         domBuilder.endDTD();
41298                         
41299                         return lastMatch.index+lastMatch[0].length
41300                 }
41301         }
41302         return -1;
41303 }
41304
41305
41306
41307 function parseInstruction(source,start,domBuilder){
41308         var end = source.indexOf('?>',start);
41309         if(end){
41310                 var match = source.substring(start,end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
41311                 if(match){
41312                         var len = match[0].length;
41313                         domBuilder.processingInstruction(match[1], match[2]) ;
41314                         return end+2;
41315                 }else{//error
41316                         return -1;
41317                 }
41318         }
41319         return -1;
41320 }
41321
41322 /**
41323  * @param source
41324  */
41325 function ElementAttributes(source){
41326         
41327 }
41328 ElementAttributes.prototype = {
41329         setTagName:function(tagName){
41330                 if(!tagNamePattern.test(tagName)){
41331                         throw new Error('invalid tagName:'+tagName)
41332                 }
41333                 this.tagName = tagName;
41334         },
41335         add:function(qName,value,offset){
41336                 if(!tagNamePattern.test(qName)){
41337                         throw new Error('invalid attribute:'+qName)
41338                 }
41339                 this[this.length++] = {qName:qName,value:value,offset:offset};
41340         },
41341         length:0,
41342         getLocalName:function(i){return this[i].localName},
41343         getLocator:function(i){return this[i].locator},
41344         getQName:function(i){return this[i].qName},
41345         getURI:function(i){return this[i].uri},
41346         getValue:function(i){return this[i].value}
41347 //      ,getIndex:function(uri, localName)){
41348 //              if(localName){
41349 //                      
41350 //              }else{
41351 //                      var qName = uri
41352 //              }
41353 //      },
41354 //      getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
41355 //      getType:function(uri,localName){}
41356 //      getType:function(i){},
41357 };
41358
41359
41360
41361
41362 function _set_proto_(thiz,parent){
41363         thiz.__proto__ = parent;
41364         return thiz;
41365 }
41366 if(!(_set_proto_({},_set_proto_.prototype) instanceof _set_proto_)){
41367         _set_proto_ = function(thiz,parent){
41368                 function p(){}
41369                 p.prototype = parent;
41370                 p = new p();
41371                 for(parent in thiz){
41372                         p[parent] = thiz[parent];
41373                 }
41374                 return p;
41375         };
41376 }
41377
41378 function split(source,start){
41379         var match;
41380         var buf = [];
41381         var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
41382         reg.lastIndex = start;
41383         reg.exec(source);//skip <
41384         while(match = reg.exec(source)){
41385                 buf.push(match);
41386                 if(match[1])return buf;
41387         }
41388 }
41389
41390 var XMLReader_1 = XMLReader;
41391
41392 var sax = {
41393         XMLReader: XMLReader_1
41394 };
41395
41396 /*
41397  * DOM Level 2
41398  * Object DOMException
41399  * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
41400  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
41401  */
41402
41403 function copy$1(src,dest){
41404         for(var p in src){
41405                 dest[p] = src[p];
41406         }
41407 }
41408 /**
41409 ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
41410 ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
41411  */
41412 function _extends(Class,Super){
41413         var pt = Class.prototype;
41414         if(Object.create){
41415                 var ppt = Object.create(Super.prototype);
41416                 pt.__proto__ = ppt;
41417         }
41418         if(!(pt instanceof Super)){
41419                 function t(){}
41420                 t.prototype = Super.prototype;
41421                 t = new t();
41422                 copy$1(pt,t);
41423                 Class.prototype = pt = t;
41424         }
41425         if(pt.constructor != Class){
41426                 if(typeof Class != 'function'){
41427                         console.error("unknow Class:"+Class);
41428                 }
41429                 pt.constructor = Class;
41430         }
41431 }
41432 var htmlns = 'http://www.w3.org/1999/xhtml';
41433 // Node Types
41434 var NodeType = {};
41435 var ELEMENT_NODE                = NodeType.ELEMENT_NODE                = 1;
41436 var ATTRIBUTE_NODE              = NodeType.ATTRIBUTE_NODE              = 2;
41437 var TEXT_NODE                   = NodeType.TEXT_NODE                   = 3;
41438 var CDATA_SECTION_NODE          = NodeType.CDATA_SECTION_NODE          = 4;
41439 var ENTITY_REFERENCE_NODE       = NodeType.ENTITY_REFERENCE_NODE       = 5;
41440 var ENTITY_NODE                 = NodeType.ENTITY_NODE                 = 6;
41441 var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
41442 var COMMENT_NODE                = NodeType.COMMENT_NODE                = 8;
41443 var DOCUMENT_NODE               = NodeType.DOCUMENT_NODE               = 9;
41444 var DOCUMENT_TYPE_NODE          = NodeType.DOCUMENT_TYPE_NODE          = 10;
41445 var DOCUMENT_FRAGMENT_NODE      = NodeType.DOCUMENT_FRAGMENT_NODE      = 11;
41446 var NOTATION_NODE               = NodeType.NOTATION_NODE               = 12;
41447
41448 // ExceptionCode
41449 var ExceptionCode = {};
41450 var ExceptionMessage = {};
41451 var INDEX_SIZE_ERR              = ExceptionCode.INDEX_SIZE_ERR              = ((ExceptionMessage[1]="Index size error"),1);
41452 var DOMSTRING_SIZE_ERR          = ExceptionCode.DOMSTRING_SIZE_ERR          = ((ExceptionMessage[2]="DOMString size error"),2);
41453 var HIERARCHY_REQUEST_ERR       = ExceptionCode.HIERARCHY_REQUEST_ERR       = ((ExceptionMessage[3]="Hierarchy request error"),3);
41454 var WRONG_DOCUMENT_ERR          = ExceptionCode.WRONG_DOCUMENT_ERR          = ((ExceptionMessage[4]="Wrong document"),4);
41455 var INVALID_CHARACTER_ERR       = ExceptionCode.INVALID_CHARACTER_ERR       = ((ExceptionMessage[5]="Invalid character"),5);
41456 var NO_DATA_ALLOWED_ERR         = ExceptionCode.NO_DATA_ALLOWED_ERR         = ((ExceptionMessage[6]="No data allowed"),6);
41457 var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]="No modification allowed"),7);
41458 var NOT_FOUND_ERR               = ExceptionCode.NOT_FOUND_ERR               = ((ExceptionMessage[8]="Not found"),8);
41459 var NOT_SUPPORTED_ERR           = ExceptionCode.NOT_SUPPORTED_ERR           = ((ExceptionMessage[9]="Not supported"),9);
41460 var INUSE_ATTRIBUTE_ERR         = ExceptionCode.INUSE_ATTRIBUTE_ERR         = ((ExceptionMessage[10]="Attribute in use"),10);
41461 //level2
41462 var INVALID_STATE_ERR           = ExceptionCode.INVALID_STATE_ERR               = ((ExceptionMessage[11]="Invalid state"),11);
41463 var SYNTAX_ERR                  = ExceptionCode.SYNTAX_ERR                      = ((ExceptionMessage[12]="Syntax error"),12);
41464 var INVALID_MODIFICATION_ERR    = ExceptionCode.INVALID_MODIFICATION_ERR        = ((ExceptionMessage[13]="Invalid modification"),13);
41465 var NAMESPACE_ERR               = ExceptionCode.NAMESPACE_ERR                   = ((ExceptionMessage[14]="Invalid namespace"),14);
41466 var INVALID_ACCESS_ERR          = ExceptionCode.INVALID_ACCESS_ERR              = ((ExceptionMessage[15]="Invalid access"),15);
41467
41468
41469 function DOMException(code, message) {
41470         if(message instanceof Error){
41471                 var error = message;
41472         }else{
41473                 error = this;
41474                 Error.call(this, ExceptionMessage[code]);
41475                 this.message = ExceptionMessage[code];
41476                 if(Error.captureStackTrace) Error.captureStackTrace(this, DOMException);
41477         }
41478         error.code = code;
41479         if(message) this.message = this.message + ": " + message;
41480         return error;
41481 }
41482 DOMException.prototype = Error.prototype;
41483 copy$1(ExceptionCode,DOMException);
41484 /**
41485  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
41486  * 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.
41487  * The items in the NodeList are accessible via an integral index, starting from 0.
41488  */
41489 function NodeList() {
41490 }
41491 NodeList.prototype = {
41492         /**
41493          * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
41494          * @standard level1
41495          */
41496         length:0, 
41497         /**
41498          * 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.
41499          * @standard level1
41500          * @param index  unsigned long 
41501          *   Index into the collection.
41502          * @return Node
41503          *      The node at the indexth position in the NodeList, or null if that is not a valid index. 
41504          */
41505         item: function(index) {
41506                 return this[index] || null;
41507         },
41508         toString:function(isHTML,nodeFilter){
41509                 for(var buf = [], i = 0;i<this.length;i++){
41510                         serializeToString(this[i],buf,isHTML,nodeFilter);
41511                 }
41512                 return buf.join('');
41513         }
41514 };
41515 function LiveNodeList(node,refresh){
41516         this._node = node;
41517         this._refresh = refresh;
41518         _updateLiveList(this);
41519 }
41520 function _updateLiveList(list){
41521         var inc = list._node._inc || list._node.ownerDocument._inc;
41522         if(list._inc != inc){
41523                 var ls = list._refresh(list._node);
41524                 //console.log(ls.length)
41525                 __set__(list,'length',ls.length);
41526                 copy$1(ls,list);
41527                 list._inc = inc;
41528         }
41529 }
41530 LiveNodeList.prototype.item = function(i){
41531         _updateLiveList(this);
41532         return this[i];
41533 };
41534
41535 _extends(LiveNodeList,NodeList);
41536 /**
41537  * 
41538  * 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.
41539  * NamedNodeMap objects in the DOM are live.
41540  * used for attributes or DocumentType entities 
41541  */
41542 function NamedNodeMap() {
41543 }
41544
41545 function _findNodeIndex(list,node){
41546         var i = list.length;
41547         while(i--){
41548                 if(list[i] === node){return i}
41549         }
41550 }
41551
41552 function _addNamedNode(el,list,newAttr,oldAttr){
41553         if(oldAttr){
41554                 list[_findNodeIndex(list,oldAttr)] = newAttr;
41555         }else{
41556                 list[list.length++] = newAttr;
41557         }
41558         if(el){
41559                 newAttr.ownerElement = el;
41560                 var doc = el.ownerDocument;
41561                 if(doc){
41562                         oldAttr && _onRemoveAttribute(doc,el,oldAttr);
41563                         _onAddAttribute(doc,el,newAttr);
41564                 }
41565         }
41566 }
41567 function _removeNamedNode(el,list,attr){
41568         //console.log('remove attr:'+attr)
41569         var i = _findNodeIndex(list,attr);
41570         if(i>=0){
41571                 var lastIndex = list.length-1;
41572                 while(i<lastIndex){
41573                         list[i] = list[++i];
41574                 }
41575                 list.length = lastIndex;
41576                 if(el){
41577                         var doc = el.ownerDocument;
41578                         if(doc){
41579                                 _onRemoveAttribute(doc,el,attr);
41580                                 attr.ownerElement = null;
41581                         }
41582                 }
41583         }else{
41584                 throw DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
41585         }
41586 }
41587 NamedNodeMap.prototype = {
41588         length:0,
41589         item:NodeList.prototype.item,
41590         getNamedItem: function(key) {
41591 //              if(key.indexOf(':')>0 || key == 'xmlns'){
41592 //                      return null;
41593 //              }
41594                 //console.log()
41595                 var i = this.length;
41596                 while(i--){
41597                         var attr = this[i];
41598                         //console.log(attr.nodeName,key)
41599                         if(attr.nodeName == key){
41600                                 return attr;
41601                         }
41602                 }
41603         },
41604         setNamedItem: function(attr) {
41605                 var el = attr.ownerElement;
41606                 if(el && el!=this._ownerElement){
41607                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41608                 }
41609                 var oldAttr = this.getNamedItem(attr.nodeName);
41610                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41611                 return oldAttr;
41612         },
41613         /* returns Node */
41614         setNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
41615                 var el = attr.ownerElement, oldAttr;
41616                 if(el && el!=this._ownerElement){
41617                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41618                 }
41619                 oldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName);
41620                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41621                 return oldAttr;
41622         },
41623
41624         /* returns Node */
41625         removeNamedItem: function(key) {
41626                 var attr = this.getNamedItem(key);
41627                 _removeNamedNode(this._ownerElement,this,attr);
41628                 return attr;
41629                 
41630                 
41631         },// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
41632         
41633         //for level2
41634         removeNamedItemNS:function(namespaceURI,localName){
41635                 var attr = this.getNamedItemNS(namespaceURI,localName);
41636                 _removeNamedNode(this._ownerElement,this,attr);
41637                 return attr;
41638         },
41639         getNamedItemNS: function(namespaceURI, localName) {
41640                 var i = this.length;
41641                 while(i--){
41642                         var node = this[i];
41643                         if(node.localName == localName && node.namespaceURI == namespaceURI){
41644                                 return node;
41645                         }
41646                 }
41647                 return null;
41648         }
41649 };
41650 /**
41651  * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
41652  */
41653 function DOMImplementation(/* Object */ features) {
41654         this._features = {};
41655         if (features) {
41656                 for (var feature in features) {
41657                          this._features = features[feature];
41658                 }
41659         }
41660 }
41661
41662 DOMImplementation.prototype = {
41663         hasFeature: function(/* string */ feature, /* string */ version) {
41664                 var versions = this._features[feature.toLowerCase()];
41665                 if (versions && (!version || version in versions)) {
41666                         return true;
41667                 } else {
41668                         return false;
41669                 }
41670         },
41671         // Introduced in DOM Level 2:
41672         createDocument:function(namespaceURI,  qualifiedName, doctype){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
41673                 var doc = new Document();
41674                 doc.implementation = this;
41675                 doc.childNodes = new NodeList();
41676                 doc.doctype = doctype;
41677                 if(doctype){
41678                         doc.appendChild(doctype);
41679                 }
41680                 if(qualifiedName){
41681                         var root = doc.createElementNS(namespaceURI,qualifiedName);
41682                         doc.appendChild(root);
41683                 }
41684                 return doc;
41685         },
41686         // Introduced in DOM Level 2:
41687         createDocumentType:function(qualifiedName, publicId, systemId){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
41688                 var node = new DocumentType();
41689                 node.name = qualifiedName;
41690                 node.nodeName = qualifiedName;
41691                 node.publicId = publicId;
41692                 node.systemId = systemId;
41693                 // Introduced in DOM Level 2:
41694                 //readonly attribute DOMString        internalSubset;
41695                 
41696                 //TODO:..
41697                 //  readonly attribute NamedNodeMap     entities;
41698                 //  readonly attribute NamedNodeMap     notations;
41699                 return node;
41700         }
41701 };
41702
41703
41704 /**
41705  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
41706  */
41707
41708 function Node$2() {
41709 }
41710
41711 Node$2.prototype = {
41712         firstChild : null,
41713         lastChild : null,
41714         previousSibling : null,
41715         nextSibling : null,
41716         attributes : null,
41717         parentNode : null,
41718         childNodes : null,
41719         ownerDocument : null,
41720         nodeValue : null,
41721         namespaceURI : null,
41722         prefix : null,
41723         localName : null,
41724         // Modified in DOM Level 2:
41725         insertBefore:function(newChild, refChild){//raises 
41726                 return _insertBefore(this,newChild,refChild);
41727         },
41728         replaceChild:function(newChild, oldChild){//raises 
41729                 this.insertBefore(newChild,oldChild);
41730                 if(oldChild){
41731                         this.removeChild(oldChild);
41732                 }
41733         },
41734         removeChild:function(oldChild){
41735                 return _removeChild(this,oldChild);
41736         },
41737         appendChild:function(newChild){
41738                 return this.insertBefore(newChild,null);
41739         },
41740         hasChildNodes:function(){
41741                 return this.firstChild != null;
41742         },
41743         cloneNode:function(deep){
41744                 return cloneNode(this.ownerDocument||this,this,deep);
41745         },
41746         // Modified in DOM Level 2:
41747         normalize:function(){
41748                 var child = this.firstChild;
41749                 while(child){
41750                         var next = child.nextSibling;
41751                         if(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){
41752                                 this.removeChild(next);
41753                                 child.appendData(next.data);
41754                         }else{
41755                                 child.normalize();
41756                                 child = next;
41757                         }
41758                 }
41759         },
41760         // Introduced in DOM Level 2:
41761         isSupported:function(feature, version){
41762                 return this.ownerDocument.implementation.hasFeature(feature,version);
41763         },
41764     // Introduced in DOM Level 2:
41765     hasAttributes:function(){
41766         return this.attributes.length>0;
41767     },
41768     lookupPrefix:function(namespaceURI){
41769         var el = this;
41770         while(el){
41771                 var map = el._nsMap;
41772                 //console.dir(map)
41773                 if(map){
41774                         for(var n in map){
41775                                 if(map[n] == namespaceURI){
41776                                         return n;
41777                                 }
41778                         }
41779                 }
41780                 el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
41781         }
41782         return null;
41783     },
41784     // Introduced in DOM Level 3:
41785     lookupNamespaceURI:function(prefix){
41786         var el = this;
41787         while(el){
41788                 var map = el._nsMap;
41789                 //console.dir(map)
41790                 if(map){
41791                         if(prefix in map){
41792                                 return map[prefix] ;
41793                         }
41794                 }
41795                 el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
41796         }
41797         return null;
41798     },
41799     // Introduced in DOM Level 3:
41800     isDefaultNamespace:function(namespaceURI){
41801         var prefix = this.lookupPrefix(namespaceURI);
41802         return prefix == null;
41803     }
41804 };
41805
41806
41807 function _xmlEncoder(c){
41808         return c == '<' && '&lt;' ||
41809          c == '>' && '&gt;' ||
41810          c == '&' && '&amp;' ||
41811          c == '"' && '&quot;' ||
41812          '&#'+c.charCodeAt()+';'
41813 }
41814
41815
41816 copy$1(NodeType,Node$2);
41817 copy$1(NodeType,Node$2.prototype);
41818
41819 /**
41820  * @param callback return true for continue,false for break
41821  * @return boolean true: break visit;
41822  */
41823 function _visitNode(node,callback){
41824         if(callback(node)){
41825                 return true;
41826         }
41827         if(node = node.firstChild){
41828                 do{
41829                         if(_visitNode(node,callback)){return true}
41830         }while(node=node.nextSibling)
41831     }
41832 }
41833
41834
41835
41836 function Document(){
41837 }
41838 function _onAddAttribute(doc,el,newAttr){
41839         doc && doc._inc++;
41840         var ns = newAttr.namespaceURI;
41841         if(ns == 'http://www.w3.org/2000/xmlns/'){
41842                 //update namespace
41843                 el._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value;
41844         }
41845 }
41846 function _onRemoveAttribute(doc,el,newAttr,remove){
41847         doc && doc._inc++;
41848         var ns = newAttr.namespaceURI;
41849         if(ns == 'http://www.w3.org/2000/xmlns/'){
41850                 //update namespace
41851                 delete el._nsMap[newAttr.prefix?newAttr.localName:''];
41852         }
41853 }
41854 function _onUpdateChild(doc,el,newChild){
41855         if(doc && doc._inc){
41856                 doc._inc++;
41857                 //update childNodes
41858                 var cs = el.childNodes;
41859                 if(newChild){
41860                         cs[cs.length++] = newChild;
41861                 }else{
41862                         //console.log(1)
41863                         var child = el.firstChild;
41864                         var i = 0;
41865                         while(child){
41866                                 cs[i++] = child;
41867                                 child =child.nextSibling;
41868                         }
41869                         cs.length = i;
41870                 }
41871         }
41872 }
41873
41874 /**
41875  * attributes;
41876  * children;
41877  * 
41878  * writeable properties:
41879  * nodeValue,Attr:value,CharacterData:data
41880  * prefix
41881  */
41882 function _removeChild(parentNode,child){
41883         var previous = child.previousSibling;
41884         var next = child.nextSibling;
41885         if(previous){
41886                 previous.nextSibling = next;
41887         }else{
41888                 parentNode.firstChild = next;
41889         }
41890         if(next){
41891                 next.previousSibling = previous;
41892         }else{
41893                 parentNode.lastChild = previous;
41894         }
41895         _onUpdateChild(parentNode.ownerDocument,parentNode);
41896         return child;
41897 }
41898 /**
41899  * preformance key(refChild == null)
41900  */
41901 function _insertBefore(parentNode,newChild,nextChild){
41902         var cp = newChild.parentNode;
41903         if(cp){
41904                 cp.removeChild(newChild);//remove and update
41905         }
41906         if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
41907                 var newFirst = newChild.firstChild;
41908                 if (newFirst == null) {
41909                         return newChild;
41910                 }
41911                 var newLast = newChild.lastChild;
41912         }else{
41913                 newFirst = newLast = newChild;
41914         }
41915         var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
41916
41917         newFirst.previousSibling = pre;
41918         newLast.nextSibling = nextChild;
41919         
41920         
41921         if(pre){
41922                 pre.nextSibling = newFirst;
41923         }else{
41924                 parentNode.firstChild = newFirst;
41925         }
41926         if(nextChild == null){
41927                 parentNode.lastChild = newLast;
41928         }else{
41929                 nextChild.previousSibling = newLast;
41930         }
41931         do{
41932                 newFirst.parentNode = parentNode;
41933         }while(newFirst !== newLast && (newFirst= newFirst.nextSibling))
41934         _onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);
41935         //console.log(parentNode.lastChild.nextSibling == null)
41936         if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
41937                 newChild.firstChild = newChild.lastChild = null;
41938         }
41939         return newChild;
41940 }
41941 function _appendSingleChild(parentNode,newChild){
41942         var cp = newChild.parentNode;
41943         if(cp){
41944                 var pre = parentNode.lastChild;
41945                 cp.removeChild(newChild);//remove and update
41946                 var pre = parentNode.lastChild;
41947         }
41948         var pre = parentNode.lastChild;
41949         newChild.parentNode = parentNode;
41950         newChild.previousSibling = pre;
41951         newChild.nextSibling = null;
41952         if(pre){
41953                 pre.nextSibling = newChild;
41954         }else{
41955                 parentNode.firstChild = newChild;
41956         }
41957         parentNode.lastChild = newChild;
41958         _onUpdateChild(parentNode.ownerDocument,parentNode,newChild);
41959         return newChild;
41960         //console.log("__aa",parentNode.lastChild.nextSibling == null)
41961 }
41962 Document.prototype = {
41963         //implementation : null,
41964         nodeName :  '#document',
41965         nodeType :  DOCUMENT_NODE,
41966         doctype :  null,
41967         documentElement :  null,
41968         _inc : 1,
41969         
41970         insertBefore :  function(newChild, refChild){//raises 
41971                 if(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){
41972                         var child = newChild.firstChild;
41973                         while(child){
41974                                 var next = child.nextSibling;
41975                                 this.insertBefore(child,refChild);
41976                                 child = next;
41977                         }
41978                         return newChild;
41979                 }
41980                 if(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){
41981                         this.documentElement = newChild;
41982                 }
41983                 
41984                 return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;
41985         },
41986         removeChild :  function(oldChild){
41987                 if(this.documentElement == oldChild){
41988                         this.documentElement = null;
41989                 }
41990                 return _removeChild(this,oldChild);
41991         },
41992         // Introduced in DOM Level 2:
41993         importNode : function(importedNode,deep){
41994                 return importNode(this,importedNode,deep);
41995         },
41996         // Introduced in DOM Level 2:
41997         getElementById :        function(id){
41998                 var rtv = null;
41999                 _visitNode(this.documentElement,function(node){
42000                         if(node.nodeType == ELEMENT_NODE){
42001                                 if(node.getAttribute('id') == id){
42002                                         rtv = node;
42003                                         return true;
42004                                 }
42005                         }
42006                 });
42007                 return rtv;
42008         },
42009         
42010         //document factory method:
42011         createElement : function(tagName){
42012                 var node = new Element();
42013                 node.ownerDocument = this;
42014                 node.nodeName = tagName;
42015                 node.tagName = tagName;
42016                 node.childNodes = new NodeList();
42017                 var attrs       = node.attributes = new NamedNodeMap();
42018                 attrs._ownerElement = node;
42019                 return node;
42020         },
42021         createDocumentFragment :        function(){
42022                 var node = new DocumentFragment();
42023                 node.ownerDocument = this;
42024                 node.childNodes = new NodeList();
42025                 return node;
42026         },
42027         createTextNode :        function(data){
42028                 var node = new Text();
42029                 node.ownerDocument = this;
42030                 node.appendData(data);
42031                 return node;
42032         },
42033         createComment : function(data){
42034                 var node = new Comment();
42035                 node.ownerDocument = this;
42036                 node.appendData(data);
42037                 return node;
42038         },
42039         createCDATASection :    function(data){
42040                 var node = new CDATASection();
42041                 node.ownerDocument = this;
42042                 node.appendData(data);
42043                 return node;
42044         },
42045         createProcessingInstruction :   function(target,data){
42046                 var node = new ProcessingInstruction();
42047                 node.ownerDocument = this;
42048                 node.tagName = node.target = target;
42049                 node.nodeValue= node.data = data;
42050                 return node;
42051         },
42052         createAttribute :       function(name){
42053                 var node = new Attr();
42054                 node.ownerDocument      = this;
42055                 node.name = name;
42056                 node.nodeName   = name;
42057                 node.localName = name;
42058                 node.specified = true;
42059                 return node;
42060         },
42061         createEntityReference : function(name){
42062                 var node = new EntityReference();
42063                 node.ownerDocument      = this;
42064                 node.nodeName   = name;
42065                 return node;
42066         },
42067         // Introduced in DOM Level 2:
42068         createElementNS :       function(namespaceURI,qualifiedName){
42069                 var node = new Element();
42070                 var pl = qualifiedName.split(':');
42071                 var attrs       = node.attributes = new NamedNodeMap();
42072                 node.childNodes = new NodeList();
42073                 node.ownerDocument = this;
42074                 node.nodeName = qualifiedName;
42075                 node.tagName = qualifiedName;
42076                 node.namespaceURI = namespaceURI;
42077                 if(pl.length == 2){
42078                         node.prefix = pl[0];
42079                         node.localName = pl[1];
42080                 }else{
42081                         //el.prefix = null;
42082                         node.localName = qualifiedName;
42083                 }
42084                 attrs._ownerElement = node;
42085                 return node;
42086         },
42087         // Introduced in DOM Level 2:
42088         createAttributeNS :     function(namespaceURI,qualifiedName){
42089                 var node = new Attr();
42090                 var pl = qualifiedName.split(':');
42091                 node.ownerDocument = this;
42092                 node.nodeName = qualifiedName;
42093                 node.name = qualifiedName;
42094                 node.namespaceURI = namespaceURI;
42095                 node.specified = true;
42096                 if(pl.length == 2){
42097                         node.prefix = pl[0];
42098                         node.localName = pl[1];
42099                 }else{
42100                         //el.prefix = null;
42101                         node.localName = qualifiedName;
42102                 }
42103                 return node;
42104         }
42105 };
42106 _extends(Document,Node$2);
42107
42108
42109 function Element() {
42110         this._nsMap = {};
42111 }
42112 Element.prototype = {
42113         nodeType : ELEMENT_NODE,
42114         hasAttribute : function(name){
42115                 return this.getAttributeNode(name)!=null;
42116         },
42117         getAttribute : function(name){
42118                 var attr = this.getAttributeNode(name);
42119                 return attr && attr.value || '';
42120         },
42121         getAttributeNode : function(name){
42122                 return this.attributes.getNamedItem(name);
42123         },
42124         setAttribute : function(name, value){
42125                 var attr = this.ownerDocument.createAttribute(name);
42126                 attr.value = attr.nodeValue = "" + value;
42127                 this.setAttributeNode(attr);
42128         },
42129         removeAttribute : function(name){
42130                 var attr = this.getAttributeNode(name);
42131                 attr && this.removeAttributeNode(attr);
42132         },
42133         
42134         //four real opeartion method
42135         appendChild:function(newChild){
42136                 if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
42137                         return this.insertBefore(newChild,null);
42138                 }else{
42139                         return _appendSingleChild(this,newChild);
42140                 }
42141         },
42142         setAttributeNode : function(newAttr){
42143                 return this.attributes.setNamedItem(newAttr);
42144         },
42145         setAttributeNodeNS : function(newAttr){
42146                 return this.attributes.setNamedItemNS(newAttr);
42147         },
42148         removeAttributeNode : function(oldAttr){
42149                 //console.log(this == oldAttr.ownerElement)
42150                 return this.attributes.removeNamedItem(oldAttr.nodeName);
42151         },
42152         //get real attribute name,and remove it by removeAttributeNode
42153         removeAttributeNS : function(namespaceURI, localName){
42154                 var old = this.getAttributeNodeNS(namespaceURI, localName);
42155                 old && this.removeAttributeNode(old);
42156         },
42157         
42158         hasAttributeNS : function(namespaceURI, localName){
42159                 return this.getAttributeNodeNS(namespaceURI, localName)!=null;
42160         },
42161         getAttributeNS : function(namespaceURI, localName){
42162                 var attr = this.getAttributeNodeNS(namespaceURI, localName);
42163                 return attr && attr.value || '';
42164         },
42165         setAttributeNS : function(namespaceURI, qualifiedName, value){
42166                 var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
42167                 attr.value = attr.nodeValue = "" + value;
42168                 this.setAttributeNode(attr);
42169         },
42170         getAttributeNodeNS : function(namespaceURI, localName){
42171                 return this.attributes.getNamedItemNS(namespaceURI, localName);
42172         },
42173         
42174         getElementsByTagName : function(tagName){
42175                 return new LiveNodeList(this,function(base){
42176                         var ls = [];
42177                         _visitNode(base,function(node){
42178                                 if(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){
42179                                         ls.push(node);
42180                                 }
42181                         });
42182                         return ls;
42183                 });
42184         },
42185         getElementsByTagNameNS : function(namespaceURI, localName){
42186                 return new LiveNodeList(this,function(base){
42187                         var ls = [];
42188                         _visitNode(base,function(node){
42189                                 if(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){
42190                                         ls.push(node);
42191                                 }
42192                         });
42193                         return ls;
42194                         
42195                 });
42196         }
42197 };
42198 Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
42199 Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
42200
42201
42202 _extends(Element,Node$2);
42203 function Attr() {
42204 }
42205 Attr.prototype.nodeType = ATTRIBUTE_NODE;
42206 _extends(Attr,Node$2);
42207
42208
42209 function CharacterData() {
42210 }
42211 CharacterData.prototype = {
42212         data : '',
42213         substringData : function(offset, count) {
42214                 return this.data.substring(offset, offset+count);
42215         },
42216         appendData: function(text) {
42217                 text = this.data+text;
42218                 this.nodeValue = this.data = text;
42219                 this.length = text.length;
42220         },
42221         insertData: function(offset,text) {
42222                 this.replaceData(offset,0,text);
42223         
42224         },
42225         appendChild:function(newChild){
42226                 throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR])
42227         },
42228         deleteData: function(offset, count) {
42229                 this.replaceData(offset,count,"");
42230         },
42231         replaceData: function(offset, count, text) {
42232                 var start = this.data.substring(0,offset);
42233                 var end = this.data.substring(offset+count);
42234                 text = start + text + end;
42235                 this.nodeValue = this.data = text;
42236                 this.length = text.length;
42237         }
42238 };
42239 _extends(CharacterData,Node$2);
42240 function Text() {
42241 }
42242 Text.prototype = {
42243         nodeName : "#text",
42244         nodeType : TEXT_NODE,
42245         splitText : function(offset) {
42246                 var text = this.data;
42247                 var newText = text.substring(offset);
42248                 text = text.substring(0, offset);
42249                 this.data = this.nodeValue = text;
42250                 this.length = text.length;
42251                 var newNode = this.ownerDocument.createTextNode(newText);
42252                 if(this.parentNode){
42253                         this.parentNode.insertBefore(newNode, this.nextSibling);
42254                 }
42255                 return newNode;
42256         }
42257 };
42258 _extends(Text,CharacterData);
42259 function Comment() {
42260 }
42261 Comment.prototype = {
42262         nodeName : "#comment",
42263         nodeType : COMMENT_NODE
42264 };
42265 _extends(Comment,CharacterData);
42266
42267 function CDATASection() {
42268 }
42269 CDATASection.prototype = {
42270         nodeName : "#cdata-section",
42271         nodeType : CDATA_SECTION_NODE
42272 };
42273 _extends(CDATASection,CharacterData);
42274
42275
42276 function DocumentType() {
42277 }
42278 DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
42279 _extends(DocumentType,Node$2);
42280
42281 function Notation() {
42282 }
42283 Notation.prototype.nodeType = NOTATION_NODE;
42284 _extends(Notation,Node$2);
42285
42286 function Entity() {
42287 }
42288 Entity.prototype.nodeType = ENTITY_NODE;
42289 _extends(Entity,Node$2);
42290
42291 function EntityReference() {
42292 }
42293 EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
42294 _extends(EntityReference,Node$2);
42295
42296 function DocumentFragment() {
42297 }
42298 DocumentFragment.prototype.nodeName =   "#document-fragment";
42299 DocumentFragment.prototype.nodeType =   DOCUMENT_FRAGMENT_NODE;
42300 _extends(DocumentFragment,Node$2);
42301
42302
42303 function ProcessingInstruction() {
42304 }
42305 ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
42306 _extends(ProcessingInstruction,Node$2);
42307 function XMLSerializer$1(){}
42308 XMLSerializer$1.prototype.serializeToString = function(node,isHtml,nodeFilter){
42309         return nodeSerializeToString.call(node,isHtml,nodeFilter);
42310 };
42311 Node$2.prototype.toString = nodeSerializeToString;
42312 function nodeSerializeToString(isHtml,nodeFilter){
42313         var buf = [];
42314         var refNode = this.nodeType == 9?this.documentElement:this;
42315         var prefix = refNode.prefix;
42316         var uri = refNode.namespaceURI;
42317         
42318         if(uri && prefix == null){
42319                 //console.log(prefix)
42320                 var prefix = refNode.lookupPrefix(uri);
42321                 if(prefix == null){
42322                         //isHTML = true;
42323                         var visibleNamespaces=[
42324                         {namespace:uri,prefix:null}
42325                         //{namespace:uri,prefix:''}
42326                         ];
42327                 }
42328         }
42329         serializeToString(this,buf,isHtml,nodeFilter,visibleNamespaces);
42330         //console.log('###',this.nodeType,uri,prefix,buf.join(''))
42331         return buf.join('');
42332 }
42333 function needNamespaceDefine(node,isHTML, visibleNamespaces) {
42334         var prefix = node.prefix||'';
42335         var uri = node.namespaceURI;
42336         if (!prefix && !uri){
42337                 return false;
42338         }
42339         if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" 
42340                 || uri == 'http://www.w3.org/2000/xmlns/'){
42341                 return false;
42342         }
42343         
42344         var i = visibleNamespaces.length; 
42345         //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces)
42346         while (i--) {
42347                 var ns = visibleNamespaces[i];
42348                 // get namespace prefix
42349                 //console.log(node.nodeType,node.tagName,ns.prefix,prefix)
42350                 if (ns.prefix == prefix){
42351                         return ns.namespace != uri;
42352                 }
42353         }
42354         //console.log(isHTML,uri,prefix=='')
42355         //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){
42356         //      return false;
42357         //}
42358         //node.flag = '11111'
42359         //console.error(3,true,node.flag,node.prefix,node.namespaceURI)
42360         return true;
42361 }
42362 function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
42363         if(nodeFilter){
42364                 node = nodeFilter(node);
42365                 if(node){
42366                         if(typeof node == 'string'){
42367                                 buf.push(node);
42368                                 return;
42369                         }
42370                 }else{
42371                         return;
42372                 }
42373                 //buf.sort.apply(attrs, attributeSorter);
42374         }
42375         switch(node.nodeType){
42376         case ELEMENT_NODE:
42377                 if (!visibleNamespaces) visibleNamespaces = [];
42378                 var startVisibleNamespaces = visibleNamespaces.length;
42379                 var attrs = node.attributes;
42380                 var len = attrs.length;
42381                 var child = node.firstChild;
42382                 var nodeName = node.tagName;
42383                 
42384                 isHTML =  (htmlns === node.namespaceURI) ||isHTML; 
42385                 buf.push('<',nodeName);
42386                 
42387                 
42388                 
42389                 for(var i=0;i<len;i++){
42390                         // add namespaces for attributes
42391                         var attr = attrs.item(i);
42392                         if (attr.prefix == 'xmlns') {
42393                                 visibleNamespaces.push({ prefix: attr.localName, namespace: attr.value });
42394                         }else if(attr.nodeName == 'xmlns'){
42395                                 visibleNamespaces.push({ prefix: '', namespace: attr.value });
42396                         }
42397                 }
42398                 for(var i=0;i<len;i++){
42399                         var attr = attrs.item(i);
42400                         if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
42401                                 var prefix = attr.prefix||'';
42402                                 var uri = attr.namespaceURI;
42403                                 var ns = prefix ? ' xmlns:' + prefix : " xmlns";
42404                                 buf.push(ns, '="' , uri , '"');
42405                                 visibleNamespaces.push({ prefix: prefix, namespace:uri });
42406                         }
42407                         serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
42408                 }
42409                 // add namespace for current node               
42410                 if (needNamespaceDefine(node,isHTML, visibleNamespaces)) {
42411                         var prefix = node.prefix||'';
42412                         var uri = node.namespaceURI;
42413                         var ns = prefix ? ' xmlns:' + prefix : " xmlns";
42414                         buf.push(ns, '="' , uri , '"');
42415                         visibleNamespaces.push({ prefix: prefix, namespace:uri });
42416                 }
42417                 
42418                 if(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){
42419                         buf.push('>');
42420                         //if is cdata child node
42421                         if(isHTML && /^script$/i.test(nodeName)){
42422                                 while(child){
42423                                         if(child.data){
42424                                                 buf.push(child.data);
42425                                         }else{
42426                                                 serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42427                                         }
42428                                         child = child.nextSibling;
42429                                 }
42430                         }else
42431                         {
42432                                 while(child){
42433                                         serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42434                                         child = child.nextSibling;
42435                                 }
42436                         }
42437                         buf.push('</',nodeName,'>');
42438                 }else{
42439                         buf.push('/>');
42440                 }
42441                 // remove added visible namespaces
42442                 //visibleNamespaces.length = startVisibleNamespaces;
42443                 return;
42444         case DOCUMENT_NODE:
42445         case DOCUMENT_FRAGMENT_NODE:
42446                 var child = node.firstChild;
42447                 while(child){
42448                         serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42449                         child = child.nextSibling;
42450                 }
42451                 return;
42452         case ATTRIBUTE_NODE:
42453                 return buf.push(' ',node.name,'="',node.value.replace(/[<&"]/g,_xmlEncoder),'"');
42454         case TEXT_NODE:
42455                 return buf.push(node.data.replace(/[<&]/g,_xmlEncoder));
42456         case CDATA_SECTION_NODE:
42457                 return buf.push( '<![CDATA[',node.data,']]>');
42458         case COMMENT_NODE:
42459                 return buf.push( "<!--",node.data,"-->");
42460         case DOCUMENT_TYPE_NODE:
42461                 var pubid = node.publicId;
42462                 var sysid = node.systemId;
42463                 buf.push('<!DOCTYPE ',node.name);
42464                 if(pubid){
42465                         buf.push(' PUBLIC "',pubid);
42466                         if (sysid && sysid!='.') {
42467                                 buf.push( '" "',sysid);
42468                         }
42469                         buf.push('">');
42470                 }else if(sysid && sysid!='.'){
42471                         buf.push(' SYSTEM "',sysid,'">');
42472                 }else{
42473                         var sub = node.internalSubset;
42474                         if(sub){
42475                                 buf.push(" [",sub,"]");
42476                         }
42477                         buf.push(">");
42478                 }
42479                 return;
42480         case PROCESSING_INSTRUCTION_NODE:
42481                 return buf.push( "<?",node.target," ",node.data,"?>");
42482         case ENTITY_REFERENCE_NODE:
42483                 return buf.push( '&',node.nodeName,';');
42484         //case ENTITY_NODE:
42485         //case NOTATION_NODE:
42486         default:
42487                 buf.push('??',node.nodeName);
42488         }
42489 }
42490 function importNode(doc,node,deep){
42491         var node2;
42492         switch (node.nodeType) {
42493         case ELEMENT_NODE:
42494                 node2 = node.cloneNode(false);
42495                 node2.ownerDocument = doc;
42496                 //var attrs = node2.attributes;
42497                 //var len = attrs.length;
42498                 //for(var i=0;i<len;i++){
42499                         //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
42500                 //}
42501         case DOCUMENT_FRAGMENT_NODE:
42502                 break;
42503         case ATTRIBUTE_NODE:
42504                 deep = true;
42505                 break;
42506         //case ENTITY_REFERENCE_NODE:
42507         //case PROCESSING_INSTRUCTION_NODE:
42508         ////case TEXT_NODE:
42509         //case CDATA_SECTION_NODE:
42510         //case COMMENT_NODE:
42511         //      deep = false;
42512         //      break;
42513         //case DOCUMENT_NODE:
42514         //case DOCUMENT_TYPE_NODE:
42515         //cannot be imported.
42516         //case ENTITY_NODE:
42517         //case NOTATION_NODE:
42518         //can not hit in level3
42519         //default:throw e;
42520         }
42521         if(!node2){
42522                 node2 = node.cloneNode(false);//false
42523         }
42524         node2.ownerDocument = doc;
42525         node2.parentNode = null;
42526         if(deep){
42527                 var child = node.firstChild;
42528                 while(child){
42529                         node2.appendChild(importNode(doc,child,deep));
42530                         child = child.nextSibling;
42531                 }
42532         }
42533         return node2;
42534 }
42535 //
42536 //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
42537 //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
42538 function cloneNode(doc,node,deep){
42539         var node2 = new node.constructor();
42540         for(var n in node){
42541                 var v = node[n];
42542                 if(typeof v != 'object' ){
42543                         if(v != node2[n]){
42544                                 node2[n] = v;
42545                         }
42546                 }
42547         }
42548         if(node.childNodes){
42549                 node2.childNodes = new NodeList();
42550         }
42551         node2.ownerDocument = doc;
42552         switch (node2.nodeType) {
42553         case ELEMENT_NODE:
42554                 var attrs       = node.attributes;
42555                 var attrs2      = node2.attributes = new NamedNodeMap();
42556                 var len = attrs.length;
42557                 attrs2._ownerElement = node2;
42558                 for(var i=0;i<len;i++){
42559                         node2.setAttributeNode(cloneNode(doc,attrs.item(i),true));
42560                 }
42561                 break;;
42562         case ATTRIBUTE_NODE:
42563                 deep = true;
42564         }
42565         if(deep){
42566                 var child = node.firstChild;
42567                 while(child){
42568                         node2.appendChild(cloneNode(doc,child,deep));
42569                         child = child.nextSibling;
42570                 }
42571         }
42572         return node2;
42573 }
42574
42575 function __set__(object,key,value){
42576         object[key] = value;
42577 }
42578 //do dynamic
42579 try{
42580         if(Object.defineProperty){
42581                 Object.defineProperty(LiveNodeList.prototype,'length',{
42582                         get:function(){
42583                                 _updateLiveList(this);
42584                                 return this.$$length;
42585                         }
42586                 });
42587                 Object.defineProperty(Node$2.prototype,'textContent',{
42588                         get:function(){
42589                                 return getTextContent(this);
42590                         },
42591                         set:function(data){
42592                                 switch(this.nodeType){
42593                                 case ELEMENT_NODE:
42594                                 case DOCUMENT_FRAGMENT_NODE:
42595                                         while(this.firstChild){
42596                                                 this.removeChild(this.firstChild);
42597                                         }
42598                                         if(data || String(data)){
42599                                                 this.appendChild(this.ownerDocument.createTextNode(data));
42600                                         }
42601                                         break;
42602                                 default:
42603                                         //TODO:
42604                                         this.data = data;
42605                                         this.value = data;
42606                                         this.nodeValue = data;
42607                                 }
42608                         }
42609                 });
42610                 
42611                 function getTextContent(node){
42612                         switch(node.nodeType){
42613                         case ELEMENT_NODE:
42614                         case DOCUMENT_FRAGMENT_NODE:
42615                                 var buf = [];
42616                                 node = node.firstChild;
42617                                 while(node){
42618                                         if(node.nodeType!==7 && node.nodeType !==8){
42619                                                 buf.push(getTextContent(node));
42620                                         }
42621                                         node = node.nextSibling;
42622                                 }
42623                                 return buf.join('');
42624                         default:
42625                                 return node.nodeValue;
42626                         }
42627                 }
42628                 __set__ = function(object,key,value){
42629                         //console.log(value)
42630                         object['$$'+key] = value;
42631                 };
42632         }
42633 }catch(e){//ie8
42634 }
42635
42636 //if(typeof require == 'function'){
42637         var DOMImplementation_1 = DOMImplementation;
42638         var XMLSerializer_1 = XMLSerializer$1;
42639 //}
42640
42641 var dom = {
42642         DOMImplementation: DOMImplementation_1,
42643         XMLSerializer: XMLSerializer_1
42644 };
42645
42646 var domParser = createCommonjsModule(function (module, exports) {
42647 function DOMParser(options){
42648         this.options = options ||{locator:{}};
42649         
42650 }
42651 DOMParser.prototype.parseFromString = function(source,mimeType){
42652         var options = this.options;
42653         var sax$$1 =  new XMLReader();
42654         var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
42655         var errorHandler = options.errorHandler;
42656         var locator = options.locator;
42657         var defaultNSMap = options.xmlns||{};
42658         var entityMap = {'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"};
42659         if(locator){
42660                 domBuilder.setDocumentLocator(locator);
42661         }
42662         
42663         sax$$1.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);
42664         sax$$1.domBuilder = options.domBuilder || domBuilder;
42665         if(/\/x?html?$/.test(mimeType)){
42666                 entityMap.nbsp = '\xa0';
42667                 entityMap.copy = '\xa9';
42668                 defaultNSMap['']= 'http://www.w3.org/1999/xhtml';
42669         }
42670         defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
42671         if(source){
42672                 sax$$1.parse(source,defaultNSMap,entityMap);
42673         }else{
42674                 sax$$1.errorHandler.error("invalid doc source");
42675         }
42676         return domBuilder.doc;
42677 };
42678 function buildErrorHandler(errorImpl,domBuilder,locator){
42679         if(!errorImpl){
42680                 if(domBuilder instanceof DOMHandler){
42681                         return domBuilder;
42682                 }
42683                 errorImpl = domBuilder ;
42684         }
42685         var errorHandler = {};
42686         var isCallback = errorImpl instanceof Function;
42687         locator = locator||{};
42688         function build(key){
42689                 var fn = errorImpl[key];
42690                 if(!fn && isCallback){
42691                         fn = errorImpl.length == 2?function(msg){errorImpl(key,msg);}:errorImpl;
42692                 }
42693                 errorHandler[key] = fn && function(msg){
42694                         fn('[xmldom '+key+']\t'+msg+_locator(locator));
42695                 }||function(){};
42696         }
42697         build('warning');
42698         build('error');
42699         build('fatalError');
42700         return errorHandler;
42701 }
42702
42703 //console.log('#\n\n\n\n\n\n\n####')
42704 /**
42705  * +ContentHandler+ErrorHandler
42706  * +LexicalHandler+EntityResolver2
42707  * -DeclHandler-DTDHandler 
42708  * 
42709  * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
42710  * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
42711  * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
42712  */
42713 function DOMHandler() {
42714     this.cdata = false;
42715 }
42716 function position(locator,node){
42717         node.lineNumber = locator.lineNumber;
42718         node.columnNumber = locator.columnNumber;
42719 }
42720 /**
42721  * @see org.xml.sax.ContentHandler#startDocument
42722  * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
42723  */ 
42724 DOMHandler.prototype = {
42725         startDocument : function() {
42726         this.doc = new DOMImplementation().createDocument(null, null, null);
42727         if (this.locator) {
42728                 this.doc.documentURI = this.locator.systemId;
42729         }
42730         },
42731         startElement:function(namespaceURI, localName, qName, attrs) {
42732                 var doc = this.doc;
42733             var el = doc.createElementNS(namespaceURI, qName||localName);
42734             var len = attrs.length;
42735             appendElement(this, el);
42736             this.currentElement = el;
42737             
42738                 this.locator && position(this.locator,el);
42739             for (var i = 0 ; i < len; i++) {
42740                 var namespaceURI = attrs.getURI(i);
42741                 var value = attrs.getValue(i);
42742                 var qName = attrs.getQName(i);
42743                         var attr = doc.createAttributeNS(namespaceURI, qName);
42744                         this.locator &&position(attrs.getLocator(i),attr);
42745                         attr.value = attr.nodeValue = value;
42746                         el.setAttributeNode(attr);
42747             }
42748         },
42749         endElement:function(namespaceURI, localName, qName) {
42750                 var current = this.currentElement;
42751                 var tagName = current.tagName;
42752                 this.currentElement = current.parentNode;
42753         },
42754         startPrefixMapping:function(prefix, uri) {
42755         },
42756         endPrefixMapping:function(prefix) {
42757         },
42758         processingInstruction:function(target, data) {
42759             var ins = this.doc.createProcessingInstruction(target, data);
42760             this.locator && position(this.locator,ins);
42761             appendElement(this, ins);
42762         },
42763         ignorableWhitespace:function(ch, start, length) {
42764         },
42765         characters:function(chars, start, length) {
42766                 chars = _toString.apply(this,arguments);
42767                 //console.log(chars)
42768                 if(chars){
42769                         if (this.cdata) {
42770                                 var charNode = this.doc.createCDATASection(chars);
42771                         } else {
42772                                 var charNode = this.doc.createTextNode(chars);
42773                         }
42774                         if(this.currentElement){
42775                                 this.currentElement.appendChild(charNode);
42776                         }else if(/^\s*$/.test(chars)){
42777                                 this.doc.appendChild(charNode);
42778                                 //process xml
42779                         }
42780                         this.locator && position(this.locator,charNode);
42781                 }
42782         },
42783         skippedEntity:function(name) {
42784         },
42785         endDocument:function() {
42786                 this.doc.normalize();
42787         },
42788         setDocumentLocator:function (locator) {
42789             if(this.locator = locator){// && !('lineNumber' in locator)){
42790                 locator.lineNumber = 0;
42791             }
42792         },
42793         //LexicalHandler
42794         comment:function(chars, start, length) {
42795                 chars = _toString.apply(this,arguments);
42796             var comm = this.doc.createComment(chars);
42797             this.locator && position(this.locator,comm);
42798             appendElement(this, comm);
42799         },
42800         
42801         startCDATA:function() {
42802             //used in characters() methods
42803             this.cdata = true;
42804         },
42805         endCDATA:function() {
42806             this.cdata = false;
42807         },
42808         
42809         startDTD:function(name, publicId, systemId) {
42810                 var impl = this.doc.implementation;
42811             if (impl && impl.createDocumentType) {
42812                 var dt = impl.createDocumentType(name, publicId, systemId);
42813                 this.locator && position(this.locator,dt);
42814                 appendElement(this, dt);
42815             }
42816         },
42817         /**
42818          * @see org.xml.sax.ErrorHandler
42819          * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
42820          */
42821         warning:function(error) {
42822                 console.warn('[xmldom warning]\t'+error,_locator(this.locator));
42823         },
42824         error:function(error) {
42825                 console.error('[xmldom error]\t'+error,_locator(this.locator));
42826         },
42827         fatalError:function(error) {
42828                 console.error('[xmldom fatalError]\t'+error,_locator(this.locator));
42829             throw error;
42830         }
42831 };
42832 function _locator(l){
42833         if(l){
42834                 return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'
42835         }
42836 }
42837 function _toString(chars,start,length){
42838         if(typeof chars == 'string'){
42839                 return chars.substr(start,length)
42840         }else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
42841                 if(chars.length >= start+length || start){
42842                         return new java.lang.String(chars,start,length)+'';
42843                 }
42844                 return chars;
42845         }
42846 }
42847
42848 /*
42849  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
42850  * used method of org.xml.sax.ext.LexicalHandler:
42851  *  #comment(chars, start, length)
42852  *  #startCDATA()
42853  *  #endCDATA()
42854  *  #startDTD(name, publicId, systemId)
42855  *
42856  *
42857  * IGNORED method of org.xml.sax.ext.LexicalHandler:
42858  *  #endDTD()
42859  *  #startEntity(name)
42860  *  #endEntity(name)
42861  *
42862  *
42863  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
42864  * IGNORED method of org.xml.sax.ext.DeclHandler
42865  *      #attributeDecl(eName, aName, type, mode, value)
42866  *  #elementDecl(name, model)
42867  *  #externalEntityDecl(name, publicId, systemId)
42868  *  #internalEntityDecl(name, value)
42869  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
42870  * IGNORED method of org.xml.sax.EntityResolver2
42871  *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
42872  *  #resolveEntity(publicId, systemId)
42873  *  #getExternalSubset(name, baseURI)
42874  * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
42875  * IGNORED method of org.xml.sax.DTDHandler
42876  *  #notationDecl(name, publicId, systemId) {};
42877  *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
42878  */
42879 "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){
42880         DOMHandler.prototype[key] = function(){return null};
42881 });
42882
42883 /* 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 */
42884 function appendElement (hander,node) {
42885     if (!hander.currentElement) {
42886         hander.doc.appendChild(node);
42887     } else {
42888         hander.currentElement.appendChild(node);
42889     }
42890 }//appendChild and setAttributeNS are preformance key
42891
42892 //if(typeof require == 'function'){
42893         var XMLReader = sax.XMLReader;
42894         var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
42895         exports.XMLSerializer = dom.XMLSerializer ;
42896         exports.DOMParser = DOMParser;
42897 //}
42898 });
42899
42900 var togeojson = createCommonjsModule(function (module, exports) {
42901 var toGeoJSON = (function() {
42902     'use strict';
42903
42904     var removeSpace = /\s*/g,
42905         trimSpace = /^\s*|\s*$/g,
42906         splitSpace = /\s+/;
42907     // generate a short, numeric hash of a string
42908     function okhash(x) {
42909         if (!x || !x.length) return 0;
42910         for (var i = 0, h = 0; i < x.length; i++) {
42911             h = ((h << 5) - h) + x.charCodeAt(i) | 0;
42912         } return h;
42913     }
42914     // all Y children of X
42915     function get(x, y) { return x.getElementsByTagName(y); }
42916     function attr(x, y) { return x.getAttribute(y); }
42917     function attrf(x, y) { return parseFloat(attr(x, y)); }
42918     // one Y child of X, if any, otherwise null
42919     function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
42920     // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
42921     function norm(el) { if (el.normalize) { el.normalize(); } return el; }
42922     // cast array x into numbers
42923     function numarray(x) {
42924         for (var j = 0, o = []; j < x.length; j++) { o[j] = parseFloat(x[j]); }
42925         return o;
42926     }
42927     // get the content of a text node, if any
42928     function nodeVal(x) {
42929         if (x) { norm(x); }
42930         return (x && x.textContent) || '';
42931     }
42932     // get the contents of multiple text nodes, if present
42933     function getMulti(x, ys) {
42934         var o = {}, n, k;
42935         for (k = 0; k < ys.length; k++) {
42936             n = get1(x, ys[k]);
42937             if (n) o[ys[k]] = nodeVal(n);
42938         }
42939         return o;
42940     }
42941     // add properties of Y to X, overwriting if present in both
42942     function extend(x, y) { for (var k in y) x[k] = y[k]; }
42943     // get one coordinate from a coordinate array, if any
42944     function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
42945     // get all coordinates from a coordinate array as [[],[]]
42946     function coord(v) {
42947         var coords = v.replace(trimSpace, '').split(splitSpace),
42948             o = [];
42949         for (var i = 0; i < coords.length; i++) {
42950             o.push(coord1(coords[i]));
42951         }
42952         return o;
42953     }
42954     function coordPair(x) {
42955         var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
42956             ele = get1(x, 'ele'),
42957             // handle namespaced attribute in browser
42958             heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
42959             time = get1(x, 'time'),
42960             e;
42961         if (ele) {
42962             e = parseFloat(nodeVal(ele));
42963             if (!isNaN(e)) {
42964                 ll.push(e);
42965             }
42966         }
42967         return {
42968             coordinates: ll,
42969             time: time ? nodeVal(time) : null,
42970             heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
42971         };
42972     }
42973
42974     // create a new feature collection parent object
42975     function fc() {
42976         return {
42977             type: 'FeatureCollection',
42978             features: []
42979         };
42980     }
42981
42982     var serializer;
42983     if (typeof XMLSerializer !== 'undefined') {
42984         /* istanbul ignore next */
42985         serializer = new XMLSerializer();
42986     // only require xmldom in a node environment
42987     } else if ('object' === 'object' && typeof process === 'object' && !process.browser) {
42988         serializer = new (domParser.XMLSerializer)();
42989     }
42990     function xml2str(str) {
42991         // IE9 will create a new XMLSerializer but it'll crash immediately.
42992         // This line is ignored because we don't run coverage tests in IE9
42993         /* istanbul ignore next */
42994         if (str.xml !== undefined) return str.xml;
42995         return serializer.serializeToString(str);
42996     }
42997
42998     var t = {
42999         kml: function(doc) {
43000
43001             var gj = fc(),
43002                 // styleindex keeps track of hashed styles in order to match features
43003                 styleIndex = {}, styleByHash = {},
43004                 // stylemapindex keeps track of style maps to expose in properties
43005                 styleMapIndex = {},
43006                 // atomic geospatial types supported by KML - MultiGeometry is
43007                 // handled separately
43008                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
43009                 // all root placemarks in the file
43010                 placemarks = get(doc, 'Placemark'),
43011                 styles = get(doc, 'Style'),
43012                 styleMaps = get(doc, 'StyleMap');
43013
43014             for (var k = 0; k < styles.length; k++) {
43015                 var hash = okhash(xml2str(styles[k])).toString(16);
43016                 styleIndex['#' + attr(styles[k], 'id')] = hash;
43017                 styleByHash[hash] = styles[k];
43018             }
43019             for (var l = 0; l < styleMaps.length; l++) {
43020                 styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
43021                 var pairs = get(styleMaps[l], 'Pair');
43022                 var pairsMap = {};
43023                 for (var m = 0; m < pairs.length; m++) {
43024                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
43025                 }
43026                 styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
43027
43028             }
43029             for (var j = 0; j < placemarks.length; j++) {
43030                 gj.features = gj.features.concat(getPlacemark(placemarks[j]));
43031             }
43032             function kmlColor(v) {
43033                 var color, opacity;
43034                 v = v || '';
43035                 if (v.substr(0, 1) === '#') { v = v.substr(1); }
43036                 if (v.length === 6 || v.length === 3) { color = v; }
43037                 if (v.length === 8) {
43038                     opacity = parseInt(v.substr(0, 2), 16) / 255;
43039                     color = '#' + v.substr(6, 2) +
43040                         v.substr(4, 2) +
43041                         v.substr(2, 2);
43042                 }
43043                 return [color, isNaN(opacity) ? undefined : opacity];
43044             }
43045             function gxCoord(v) { return numarray(v.split(' ')); }
43046             function gxCoords(root) {
43047                 var elems = get(root, 'coord', 'gx'), coords = [], times = [];
43048                 if (elems.length === 0) elems = get(root, 'gx:coord');
43049                 for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
43050                 var timeElems = get(root, 'when');
43051                 for (var j = 0; j < timeElems.length; j++) times.push(nodeVal(timeElems[j]));
43052                 return {
43053                     coords: coords,
43054                     times: times
43055                 };
43056             }
43057             function getGeometry(root) {
43058                 var geomNode, geomNodes, i, j, k, geoms = [], coordTimes = [];
43059                 if (get1(root, 'MultiGeometry')) { return getGeometry(get1(root, 'MultiGeometry')); }
43060                 if (get1(root, 'MultiTrack')) { return getGeometry(get1(root, 'MultiTrack')); }
43061                 if (get1(root, 'gx:MultiTrack')) { return getGeometry(get1(root, 'gx:MultiTrack')); }
43062                 for (i = 0; i < geotypes.length; i++) {
43063                     geomNodes = get(root, geotypes[i]);
43064                     if (geomNodes) {
43065                         for (j = 0; j < geomNodes.length; j++) {
43066                             geomNode = geomNodes[j];
43067                             if (geotypes[i] === 'Point') {
43068                                 geoms.push({
43069                                     type: 'Point',
43070                                     coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
43071                                 });
43072                             } else if (geotypes[i] === 'LineString') {
43073                                 geoms.push({
43074                                     type: 'LineString',
43075                                     coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
43076                                 });
43077                             } else if (geotypes[i] === 'Polygon') {
43078                                 var rings = get(geomNode, 'LinearRing'),
43079                                     coords = [];
43080                                 for (k = 0; k < rings.length; k++) {
43081                                     coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
43082                                 }
43083                                 geoms.push({
43084                                     type: 'Polygon',
43085                                     coordinates: coords
43086                                 });
43087                             } else if (geotypes[i] === 'Track' ||
43088                                 geotypes[i] === 'gx:Track') {
43089                                 var track = gxCoords(geomNode);
43090                                 geoms.push({
43091                                     type: 'LineString',
43092                                     coordinates: track.coords
43093                                 });
43094                                 if (track.times.length) coordTimes.push(track.times);
43095                             }
43096                         }
43097                     }
43098                 }
43099                 return {
43100                     geoms: geoms,
43101                     coordTimes: coordTimes
43102                 };
43103             }
43104             function getPlacemark(root) {
43105                 var geomsAndTimes = getGeometry(root), i, properties = {},
43106                     name = nodeVal(get1(root, 'name')),
43107                     address = nodeVal(get1(root, 'address')),
43108                     styleUrl = nodeVal(get1(root, 'styleUrl')),
43109                     description = nodeVal(get1(root, 'description')),
43110                     timeSpan = get1(root, 'TimeSpan'),
43111                     timeStamp = get1(root, 'TimeStamp'),
43112                     extendedData = get1(root, 'ExtendedData'),
43113                     lineStyle = get1(root, 'LineStyle'),
43114                     polyStyle = get1(root, 'PolyStyle'),
43115                     visibility = get1(root, 'visibility');
43116
43117                 if (!geomsAndTimes.geoms.length) return [];
43118                 if (name) properties.name = name;
43119                 if (address) properties.address = address;
43120                 if (styleUrl) {
43121                     if (styleUrl[0] !== '#') {
43122                         styleUrl = '#' + styleUrl;
43123                     }
43124
43125                     properties.styleUrl = styleUrl;
43126                     if (styleIndex[styleUrl]) {
43127                         properties.styleHash = styleIndex[styleUrl];
43128                     }
43129                     if (styleMapIndex[styleUrl]) {
43130                         properties.styleMapHash = styleMapIndex[styleUrl];
43131                         properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
43132                     }
43133                     // Try to populate the lineStyle or polyStyle since we got the style hash
43134                     var style = styleByHash[properties.styleHash];
43135                     if (style) {
43136                         if (!lineStyle) lineStyle = get1(style, 'LineStyle');
43137                         if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
43138                     }
43139                 }
43140                 if (description) properties.description = description;
43141                 if (timeSpan) {
43142                     var begin = nodeVal(get1(timeSpan, 'begin'));
43143                     var end = nodeVal(get1(timeSpan, 'end'));
43144                     properties.timespan = { begin: begin, end: end };
43145                 }
43146                 if (timeStamp) {
43147                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
43148                 }
43149                 if (lineStyle) {
43150                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
43151                         color = linestyles[0],
43152                         opacity = linestyles[1],
43153                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
43154                     if (color) properties.stroke = color;
43155                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
43156                     if (!isNaN(width)) properties['stroke-width'] = width;
43157                 }
43158                 if (polyStyle) {
43159                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
43160                         pcolor = polystyles[0],
43161                         popacity = polystyles[1],
43162                         fill = nodeVal(get1(polyStyle, 'fill')),
43163                         outline = nodeVal(get1(polyStyle, 'outline'));
43164                     if (pcolor) properties.fill = pcolor;
43165                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
43166                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
43167                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
43168                 }
43169                 if (extendedData) {
43170                     var datas = get(extendedData, 'Data'),
43171                         simpleDatas = get(extendedData, 'SimpleData');
43172
43173                     for (i = 0; i < datas.length; i++) {
43174                         properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
43175                     }
43176                     for (i = 0; i < simpleDatas.length; i++) {
43177                         properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
43178                     }
43179                 }
43180                 if (visibility) {
43181                     properties.visibility = nodeVal(visibility);
43182                 }
43183                 if (geomsAndTimes.coordTimes.length) {
43184                     properties.coordTimes = (geomsAndTimes.coordTimes.length === 1) ?
43185                         geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
43186                 }
43187                 var feature = {
43188                     type: 'Feature',
43189                     geometry: (geomsAndTimes.geoms.length === 1) ? geomsAndTimes.geoms[0] : {
43190                         type: 'GeometryCollection',
43191                         geometries: geomsAndTimes.geoms
43192                     },
43193                     properties: properties
43194                 };
43195                 if (attr(root, 'id')) feature.id = attr(root, 'id');
43196                 return [feature];
43197             }
43198             return gj;
43199         },
43200         gpx: function(doc) {
43201             var i,
43202                 tracks = get(doc, 'trk'),
43203                 routes = get(doc, 'rte'),
43204                 waypoints = get(doc, 'wpt'),
43205                 // a feature collection
43206                 gj = fc(),
43207                 feature;
43208             for (i = 0; i < tracks.length; i++) {
43209                 feature = getTrack(tracks[i]);
43210                 if (feature) gj.features.push(feature);
43211             }
43212             for (i = 0; i < routes.length; i++) {
43213                 feature = getRoute(routes[i]);
43214                 if (feature) gj.features.push(feature);
43215             }
43216             for (i = 0; i < waypoints.length; i++) {
43217                 gj.features.push(getPoint(waypoints[i]));
43218             }
43219             function getPoints(node, pointname) {
43220                 var pts = get(node, pointname),
43221                     line = [],
43222                     times = [],
43223                     heartRates = [],
43224                     l = pts.length;
43225                 if (l < 2) return {};  // Invalid line in GeoJSON
43226                 for (var i = 0; i < l; i++) {
43227                     var c = coordPair(pts[i]);
43228                     line.push(c.coordinates);
43229                     if (c.time) times.push(c.time);
43230                     if (c.heartRate) heartRates.push(c.heartRate);
43231                 }
43232                 return {
43233                     line: line,
43234                     times: times,
43235                     heartRates: heartRates
43236                 };
43237             }
43238             function getTrack(node) {
43239                 var segments = get(node, 'trkseg'),
43240                     track = [],
43241                     times = [],
43242                     heartRates = [],
43243                     line;
43244                 for (var i = 0; i < segments.length; i++) {
43245                     line = getPoints(segments[i], 'trkpt');
43246                     if (line) {
43247                         if (line.line) track.push(line.line);
43248                         if (line.times && line.times.length) times.push(line.times);
43249                         if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
43250                     }
43251                 }
43252                 if (track.length === 0) return;
43253                 var properties = getProperties(node);
43254                 extend(properties, getLineStyle(get1(node, 'extensions')));
43255                 if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
43256                 if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
43257                 return {
43258                     type: 'Feature',
43259                     properties: properties,
43260                     geometry: {
43261                         type: track.length === 1 ? 'LineString' : 'MultiLineString',
43262                         coordinates: track.length === 1 ? track[0] : track
43263                     }
43264                 };
43265             }
43266             function getRoute(node) {
43267                 var line = getPoints(node, 'rtept');
43268                 if (!line.line) return;
43269                 var prop = getProperties(node);
43270                 extend(prop, getLineStyle(get1(node, 'extensions')));
43271                 var routeObj = {
43272                     type: 'Feature',
43273                     properties: prop,
43274                     geometry: {
43275                         type: 'LineString',
43276                         coordinates: line.line
43277                     }
43278                 };
43279                 return routeObj;
43280             }
43281             function getPoint(node) {
43282                 var prop = getProperties(node);
43283                 extend(prop, getMulti(node, ['sym']));
43284                 return {
43285                     type: 'Feature',
43286                     properties: prop,
43287                     geometry: {
43288                         type: 'Point',
43289                         coordinates: coordPair(node).coordinates
43290                     }
43291                 };
43292             }
43293             function getLineStyle(extensions) {
43294                 var style = {};
43295                 if (extensions) {
43296                     var lineStyle = get1(extensions, 'line');
43297                     if (lineStyle) {
43298                         var color = nodeVal(get1(lineStyle, 'color')),
43299                             opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
43300                             width = parseFloat(nodeVal(get1(lineStyle, 'width')));
43301                         if (color) style.stroke = color;
43302                         if (!isNaN(opacity)) style['stroke-opacity'] = opacity;
43303                         // GPX width is in mm, convert to px with 96 px per inch
43304                         if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
43305                     }
43306                 }
43307                 return style;
43308             }
43309             function getProperties(node) {
43310                 var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
43311                     links = get(node, 'link');
43312                 if (links.length) prop.links = [];
43313                 for (var i = 0, link; i < links.length; i++) {
43314                     link = { href: attr(links[i], 'href') };
43315                     extend(link, getMulti(links[i], ['text', 'type']));
43316                     prop.links.push(link);
43317                 }
43318                 return prop;
43319             }
43320             return gj;
43321         }
43322     };
43323     return t;
43324 })();
43325
43326 module.exports = toGeoJSON;
43327 });
43328
43329 function svgGpx(projection$$1, context, dispatch$$1) {
43330     var showLabels = true,
43331         detected = utilDetect(),
43332         layer;
43333
43334
43335     function init() {
43336         if (svgGpx.initialized) return;  // run once
43337
43338         svgGpx.geojson = {};
43339         svgGpx.enabled = true;
43340
43341         function over() {
43342             event.stopPropagation();
43343             event.preventDefault();
43344             event.dataTransfer.dropEffect = 'copy';
43345         }
43346
43347         select('body')
43348             .attr('dropzone', 'copy')
43349             .on('drop.localgpx', function() {
43350                 event.stopPropagation();
43351                 event.preventDefault();
43352                 if (!detected.filedrop) return;
43353                 drawGpx.files(event.dataTransfer.files);
43354             })
43355             .on('dragenter.localgpx', over)
43356             .on('dragexit.localgpx', over)
43357             .on('dragover.localgpx', over);
43358
43359         svgGpx.initialized = true;
43360     }
43361
43362
43363     function drawGpx(selection$$1) {
43364         var geojson = svgGpx.geojson,
43365             enabled = svgGpx.enabled;
43366
43367         layer = selection$$1.selectAll('.layer-gpx')
43368             .data(enabled ? [0] : []);
43369
43370         layer.exit()
43371             .remove();
43372
43373         layer = layer.enter()
43374             .append('g')
43375             .attr('class', 'layer-gpx')
43376             .merge(layer);
43377
43378
43379         var paths = layer
43380             .selectAll('path')
43381             .data([geojson]);
43382
43383         paths.exit()
43384             .remove();
43385
43386         paths = paths.enter()
43387             .append('path')
43388             .attr('class', 'gpx')
43389             .merge(paths);
43390
43391
43392         var path$$1 = index$4(projection$$1);
43393
43394         paths
43395             .attr('d', path$$1);
43396
43397
43398         var labels = layer.selectAll('text')
43399             .data(showLabels && geojson.features ? geojson.features : []);
43400
43401         labels.exit()
43402             .remove();
43403
43404         labels = labels.enter()
43405             .append('text')
43406             .attr('class', 'gpx')
43407             .merge(labels);
43408
43409         labels
43410             .text(function(d) {
43411                 return d.properties.desc || d.properties.name;
43412             })
43413             .attr('x', function(d) {
43414                 var centroid = path$$1.centroid(d);
43415                 return centroid[0] + 7;
43416             })
43417             .attr('y', function(d) {
43418                 var centroid = path$$1.centroid(d);
43419                 return centroid[1];
43420             });
43421
43422     }
43423
43424
43425     function toDom(x) {
43426         return (new DOMParser()).parseFromString(x, 'text/xml');
43427     }
43428
43429
43430     function getExtension(fileName) {
43431         if (lodash.isUndefined(fileName)) {
43432             return '';
43433         }
43434
43435         var lastDotIndex = fileName.lastIndexOf('.');
43436         if (lastDotIndex < 0) {
43437             return '';
43438         }
43439
43440         return fileName.substr(lastDotIndex);
43441     }
43442
43443
43444     function parseSaveAndZoom(extension, data) {
43445         switch (extension) {
43446             default:
43447                 drawGpx.geojson(togeojson.gpx(toDom(data))).fitZoom();
43448                 break;
43449             case '.kml':
43450                 drawGpx.geojson(togeojson.kml(toDom(data))).fitZoom();
43451                 break;
43452             case '.geojson':
43453             case '.json':
43454                 drawGpx.geojson(JSON.parse(data)).fitZoom();
43455                 break;
43456         }
43457     }
43458
43459
43460     drawGpx.showLabels = function(_) {
43461         if (!arguments.length) return showLabels;
43462         showLabels = _;
43463         return this;
43464     };
43465
43466
43467     drawGpx.enabled = function(_) {
43468         if (!arguments.length) return svgGpx.enabled;
43469         svgGpx.enabled = _;
43470         dispatch$$1.call('change');
43471         return this;
43472     };
43473
43474
43475     drawGpx.hasGpx = function() {
43476         var geojson = svgGpx.geojson;
43477         return (!(lodash.isEmpty(geojson) || lodash.isEmpty(geojson.features)));
43478     };
43479
43480
43481     drawGpx.geojson = function(gj) {
43482         if (!arguments.length) return svgGpx.geojson;
43483         if (lodash.isEmpty(gj) || lodash.isEmpty(gj.features)) return this;
43484         svgGpx.geojson = gj;
43485         dispatch$$1.call('change');
43486         return this;
43487     };
43488
43489
43490     drawGpx.url = function(url) {
43491         text(url, function(err, data) {
43492             if (!err) {
43493                 var extension = getExtension(url);
43494                 parseSaveAndZoom(extension, data);
43495             }
43496         });
43497         return this;
43498     };
43499
43500
43501     drawGpx.files = function(fileList) {
43502         if (!fileList.length) return this;
43503         var f = fileList[0],
43504             reader = new FileReader();
43505
43506         reader.onload = (function(file) {
43507             var extension = getExtension(file.name);
43508
43509             return function (e) {
43510                 parseSaveAndZoom(extension, e.target.result);
43511             };
43512         })(f);
43513
43514         reader.readAsText(f);
43515         return this;
43516     };
43517
43518
43519     drawGpx.fitZoom = function() {
43520         if (!this.hasGpx()) return this;
43521         var geojson = svgGpx.geojson;
43522
43523         var map = context.map(),
43524             viewport = map.trimmedExtent().polygon(),
43525             coords = lodash.reduce(geojson.features, function(coords, feature) {
43526                 var c = feature.geometry.coordinates;
43527
43528                 /* eslint-disable no-fallthrough */
43529                 switch (feature.geometry.type) {
43530                     case 'Point':
43531                         c = [c];
43532                     case 'MultiPoint':
43533                     case 'LineString':
43534                         break;
43535
43536                     case 'MultiPolygon':
43537                         c = lodash.flatten(c);
43538                     case 'Polygon':
43539                     case 'MultiLineString':
43540                         c = lodash.flatten(c);
43541                         break;
43542                 }
43543                 /* eslint-enable no-fallthrough */
43544
43545                 return lodash.union(coords, c);
43546             }, []);
43547
43548         if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
43549             var extent$$1 = geoExtent$$1(bounds({ type: 'LineString', coordinates: coords }));
43550             map.centerZoom(extent$$1.center(), map.trimmedExtentZoom(extent$$1));
43551         }
43552
43553         return this;
43554     };
43555
43556
43557     init();
43558     return drawGpx;
43559 }
43560
43561 function svgIcon(name, svgklass, useklass) {
43562     return function drawIcon(selection) {
43563         selection.selectAll('svg')
43564             .data([0])
43565             .enter()
43566             .append('svg')
43567             .attr('class', 'icon ' + (svgklass || ''))
43568             .append('use')
43569             .attr('xlink:href', name)
43570             .attr('class', useklass);
43571     };
43572 }
43573
43574 function svgLabels(projection$$1, context) {
43575     var path$$1 = index$4(projection$$1),
43576         detected = utilDetect(),
43577         baselineHack = (detected.ie || detected.browser.toLowerCase() === 'edge'),
43578         rdrawn = index$9(),
43579         rskipped = index$9(),
43580         textWidthCache = {},
43581         entitybboxes = {};
43582
43583     // Listed from highest to lowest priority
43584     var labelStack = [
43585         ['line', 'aeroway', '*', 12],
43586         ['line', 'highway', 'motorway', 12],
43587         ['line', 'highway', 'trunk', 12],
43588         ['line', 'highway', 'primary', 12],
43589         ['line', 'highway', 'secondary', 12],
43590         ['line', 'highway', 'tertiary', 12],
43591         ['line', 'highway', '*', 12],
43592         ['line', 'railway', '*', 12],
43593         ['line', 'waterway', '*', 12],
43594         ['area', 'aeroway', '*', 12],
43595         ['area', 'amenity', '*', 12],
43596         ['area', 'building', '*', 12],
43597         ['area', 'historic', '*', 12],
43598         ['area', 'leisure', '*', 12],
43599         ['area', 'man_made', '*', 12],
43600         ['area', 'natural', '*', 12],
43601         ['area', 'shop', '*', 12],
43602         ['area', 'tourism', '*', 12],
43603         ['area', 'camp_site', '*', 12],
43604         ['point', 'aeroway', '*', 10],
43605         ['point', 'amenity', '*', 10],
43606         ['point', 'building', '*', 10],
43607         ['point', 'historic', '*', 10],
43608         ['point', 'leisure', '*', 10],
43609         ['point', 'man_made', '*', 10],
43610         ['point', 'natural', '*', 10],
43611         ['point', 'shop', '*', 10],
43612         ['point', 'tourism', '*', 10],
43613         ['point', 'camp_site', '*', 10],
43614         ['line', 'name', '*', 12],
43615         ['area', 'name', '*', 12],
43616         ['point', 'name', '*', 10]
43617     ];
43618
43619
43620     function blacklisted(preset) {
43621         var noIcons = ['building', 'landuse', 'natural'];
43622         return lodash.some(noIcons, function(s) {
43623             return preset.id.indexOf(s) >= 0;
43624         });
43625     }
43626
43627
43628     function get(array, prop) {
43629         return function(d, i) { return array[i][prop]; };
43630     }
43631
43632
43633     function textWidth(text$$1, size, elem) {
43634         var c = textWidthCache[size];
43635         if (!c) c = textWidthCache[size] = {};
43636
43637         if (c[text$$1]) {
43638             return c[text$$1];
43639
43640         } else if (elem) {
43641             c[text$$1] = elem.getComputedTextLength();
43642             return c[text$$1];
43643
43644         } else {
43645             var str = encodeURIComponent(text$$1).match(/%[CDEFcdef]/g);
43646             if (str === null) {
43647                 return size / 3 * 2 * text$$1.length;
43648             } else {
43649                 return size / 3 * (2 * text$$1.length + str.length);
43650             }
43651         }
43652     }
43653
43654
43655     function drawLinePaths(selection$$1, entities, filter, classes, labels) {
43656         var paths = selection$$1.selectAll('path')
43657             .filter(filter)
43658             .data(entities, osmEntity$$1.key);
43659
43660         paths.exit()
43661             .remove();
43662
43663         paths.enter()
43664             .append('path')
43665             .style('stroke-width', get(labels, 'font-size'))
43666             .attr('id', function(d) { return 'labelpath-' + d.id; })
43667             .attr('class', classes)
43668             .merge(paths)
43669             .attr('d', get(labels, 'lineString'));
43670     }
43671
43672
43673     function drawLineLabels(selection$$1, entities, filter, classes, labels) {
43674         var texts = selection$$1.selectAll('text.' + classes)
43675             .filter(filter)
43676             .data(entities, osmEntity$$1.key);
43677
43678         texts.exit()
43679             .remove();
43680
43681         texts.enter()
43682             .append('text')
43683             .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
43684             .attr('dy', baselineHack ? '0.35em' : null)
43685             .append('textPath')
43686             .attr('class', 'textpath');
43687
43688         texts = selection$$1.selectAll('text.' + classes);
43689
43690         texts.selectAll('.textpath')
43691             .filter(filter)
43692             .data(entities, osmEntity$$1.key)
43693             .attr('startOffset', '50%')
43694             .attr('xlink:href', function(d) { return '#labelpath-' + d.id; })
43695             .text(utilDisplayNameForPath);
43696     }
43697
43698
43699     function drawPointLabels(selection$$1, entities, filter, classes, labels) {
43700         var texts = selection$$1.selectAll('text.' + classes)
43701             .filter(filter)
43702             .data(entities, osmEntity$$1.key);
43703
43704         texts.exit()
43705             .remove();
43706
43707         texts = texts.enter()
43708             .append('text')
43709             .attr('class', function(d, i) {
43710                 return classes + ' ' + labels[i].classes + ' ' + d.id;
43711             })
43712             .merge(texts);
43713
43714         texts
43715             .attr('x', get(labels, 'x'))
43716             .attr('y', get(labels, 'y'))
43717             .style('text-anchor', get(labels, 'textAnchor'))
43718             .text(utilDisplayName)
43719             .each(function(d, i) {
43720                 textWidth(utilDisplayName(d), labels[i].height, this);
43721             });
43722     }
43723
43724
43725     function drawAreaLabels(selection$$1, entities, filter, classes, labels) {
43726         entities = entities.filter(hasText);
43727         labels = labels.filter(hasText);
43728         drawPointLabels(selection$$1, entities, filter, classes, labels);
43729
43730         function hasText(d, i) {
43731             return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
43732         }
43733     }
43734
43735
43736     function drawAreaIcons(selection$$1, entities, filter, classes, labels) {
43737         var icons = selection$$1.selectAll('use.' + classes)
43738             .filter(filter)
43739             .data(entities, osmEntity$$1.key);
43740
43741         icons.exit()
43742             .remove();
43743
43744         icons = icons.enter()
43745             .append('use')
43746             .attr('class', 'icon ' + classes)
43747             .attr('width', '17px')
43748             .attr('height', '17px')
43749             .merge(icons);
43750
43751         icons
43752             .attr('transform', get(labels, 'transform'))
43753             .attr('xlink:href', function(d) {
43754                 var preset = context.presets().match(d, context.graph()),
43755                     picon = preset && preset.icon;
43756
43757                 if (!picon)
43758                     return '';
43759                 else {
43760                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
43761                     return '#' + picon + (isMaki ? '-15' : '');
43762                 }
43763             });
43764     }
43765
43766
43767     function drawCollisionBoxes(selection$$1, rtree, which) {
43768         var showDebug = context.getDebug('collision'),
43769             classes = 'debug ' + which + ' ' +
43770                 (which === 'debug-skipped' ? 'orange' : 'yellow');
43771
43772         var debug = selection$$1.selectAll('.layer-label-debug')
43773                 .data(showDebug ? [true] : []);
43774
43775         debug.exit()
43776             .remove();
43777
43778         debug = debug.enter()
43779             .append('g')
43780             .attr('class', 'layer-label-debug')
43781             .merge(debug);
43782
43783         if (showDebug) {
43784             var gj = rtree.all().map(function(d) {
43785                 return { type: 'Polygon', coordinates: [[
43786                     [d.minX, d.minY],
43787                     [d.maxX, d.minY],
43788                     [d.maxX, d.maxY],
43789                     [d.minX, d.maxY],
43790                     [d.minX, d.minY]
43791                 ]]};
43792             });
43793
43794             var debugboxes = debug.selectAll('.' + which)
43795                 .data(gj);
43796
43797             debugboxes.exit()
43798                 .remove();
43799
43800             debugboxes = debugboxes.enter()
43801                 .append('path')
43802                 .attr('class', classes)
43803                 .merge(debugboxes);
43804
43805             debugboxes
43806                 .attr('d', index$4());
43807         }
43808     }
43809
43810
43811     function drawLabels(selection$$1, graph, entities, filter, dimensions, fullRedraw) {
43812         var lowZoom = context.surface().classed('low-zoom');
43813
43814         var labelable = [], i, j, k, entity, geometry;
43815         for (i = 0; i < labelStack.length; i++) {
43816             labelable.push([]);
43817         }
43818
43819         if (fullRedraw) {
43820             rdrawn.clear();
43821             rskipped.clear();
43822             entitybboxes = {};
43823         } else {
43824             for (i = 0; i < entities.length; i++) {
43825                 entity = entities[i];
43826                 var toRemove = []
43827                     .concat(entitybboxes[entity.id] || [])
43828                     .concat(entitybboxes[entity.id + 'I'] || []);
43829
43830                 for (j = 0; j < toRemove.length; j++) {
43831                     rdrawn.remove(toRemove[j]);
43832                     rskipped.remove(toRemove[j]);
43833                 }
43834             }
43835         }
43836
43837         // Split entities into groups specified by labelStack
43838         for (i = 0; i < entities.length; i++) {
43839             entity = entities[i];
43840             geometry = entity.geometry(graph);
43841             if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43842
43843             var preset = geometry === 'area' && context.presets().match(entity, graph),
43844                 icon = preset && !blacklisted(preset) && preset.icon;
43845
43846             if (!icon && !utilDisplayName(entity))
43847                 continue;
43848
43849             for (k = 0; k < labelStack.length; k++) {
43850                 var matchGeom = labelStack[k][0],
43851                     matchKey = labelStack[k][1],
43852                     matchVal = labelStack[k][2],
43853                     hasVal = entity.tags[matchKey];
43854
43855                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
43856                     labelable[k].push(entity);
43857                     break;
43858                 }
43859             }
43860         }
43861
43862         var positions = {
43863             point: [],
43864             line: [],
43865             area: []
43866         };
43867
43868         var labelled = {
43869             point: [],
43870             line: [],
43871             area: []
43872         };
43873
43874         // Try and find a valid label for labellable entities
43875         for (k = 0; k < labelable.length; k++) {
43876             var fontSize = labelStack[k][3];
43877             for (i = 0; i < labelable[k].length; i++) {
43878                 entity = labelable[k][i];
43879                 geometry = entity.geometry(graph);
43880
43881                 var getName = (geometry === 'line') ? utilDisplayNameForPath : utilDisplayName,
43882                     name = getName(entity),
43883                     width = name && textWidth(name, fontSize),
43884                     p;
43885
43886                 if (geometry === 'point') {
43887                     p = getPointLabel(entity, width, fontSize, geometry);
43888                 } else if (geometry === 'vertex' && !lowZoom) {
43889                     // don't label vertices at low zoom because they don't have icons
43890                     p = getPointLabel(entity, width, fontSize, geometry);
43891                 } else if (geometry === 'line') {
43892                     p = getLineLabel(entity, width, fontSize);
43893                 } else if (geometry === 'area') {
43894                     p = getAreaLabel(entity, width, fontSize);
43895                 }
43896
43897                 if (p) {
43898                     if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43899                     p.classes = geometry + ' tag-' + labelStack[k][1];
43900                     positions[geometry].push(p);
43901                     labelled[geometry].push(entity);
43902                 }
43903             }
43904         }
43905
43906
43907         function getPointLabel(entity, width, height, geometry) {
43908             var y = (geometry === 'point' ? -12 : 0),
43909                 pointOffsets = {
43910                     ltr: [15, y, 'start'],
43911                     rtl: [-15, y, 'end']
43912                 };
43913
43914             var coord = projection$$1(entity.loc),
43915                 margin = 2,
43916                 offset = pointOffsets[textDirection],
43917                 p = {
43918                     height: height,
43919                     width: width,
43920                     x: coord[0] + offset[0],
43921                     y: coord[1] + offset[1],
43922                     textAnchor: offset[2]
43923                 },
43924                 bbox;
43925
43926             if (textDirection === 'rtl') {
43927                 bbox = {
43928                     minX: p.x - width - margin,
43929                     minY: p.y - (height / 2) - margin,
43930                     maxX: p.x + margin,
43931                     maxY: p.y + (height / 2) + margin
43932                 };
43933             } else {
43934                 bbox = {
43935                     minX: p.x - margin,
43936                     minY: p.y - (height / 2) - margin,
43937                     maxX: p.x + width + margin,
43938                     maxY: p.y + (height / 2) + margin
43939                 };
43940             }
43941
43942             if (tryInsert([bbox], entity.id, true)) {
43943                 return p;
43944             }
43945         }
43946
43947
43948         function getLineLabel(entity, width, height) {
43949             var viewport = geoExtent$$1(context.projection.clipExtent()).polygon(),
43950                 nodes = lodash.map(graph.childNodes(entity), 'loc').map(projection$$1),
43951                 length = geoPathLength(nodes);
43952
43953             if (length < width + 20) return;
43954
43955             // % along the line to attempt to place the label
43956             var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70,
43957                                25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
43958             var margin = 3;
43959
43960             for (var i = 0; i < lineOffsets.length; i++) {
43961                 var offset = lineOffsets[i],
43962                     middle = offset / 100 * length,
43963                     start = middle - width / 2;
43964
43965                 if (start < 0 || start + width > length) continue;
43966
43967                 // generate subpath and ignore paths that are invalid or don't cross viewport.
43968                 var sub = subpath(nodes, start, start + width);
43969                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
43970                     continue;
43971                 }
43972
43973                 var isReverse = reverse$$1(sub);
43974                 if (isReverse) {
43975                     sub = sub.reverse();
43976                 }
43977
43978                 var bboxes = [],
43979                     boxsize = (height + 2) / 2;
43980
43981                 for (var j = 0; j < sub.length - 1; j++) {
43982                     var a = sub[j];
43983                     var b = sub[j + 1];
43984                     var num = Math.max(1, Math.floor(geoEuclideanDistance(a, b) / boxsize / 2));
43985
43986                     for (var box = 0; box < num; box++) {
43987                         var p = geoInterp(a, b, box / num);
43988                         var x0 = p[0] - boxsize - margin;
43989                         var y0 = p[1] - boxsize - margin;
43990                         var x1 = p[0] + boxsize + margin;
43991                         var y1 = p[1] + boxsize + margin;
43992
43993                         bboxes.push({
43994                             minX: Math.min(x0, x1),
43995                             minY: Math.min(y0, y1),
43996                             maxX: Math.max(x0, x1),
43997                             maxY: Math.max(y0, y1)
43998                         });
43999                     }
44000                 }
44001
44002                 if (tryInsert(bboxes, entity.id, false)) {
44003                     return {
44004                         'font-size': height + 2,
44005                         lineString: lineString(sub),
44006                         startOffset: offset + '%'
44007                     };
44008                 }
44009             }
44010
44011             function reverse$$1(p) {
44012                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
44013                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
44014             }
44015
44016             function lineString(nodes) {
44017                 return 'M' + nodes.join('L');
44018             }
44019
44020             function subpath(nodes, from, to) {
44021                 var sofar = 0,
44022                     start, end, i0, i1;
44023
44024                 for (var i = 0; i < nodes.length - 1; i++) {
44025                     var a = nodes[i],
44026                         b = nodes[i + 1];
44027                     var current = geoEuclideanDistance(a, b);
44028                     var portion;
44029                     if (!start && sofar + current >= from) {
44030                         portion = (from - sofar) / current;
44031                         start = [
44032                             a[0] + portion * (b[0] - a[0]),
44033                             a[1] + portion * (b[1] - a[1])
44034                         ];
44035                         i0 = i + 1;
44036                     }
44037                     if (!end && sofar + current >= to) {
44038                         portion = (to - sofar) / current;
44039                         end = [
44040                             a[0] + portion * (b[0] - a[0]),
44041                             a[1] + portion * (b[1] - a[1])
44042                         ];
44043                         i1 = i + 1;
44044                     }
44045                     sofar += current;
44046                 }
44047
44048                 var ret = nodes.slice(i0, i1);
44049                 ret.unshift(start);
44050                 ret.push(end);
44051                 return ret;
44052             }
44053         }
44054
44055
44056         function getAreaLabel(entity, width, height) {
44057             var centroid = path$$1.centroid(entity.asGeoJSON(graph, true)),
44058                 extent$$1 = entity.extent(graph),
44059                 entitywidth = projection$$1(extent$$1[1])[0] - projection$$1(extent$$1[0])[0];
44060
44061             if (isNaN(centroid[0]) || entitywidth < 20) return;
44062
44063             var iconSize = 20,
44064                 iconX = centroid[0] - (iconSize / 2),
44065                 iconY = centroid[1] - (iconSize / 2),
44066                 margin = 2,
44067                 textOffset = iconSize + margin,
44068                 p = { transform: 'translate(' + iconX + ',' + iconY + ')' };
44069
44070             var bbox = {
44071                 minX: iconX,
44072                 minY: iconY,
44073                 maxX: iconX + iconSize,
44074                 maxY: iconY + iconSize
44075             };
44076
44077             // try to add icon
44078             if (tryInsert([bbox], entity.id + 'I', true)) {
44079                 if (width && entitywidth >= width + 20) {
44080                     var labelX = centroid[0],
44081                         labelY = centroid[1] + textOffset;
44082
44083                     bbox = {
44084                         minX: labelX - (width / 2) - margin,
44085                         minY: labelY - (height / 2) - margin,
44086                         maxX: labelX + (width / 2) + margin,
44087                         maxY: labelY + (height / 2) + margin
44088                     };
44089
44090                     // try to add label
44091                     if (tryInsert([bbox], entity.id, true)) {
44092                         p.x = labelX;
44093                         p.y = labelY;
44094                         p.textAnchor = 'middle';
44095                         p.height = height;
44096                     }
44097                 }
44098
44099                 return p;
44100             }
44101         }
44102
44103
44104         function tryInsert(bboxes, id, saveSkipped) {
44105             var skipped = false,
44106                 bbox;
44107
44108             for (var i = 0; i < bboxes.length; i++) {
44109                 bbox = bboxes[i];
44110                 bbox.id = id;
44111
44112                 // Check that label is visible
44113                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
44114                     skipped = true;
44115                     break;
44116                 }
44117                 if (rdrawn.collides(bbox)) {
44118                     skipped = true;
44119                     break;
44120                 }
44121             }
44122
44123             entitybboxes[id] = bboxes;
44124
44125             if (skipped) {
44126                 if (saveSkipped) {
44127                     rskipped.load(bboxes);
44128                 }
44129             } else {
44130                 rdrawn.load(bboxes);
44131             }
44132
44133             return !skipped;
44134         }
44135
44136
44137         var label = selection$$1.selectAll('.layer-label'),
44138             halo = selection$$1.selectAll('.layer-halo');
44139
44140         // points
44141         drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
44142         drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
44143
44144         // lines
44145         drawLinePaths(halo, labelled.line, filter, '', positions.line);
44146         drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
44147         drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
44148
44149         // areas
44150         drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
44151         drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
44152         drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
44153         drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area);
44154
44155         // debug
44156         drawCollisionBoxes(label, rskipped, 'debug-skipped');
44157         drawCollisionBoxes(label, rdrawn, 'debug-drawn');
44158
44159         selection$$1.call(filterLabels);
44160     }
44161
44162
44163     function filterLabels(selection$$1) {
44164         var layers = selection$$1
44165             .selectAll('.layer-label, .layer-halo');
44166
44167         layers.selectAll('.proximate')
44168             .classed('proximate', false);
44169
44170         var mouse$$1 = context.mouse(),
44171             graph = context.graph(),
44172             selectedIDs = context.selectedIDs(),
44173             ids = [],
44174             pad, bbox;
44175
44176         // hide labels near the mouse
44177         if (mouse$$1) {
44178             pad = 20;
44179             bbox = { minX: mouse$$1[0] - pad, minY: mouse$$1[1] - pad, maxX: mouse$$1[0] + pad, maxY: mouse$$1[1] + pad };
44180             ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
44181         }
44182
44183         // hide labels along selected ways, or near selected vertices
44184         for (var i = 0; i < selectedIDs.length; i++) {
44185             var entity = graph.hasEntity(selectedIDs[i]);
44186             if (!entity) continue;
44187             var geometry = entity.geometry(graph);
44188
44189             if (geometry === 'line') {
44190                 ids.push(selectedIDs[i]);
44191             } else if (geometry === 'vertex') {
44192                 var point = context.projection(entity.loc);
44193                 pad = 10;
44194                 bbox = { minX: point[0] - pad, minY: point[1] - pad, maxX: point[0] + pad, maxY: point[1] + pad };
44195                 ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
44196             }
44197         }
44198
44199         layers.selectAll(utilEntitySelector(ids))
44200             .classed('proximate', true);
44201     }
44202
44203
44204     var throttleFilterLabels = lodash.throttle(filterLabels, 100);
44205
44206
44207     drawLabels.observe = function(selection$$1) {
44208         var listener = function() { throttleFilterLabels(selection$$1); };
44209         selection$$1.on('mousemove.hidelabels', listener);
44210         context.on('enter.hidelabels', listener);
44211     };
44212
44213
44214     drawLabels.off = function(selection$$1) {
44215         throttleFilterLabels.cancel();
44216         selection$$1.on('mousemove.hidelabels', null);
44217         context.on('enter.hidelabels', null);
44218     };
44219
44220
44221     return drawLabels;
44222 }
44223
44224 function refresh(selection, node) {
44225     var cr = node.getBoundingClientRect();
44226     var prop = [cr.width, cr.height];
44227     selection.property('__dimensions__', prop);
44228     return prop;
44229 }
44230
44231 function utilGetDimensions(selection, force) {
44232     if (!selection || selection.empty()) {
44233         return [0, 0];
44234     }
44235     var node = selection.node(),
44236         cached = selection.property('__dimensions__');
44237     return (!cached || force) ? refresh(selection, node) : cached;
44238 }
44239
44240
44241 function utilSetDimensions(selection, dimensions) {
44242     if (!selection || selection.empty()) {
44243         return selection;
44244     }
44245     var node = selection.node();
44246     if (dimensions === null) {
44247         refresh(selection, node);
44248         return selection;
44249     }
44250     return selection
44251         .property('__dimensions__', [dimensions[0], dimensions[1]])
44252         .attr('width', dimensions[0])
44253         .attr('height', dimensions[1]);
44254 }
44255
44256 function svgPointTransform(projection) {
44257     return function(entity) {
44258         // http://jsperf.com/short-array-join
44259         var pt = projection(entity.loc);
44260         return 'translate(' + pt[0] + ',' + pt[1] + ')';
44261     };
44262 }
44263
44264 function d3geoTile() {
44265   var size = [960, 500],
44266       scale = 256,
44267       scaleExtent = [0, 20],
44268       translate = [size[0] / 2, size[1] / 2],
44269       zoomDelta = 0;
44270
44271   function bound(_) {
44272       return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
44273   }
44274
44275   function tile() {
44276     var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
44277         z0 = bound(Math.round(z + zoomDelta)),
44278         k = Math.pow(2, z - z0 + 8),
44279         origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
44280         tiles = [],
44281         cols = sequence(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
44282         rows = sequence(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
44283
44284     rows.forEach(function(y) {
44285       cols.forEach(function(x) {
44286         tiles.push([x, y, z0]);
44287       });
44288     });
44289
44290     tiles.translate = origin;
44291     tiles.scale = k;
44292
44293     return tiles;
44294   }
44295
44296   tile.scaleExtent = function(_) {
44297     if (!arguments.length) return scaleExtent;
44298     scaleExtent = _;
44299     return tile;
44300   };
44301
44302   tile.size = function(_) {
44303     if (!arguments.length) return size;
44304     size = _;
44305     return tile;
44306   };
44307
44308   tile.scale = function(_) {
44309     if (!arguments.length) return scale;
44310     scale = _;
44311     return tile;
44312   };
44313
44314   tile.translate = function(_) {
44315     if (!arguments.length) return translate;
44316     translate = _;
44317     return tile;
44318   };
44319
44320   tile.zoomDelta = function(_) {
44321     if (!arguments.length) return zoomDelta;
44322     zoomDelta = +_;
44323     return tile;
44324   };
44325
44326   return tile;
44327 }
44328
44329 /* global Mapillary:false */
44330 var apibase = 'https://a.mapillary.com/v3/';
44331 var viewercss = 'mapillary-js/mapillary.min.css';
44332 var viewerjs = 'mapillary-js/mapillary.min.js';
44333 var clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
44334 var maxResults = 1000;
44335 var tileZoom = 14;
44336 var dispatch$2 = dispatch('loadedImages', 'loadedSigns');
44337 var mapillaryCache;
44338 var mapillaryClicks;
44339 var mapillaryImage;
44340 var mapillarySignDefs;
44341 var mapillarySignSprite;
44342 var mapillaryViewer;
44343
44344
44345 function abortRequest(i) {
44346     i.abort();
44347 }
44348
44349
44350 function nearNullIsland(x, y, z) {
44351     if (z >= 7) {
44352         var center = Math.pow(2, z - 1),
44353             width = Math.pow(2, z - 6),
44354             min$$1 = center - (width / 2),
44355             max$$1 = center + (width / 2) - 1;
44356         return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
44357     }
44358     return false;
44359 }
44360
44361
44362 function maxPageAtZoom(z) {
44363     if (z < 15)   return 2;
44364     if (z === 15) return 5;
44365     if (z === 16) return 10;
44366     if (z === 17) return 20;
44367     if (z === 18) return 40;
44368     if (z > 18)   return 80;
44369 }
44370
44371
44372 function getTiles(projection$$1) {
44373     var s = projection$$1.scale() * 2 * Math.PI,
44374         z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
44375         ts = 256 * Math.pow(2, z - tileZoom),
44376         origin = [
44377             s / 2 - projection$$1.translate()[0],
44378             s / 2 - projection$$1.translate()[1]];
44379
44380     return d3geoTile()
44381         .scaleExtent([tileZoom, tileZoom])
44382         .scale(s)
44383         .size(projection$$1.clipExtent()[1])
44384         .translate(projection$$1.translate())()
44385         .map(function(tile) {
44386             var x = tile[0] * ts - origin[0],
44387                 y = tile[1] * ts - origin[1];
44388
44389             return {
44390                 id: tile.toString(),
44391                 xyz: tile,
44392                 extent: geoExtent$$1(
44393                     projection$$1.invert([x, y + ts]),
44394                     projection$$1.invert([x + ts, y])
44395                 )
44396             };
44397         });
44398 }
44399
44400
44401 function loadTiles(which, url, projection$$1) {
44402     var s = projection$$1.scale() * 2 * Math.PI,
44403         currZoom = Math.floor(Math.max(Math.log(s) / Math.log(2) - 8, 0));
44404
44405     var tiles = getTiles(projection$$1).filter(function(t) {
44406             return !nearNullIsland(t.xyz[0], t.xyz[1], t.xyz[2]);
44407         });
44408
44409     lodash.filter(which.inflight, function(v, k) {
44410         var wanted = lodash.find(tiles, function(tile) { return k === (tile.id + ',0'); });
44411         if (!wanted) delete which.inflight[k];
44412         return !wanted;
44413     }).map(abortRequest);
44414
44415     tiles.forEach(function(tile) {
44416         loadNextTilePage(which, currZoom, url, tile);
44417     });
44418 }
44419
44420
44421 function loadNextTilePage(which, currZoom, url, tile) {
44422     var cache = mapillaryCache[which],
44423         rect = tile.extent.rectangle(),
44424         maxPages = maxPageAtZoom(currZoom),
44425         nextPage = cache.nextPage[tile.id] || 0,
44426         nextURL = cache.nextURL[tile.id] || url +
44427             utilQsString({
44428                 per_page: maxResults,
44429                 page: nextPage,
44430                 client_id: clientId,
44431                 bbox: [rect[0], rect[1], rect[2], rect[3]].join(','),
44432             });
44433
44434     if (nextPage > maxPages) return;
44435
44436     var id = tile.id + ',' + String(nextPage);
44437     if (cache.loaded[id] || cache.inflight[id]) return;
44438     cache.inflight[id] = request(nextURL)
44439         .mimeType('application/json')
44440         .response(function(xhr) {
44441             var linkHeader = xhr.getResponseHeader('Link');
44442             if (linkHeader) {
44443                 var pagination = parsePagination(xhr.getResponseHeader('Link'));
44444                 if (pagination.next) {
44445                     cache.nextURL[tile.id] = pagination.next;
44446                 }
44447             }
44448             return JSON.parse(xhr.responseText);
44449         })
44450         .get(function(err, data) {
44451             cache.loaded[id] = true;
44452             delete cache.inflight[id];
44453             if (err || !data.features || !data.features.length) return;
44454
44455             var features = data.features.map(function(feature) {
44456                 var loc = feature.geometry.coordinates,
44457                     d;
44458
44459                 if (which === 'images') {
44460                     d = {
44461                         loc: loc,
44462                         key: feature.properties.key,
44463                         ca: feature.properties.ca,
44464                         captured_at: feature.properties.captured_at,
44465                         pano: feature.properties.pano
44466                     };
44467                 } else if (which === 'objects') {
44468                     d = {
44469                         loc: loc,
44470                         key: feature.properties.key,
44471                         value: feature.properties.value,
44472                         package: feature.properties.package,
44473                         detections: feature.properties.detections
44474                     };
44475
44476                     // cache image_key -> detection_key
44477                     feature.properties.detections.forEach(function(detection) {
44478                         var ik = detection.image_key;
44479                         var dk = detection.detection_key;
44480                         if (!mapillaryCache.detections[ik]) {
44481                             mapillaryCache.detections[ik] = {};
44482                         }
44483                         if (!mapillaryCache.detections[ik][dk]) {
44484                             mapillaryCache.detections[ik][dk] = {};
44485                         }
44486                     });
44487                 }
44488
44489                 return {
44490                     minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d
44491                 };
44492             });
44493
44494             cache.rtree.load(features);
44495
44496             if (which === 'images') {
44497                 dispatch$2.call('loadedImages');
44498             } else if (which === 'objects') {
44499                 dispatch$2.call('loadedSigns');
44500             }
44501
44502             if (data.features.length === maxResults) {  // more pages to load
44503                 cache.nextPage[tile.id] = nextPage + 1;
44504                 loadNextTilePage(which, currZoom, url, tile);
44505             } else {
44506                 cache.nextPage[tile.id] = Infinity;     // no more pages to load
44507             }
44508         });
44509 }
44510
44511 // extract links to pages of API results
44512 function parsePagination(links) {
44513     return links.split(',').map(function(rel) {
44514         var elements = rel.split(';');
44515         if (elements.length === 2) {
44516             return [
44517                 /<(.+)>/.exec(elements[0])[1],
44518                 /rel="(.+)"/.exec(elements[1])[1]
44519                 ];
44520         } else {
44521             return ['',''];
44522         }
44523     }).reduce(function(pagination, val) {
44524         pagination[val[1]] = val[0];
44525         return pagination;
44526     }, {});
44527 }
44528
44529
44530 // partition viewport into `psize` x `psize` regions
44531 function partitionViewport(psize, projection$$1) {
44532     var dimensions = projection$$1.clipExtent()[1];
44533     psize = psize || 16;
44534     var cols = sequence(0, dimensions[0], psize),
44535         rows = sequence(0, dimensions[1], psize),
44536         partitions = [];
44537
44538     rows.forEach(function(y) {
44539         cols.forEach(function(x) {
44540             var min$$1 = [x, y + psize],
44541                 max$$1 = [x + psize, y];
44542             partitions.push(
44543                 geoExtent$$1(projection$$1.invert(min$$1), projection$$1.invert(max$$1)));
44544         });
44545     });
44546
44547     return partitions;
44548 }
44549
44550
44551 // no more than `limit` results per partition.
44552 function searchLimited(psize, limit, projection$$1, rtree) {
44553     limit = limit || 3;
44554
44555     var partitions = partitionViewport(psize, projection$$1);
44556     return lodash.flatten(lodash.compact(lodash.map(partitions, function(extent$$1) {
44557         return rtree.search(extent$$1.bbox())
44558             .slice(0, limit)
44559             .map(function(d) { return d.data; });
44560     })));
44561 }
44562
44563
44564
44565 var serviceMapillary = {
44566
44567     init: function() {
44568         if (!mapillaryCache) {
44569             this.reset();
44570         }
44571
44572         this.event = utilRebind(this, dispatch$2, 'on');
44573     },
44574
44575     reset: function() {
44576         var cache = mapillaryCache;
44577
44578         if (cache) {
44579             if (cache.images && cache.images.inflight) {
44580                 lodash.forEach(cache.images.inflight, abortRequest);
44581             }
44582             if (cache.objects && cache.objects.inflight) {
44583                 lodash.forEach(cache.objects.inflight, abortRequest);
44584             }
44585         }
44586
44587         mapillaryCache = {
44588             images: { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: index$9() },
44589             objects:  { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: index$9() },
44590             detections: {}
44591         };
44592
44593         mapillaryImage = null;
44594         mapillaryClicks = [];
44595     },
44596
44597
44598     images: function(projection$$1) {
44599         var psize = 16, limit = 3;
44600         return searchLimited(psize, limit, projection$$1, mapillaryCache.images.rtree);
44601     },
44602
44603
44604     signs: function(projection$$1) {
44605         var psize = 32, limit = 3;
44606         return searchLimited(psize, limit, projection$$1, mapillaryCache.objects.rtree);
44607     },
44608
44609
44610     signsSupported: function() {
44611         var detected = utilDetect();
44612         if (detected.ie) return false;
44613         if ((detected.browser.toLowerCase() === 'safari') && (parseFloat(detected.version) < 10)) return false;
44614         return true;
44615     },
44616
44617
44618     signHTML: function(d) {
44619         if (!mapillarySignDefs || !mapillarySignSprite) return;
44620         var position = mapillarySignDefs[d.value];
44621         if (!position) return '<div></div>';
44622         var iconStyle = [
44623             'background-image:url(' + mapillarySignSprite + ')',
44624             'background-repeat:no-repeat',
44625             'height:' + position.height + 'px',
44626             'width:' + position.width + 'px',
44627             'background-position-x:-' + position.x + 'px',
44628             'background-position-y:-' + position.y + 'px',
44629         ];
44630
44631         return '<div style="' + iconStyle.join(';') +'"></div>';
44632     },
44633
44634
44635     loadImages: function(projection$$1) {
44636         var url = apibase + 'images?';
44637         loadTiles('images', url, projection$$1);
44638     },
44639
44640
44641     loadSigns: function(context, projection$$1) {
44642         var url = apibase + 'objects?';
44643         loadTiles('objects', url, projection$$1);
44644
44645         // load traffic sign defs
44646         if (!mapillarySignDefs) {
44647             mapillarySignSprite = context.asset('img/traffic-signs/traffic-signs.png');
44648             mapillarySignDefs = {};
44649             json(context.asset('img/traffic-signs/traffic-signs.json'), function(err, data) {
44650                 if (err) return;
44651                 mapillarySignDefs = data;
44652             });
44653         }
44654     },
44655
44656
44657     loadViewer: function(context) {
44658         var that = this;
44659         var wrap = select('#content').selectAll('.mapillary-wrap')
44660             .data([0]);
44661
44662         var enter = wrap.enter()
44663             .append('div')
44664             .attr('class', 'mapillary-wrap')
44665             .classed('al', true)       // 'al'=left,  'ar'=right
44666             .classed('hidden', true);
44667
44668         enter
44669             .append('button')
44670             .attr('class', 'thumb-hide')
44671             .on('click', function () { that.hideViewer(); })
44672             .append('div')
44673             .call(svgIcon('#icon-close'));
44674
44675         enter
44676             .append('div')
44677             .attr('id', 'mly')
44678             .attr('class', 'mly-wrapper')
44679             .classed('active', false);
44680
44681         // load mapillary-viewercss
44682         select('head').selectAll('#mapillary-viewercss')
44683             .data([0])
44684             .enter()
44685             .append('link')
44686             .attr('id', 'mapillary-viewercss')
44687             .attr('rel', 'stylesheet')
44688             .attr('href', context.asset(viewercss));
44689
44690         // load mapillary-viewerjs
44691         select('head').selectAll('#mapillary-viewerjs')
44692             .data([0])
44693             .enter()
44694             .append('script')
44695             .attr('id', 'mapillary-viewerjs')
44696             .attr('src', context.asset(viewerjs));
44697     },
44698
44699
44700     showViewer: function() {
44701         select('#content')
44702             .selectAll('.mapillary-wrap')
44703             .classed('hidden', false)
44704             .selectAll('.mly-wrapper')
44705             .classed('active', true);
44706
44707         return this;
44708     },
44709
44710
44711     hideViewer: function() {
44712         select('#content')
44713             .selectAll('.mapillary-wrap')
44714             .classed('hidden', true)
44715             .selectAll('.mly-wrapper')
44716             .classed('active', false);
44717
44718         selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
44719             .classed('selected', false);
44720
44721         mapillaryImage = null;
44722         return this;
44723     },
44724
44725
44726     parsePagination: parsePagination,
44727
44728
44729     updateViewer: function(imageKey, context) {
44730         if (!imageKey) return;
44731
44732         if (!mapillaryViewer) {
44733             this.initViewer(imageKey, context);
44734         } else {
44735             mapillaryViewer.moveToKey(imageKey);
44736         }
44737
44738         return this;
44739     },
44740
44741
44742     initViewer: function(imageKey, context) {
44743         var that = this;
44744         if (Mapillary && imageKey) {
44745             var opts = {
44746                 baseImageSize: 320,
44747                 component: {
44748                     cover: false,
44749                     keyboard: false,
44750                     tag: true
44751                 }
44752             };
44753
44754             mapillaryViewer = new Mapillary.Viewer('mly', clientId, imageKey, opts);
44755             mapillaryViewer.on('nodechanged', nodeChanged);
44756         }
44757
44758         // nodeChanged: called after the viewer has changed images and is ready.
44759         //
44760         // There is some logic here to batch up clicks into a mapillaryClicks array
44761         // because the user might click on a lot of markers quickly and nodechanged
44762         // may be called out of order asychronously.
44763         //
44764         // Clicks are added to the array in `selectedImage` and removed here.
44765         //
44766         function nodeChanged(node) {
44767             mapillaryViewer.getComponent('tag').removeAll();  // remove previous detections
44768
44769             var clicks = mapillaryClicks;
44770             var index = clicks.indexOf(node.key);
44771             if (index > -1) {    // `nodechanged` initiated from clicking on a marker..
44772                 clicks.splice(index, 1);
44773                 // If `node.key` matches the current mapillaryImage, call `selectedImage()`
44774                 // one more time to update the detections and attribution..
44775                 if (node.key === mapillaryImage) {
44776                     that.selectedImage(node.key, false);
44777                 }
44778             } else {             // `nodechanged` initiated from the Mapillary viewer controls..
44779                 var loc = node.computedLatLon ? [node.computedLatLon.lon, node.computedLatLon.lat] : [node.latLon.lon, node.latLon.lat];
44780                 context.map().centerEase(loc);
44781                 that.selectedImage(node.key, false);
44782             }
44783         }
44784     },
44785
44786
44787     selectedImage: function(imageKey, fromClick) {
44788         if (!arguments.length) return mapillaryImage;
44789         mapillaryImage = imageKey;
44790
44791         if (fromClick) {
44792             mapillaryClicks.push(imageKey);
44793         }
44794
44795         selectAll('.layer-mapillary-images .viewfield-group')
44796             .classed('selected', function(d) {
44797                 return d.key === imageKey;
44798             });
44799
44800         selectAll('.layer-mapillary-signs .icon-sign')
44801             .classed('selected', function(d) {
44802                 return lodash.some(d.detections, function(detection) {
44803                     return detection.image_key === imageKey;
44804                 });
44805             });
44806
44807         if (!imageKey)  return this;
44808
44809
44810         function localeTimestamp(s) {
44811             if (!s) return null;
44812             var d = new Date(s);
44813             if (isNaN(d.getTime())) return null;
44814             return d.toLocaleString(undefined, { timeZone: 'UTC' });
44815         }
44816
44817         var selected = selectAll('.layer-mapillary-images .viewfield-group.selected');
44818         if (selected.empty()) return this;
44819
44820         var datum = selected.datum();
44821         var timestamp = localeTimestamp(datum.captured_at);
44822         var attribution = select('.mapillary-js-dom .Attribution');
44823         var capturedAt = attribution.selectAll('.captured-at');
44824         if (capturedAt.empty()) {
44825             attribution
44826                 .append('span')
44827                 .text('|');
44828             capturedAt = attribution
44829                 .append('span')
44830                 .attr('class', 'captured-at');
44831         }
44832         capturedAt
44833             .text(timestamp);
44834
44835         this.updateDetections();
44836
44837         return this;
44838     },
44839
44840
44841     updateDetections: function() {
44842         if (!mapillaryViewer) return;
44843
44844         var detections = mapillaryCache.detections[mapillaryImage];
44845         lodash.each(detections, function(data, k) {
44846             if (lodash.isEmpty(data)) {
44847                 loadDetection(k);
44848             } else {
44849                 var tag = makeTag(data);
44850                 if (tag) {
44851                     var tagComponent = mapillaryViewer.getComponent('tag');
44852                     tagComponent.add([tag]);
44853                 }
44854             }
44855         });
44856
44857
44858         function loadDetection(detectionKey) {
44859             var url = apibase + 'detections/'+
44860                 detectionKey + '?' + utilQsString({
44861                     client_id: clientId,
44862                 });
44863
44864             request(url)
44865                 .mimeType('application/json')
44866                 .response(function(xhr) {
44867                     return JSON.parse(xhr.responseText);
44868                 })
44869                 .get(function(err, data) {
44870                     if (!data || !data.properties) return;
44871
44872                     var ik = data.properties.image_key;
44873                     mapillaryCache.detections[ik][detectionKey] = data;
44874
44875                     if (mapillaryImage === ik) {
44876                         var tag = makeTag(data);
44877                         if (tag) {
44878                             var tagComponent = mapillaryViewer.getComponent('tag');
44879                             tagComponent.add([tag]);
44880                         }
44881                     }
44882                 });
44883         }
44884
44885
44886         function makeTag(data) {
44887             var valueParts = data.properties.value.split('--');
44888             if (valueParts.length !== 3) return;
44889
44890             var text$$1 = valueParts[1].replace(/-/g, ' ');
44891             var tag;
44892
44893             // Currently only two shapes <Polygon|Point>
44894             if (data.properties.shape.type === 'Polygon') {
44895                 var polygonGeometry = new Mapillary
44896                     .TagComponent
44897                     .PolygonGeometry(data.properties.shape.coordinates[0]);
44898
44899                 tag = new Mapillary.TagComponent.OutlineTag(
44900                     data.properties.key,
44901                     polygonGeometry,
44902                     {
44903                         text: text$$1,
44904                         textColor: 0xffff00,
44905                         lineColor: 0xffff00,
44906                         lineWidth: 2,
44907                         fillColor: 0xffff00,
44908                         fillOpacity: 0.3,
44909                     }
44910                 );
44911
44912             } else if (data.properties.shape.type === 'Point') {
44913                 var pointGeometry = new Mapillary
44914                     .TagComponent
44915                     .PointGeometry(data.properties.shape.coordinates[0]);
44916
44917                 tag = new Mapillary.TagComponent.SpotTag(
44918                     data.properties.key,
44919                     pointGeometry,
44920                     {
44921                         text: text$$1,
44922                         color: 0xffff00,
44923                         textColor: 0xffff00
44924                     }
44925                 );
44926             }
44927
44928             return tag;
44929         }
44930     },
44931
44932
44933     cache: function(_) {
44934         if (!arguments.length) return mapillaryCache;
44935         mapillaryCache = _;
44936         return this;
44937     },
44938
44939
44940     signDefs: function(_) {
44941         if (!arguments.length) return mapillarySignDefs;
44942         mapillarySignDefs = _;
44943         return this;
44944     }
44945
44946 };
44947
44948 var apibase$1 = 'https://nominatim.openstreetmap.org/';
44949 var inflight = {};
44950 var nominatimCache;
44951
44952
44953 var serviceNominatim = {
44954
44955     init: function() {
44956         inflight = {};
44957         nominatimCache = index$9();
44958     },
44959
44960     reset: function() {
44961         lodash.forEach(inflight, function(req) { req.abort(); });
44962         inflight = {};
44963         nominatimCache = index$9();
44964     },
44965
44966
44967     countryCode: function (location, callback) {
44968         this.reverse(location, function(err, result) {
44969             if (err) {
44970                 return callback(err);
44971             } else if (result.address) {
44972                 return callback(null, result.address.country_code);
44973             } else {
44974                 return callback('Unable to geocode', null);
44975             }
44976         });
44977     },
44978
44979
44980     reverse: function (location, callback) {
44981         var cached = nominatimCache.search(
44982             { minX: location[0], minY: location[1], maxX: location[0], maxY: location[1] }
44983         );
44984
44985         if (cached.length > 0) {
44986             return callback(null, cached[0].data);
44987         }
44988
44989         var params = { zoom: 13, format: 'json', addressdetails: 1, lat: location[1], lon: location[0] };
44990         var url = apibase$1 + 'reverse?' + utilQsString(params);
44991         if (inflight[url]) return;
44992
44993         inflight[url] = json(url, function(err, result) {
44994             delete inflight[url];
44995
44996             if (err) {
44997                 return callback(err);
44998             } else if (result && result.error) {
44999                 return callback(result.error);
45000             }
45001
45002             var extent$$1 = geoExtent$$1(location).padByMeters(200);
45003             nominatimCache.insert(lodash.assign(extent$$1.bbox(), {data: result}));
45004
45005             callback(null, result);
45006         });
45007     },
45008
45009
45010     search: function (val, callback) {
45011         var searchVal = encodeURIComponent(val);
45012         var url = apibase$1 + 'search/' + searchVal + '?limit=10&format=json';
45013         if (inflight[url]) return;
45014
45015         inflight[url] = json(url, function(err, result) {
45016             delete inflight[url];
45017             callback(err, result);
45018         });
45019     }
45020
45021 };
45022
45023 var hashes = createCommonjsModule(function (module, exports) {
45024 /**
45025  * jshashes - https://github.com/h2non/jshashes
45026  * Released under the "New BSD" license
45027  *
45028  * Algorithms specification:
45029  *
45030  * MD5 - http://www.ietf.org/rfc/rfc1321.txt
45031  * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
45032  * SHA1   - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
45033  * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
45034  * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
45035  * HMAC - http://www.ietf.org/rfc/rfc2104.txt
45036  */
45037 (function() {
45038   var Hashes;
45039
45040   function utf8Encode(str) {
45041     var x, y, output = '',
45042       i = -1,
45043       l;
45044
45045     if (str && str.length) {
45046       l = str.length;
45047       while ((i += 1) < l) {
45048         /* Decode utf-16 surrogate pairs */
45049         x = str.charCodeAt(i);
45050         y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
45051         if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
45052           x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
45053           i += 1;
45054         }
45055         /* Encode output as utf-8 */
45056         if (x <= 0x7F) {
45057           output += String.fromCharCode(x);
45058         } else if (x <= 0x7FF) {
45059           output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F),
45060             0x80 | (x & 0x3F));
45061         } else if (x <= 0xFFFF) {
45062           output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
45063             0x80 | ((x >>> 6) & 0x3F),
45064             0x80 | (x & 0x3F));
45065         } else if (x <= 0x1FFFFF) {
45066           output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
45067             0x80 | ((x >>> 12) & 0x3F),
45068             0x80 | ((x >>> 6) & 0x3F),
45069             0x80 | (x & 0x3F));
45070         }
45071       }
45072     }
45073     return output;
45074   }
45075
45076   function utf8Decode(str) {
45077     var i, ac, c1, c2, c3, arr = [],
45078       l;
45079     i = ac = c1 = c2 = c3 = 0;
45080
45081     if (str && str.length) {
45082       l = str.length;
45083       str += '';
45084
45085       while (i < l) {
45086         c1 = str.charCodeAt(i);
45087         ac += 1;
45088         if (c1 < 128) {
45089           arr[ac] = String.fromCharCode(c1);
45090           i += 1;
45091         } else if (c1 > 191 && c1 < 224) {
45092           c2 = str.charCodeAt(i + 1);
45093           arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
45094           i += 2;
45095         } else {
45096           c2 = str.charCodeAt(i + 1);
45097           c3 = str.charCodeAt(i + 2);
45098           arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
45099           i += 3;
45100         }
45101       }
45102     }
45103     return arr.join('');
45104   }
45105
45106   /**
45107    * Add integers, wrapping at 2^32. This uses 16-bit operations internally
45108    * to work around bugs in some JS interpreters.
45109    */
45110
45111   function safe_add(x, y) {
45112     var lsw = (x & 0xFFFF) + (y & 0xFFFF),
45113       msw = (x >> 16) + (y >> 16) + (lsw >> 16);
45114     return (msw << 16) | (lsw & 0xFFFF);
45115   }
45116
45117   /**
45118    * Bitwise rotate a 32-bit number to the left.
45119    */
45120
45121   function bit_rol(num, cnt) {
45122     return (num << cnt) | (num >>> (32 - cnt));
45123   }
45124
45125   /**
45126    * Convert a raw string to a hex string
45127    */
45128
45129   function rstr2hex(input, hexcase) {
45130     var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
45131       output = '',
45132       x, i = 0,
45133       l = input.length;
45134     for (; i < l; i += 1) {
45135       x = input.charCodeAt(i);
45136       output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
45137     }
45138     return output;
45139   }
45140
45141   /**
45142    * Encode a string as utf-16
45143    */
45144
45145   function binb2rstr(input) {
45146     var i, l = input.length * 32,
45147       output = '';
45148     for (i = 0; i < l; i += 8) {
45149       output += String.fromCharCode((input[i >> 5] >>> (24 - i % 32)) & 0xFF);
45150     }
45151     return output;
45152   }
45153
45154   /**
45155    * Convert an array of little-endian words to a string
45156    */
45157
45158   function binl2rstr(input) {
45159     var i, l = input.length * 32,
45160       output = '';
45161     for (i = 0; i < l; i += 8) {
45162       output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
45163     }
45164     return output;
45165   }
45166
45167   /**
45168    * Convert a raw string to an array of little-endian words
45169    * Characters >255 have their high-byte silently ignored.
45170    */
45171
45172   function rstr2binl(input) {
45173     var i, l = input.length * 8,
45174       output = Array(input.length >> 2),
45175       lo = output.length;
45176     for (i = 0; i < lo; i += 1) {
45177       output[i] = 0;
45178     }
45179     for (i = 0; i < l; i += 8) {
45180       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
45181     }
45182     return output;
45183   }
45184
45185   /**
45186    * Convert a raw string to an array of big-endian words
45187    * Characters >255 have their high-byte silently ignored.
45188    */
45189
45190   function rstr2binb(input) {
45191     var i, l = input.length * 8,
45192       output = Array(input.length >> 2),
45193       lo = output.length;
45194     for (i = 0; i < lo; i += 1) {
45195       output[i] = 0;
45196     }
45197     for (i = 0; i < l; i += 8) {
45198       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
45199     }
45200     return output;
45201   }
45202
45203   /**
45204    * Convert a raw string to an arbitrary string encoding
45205    */
45206
45207   function rstr2any(input, encoding) {
45208     var divisor = encoding.length,
45209       remainders = Array(),
45210       i, q, x, ld, quotient, dividend, output, full_length;
45211
45212     /* Convert to an array of 16-bit big-endian values, forming the dividend */
45213     dividend = Array(Math.ceil(input.length / 2));
45214     ld = dividend.length;
45215     for (i = 0; i < ld; i += 1) {
45216       dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
45217     }
45218
45219     /**
45220      * Repeatedly perform a long division. The binary array forms the dividend,
45221      * the length of the encoding is the divisor. Once computed, the quotient
45222      * forms the dividend for the next step. We stop when the dividend is zerHashes.
45223      * All remainders are stored for later use.
45224      */
45225     while (dividend.length > 0) {
45226       quotient = Array();
45227       x = 0;
45228       for (i = 0; i < dividend.length; i += 1) {
45229         x = (x << 16) + dividend[i];
45230         q = Math.floor(x / divisor);
45231         x -= q * divisor;
45232         if (quotient.length > 0 || q > 0) {
45233           quotient[quotient.length] = q;
45234         }
45235       }
45236       remainders[remainders.length] = x;
45237       dividend = quotient;
45238     }
45239
45240     /* Convert the remainders to the output string */
45241     output = '';
45242     for (i = remainders.length - 1; i >= 0; i--) {
45243       output += encoding.charAt(remainders[i]);
45244     }
45245
45246     /* Append leading zero equivalents */
45247     full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
45248     for (i = output.length; i < full_length; i += 1) {
45249       output = encoding[0] + output;
45250     }
45251     return output;
45252   }
45253
45254   /**
45255    * Convert a raw string to a base-64 string
45256    */
45257
45258   function rstr2b64(input, b64pad) {
45259     var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
45260       output = '',
45261       len = input.length,
45262       i, j, triplet;
45263     b64pad = b64pad || '=';
45264     for (i = 0; i < len; i += 3) {
45265       triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
45266       for (j = 0; j < 4; j += 1) {
45267         if (i * 8 + j * 6 > input.length * 8) {
45268           output += b64pad;
45269         } else {
45270           output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
45271         }
45272       }
45273     }
45274     return output;
45275   }
45276
45277   Hashes = {
45278     /**
45279      * @property {String} version
45280      * @readonly
45281      */
45282     VERSION: '1.0.6',
45283     /**
45284      * @member Hashes
45285      * @class Base64
45286      * @constructor
45287      */
45288     Base64: function() {
45289       // private properties
45290       var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
45291         pad = '=', // default pad according with the RFC standard
45292         url = false, // URL encoding support @todo
45293         utf8 = true; // by default enable UTF-8 support encoding
45294
45295       // public method for encoding
45296       this.encode = function(input) {
45297         var i, j, triplet,
45298           output = '',
45299           len = input.length;
45300
45301         pad = pad || '=';
45302         input = (utf8) ? utf8Encode(input) : input;
45303
45304         for (i = 0; i < len; i += 3) {
45305           triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
45306           for (j = 0; j < 4; j += 1) {
45307             if (i * 8 + j * 6 > len * 8) {
45308               output += pad;
45309             } else {
45310               output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
45311             }
45312           }
45313         }
45314         return output;
45315       };
45316
45317       // public method for decoding
45318       this.decode = function(input) {
45319         // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
45320         var i, o1, o2, o3, h1, h2, h3, h4, bits, ac,
45321           dec = '',
45322           arr = [];
45323         if (!input) {
45324           return input;
45325         }
45326
45327         i = ac = 0;
45328         input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
45329         //input += '';
45330
45331         do { // unpack four hexets into three octets using index points in b64
45332           h1 = tab.indexOf(input.charAt(i += 1));
45333           h2 = tab.indexOf(input.charAt(i += 1));
45334           h3 = tab.indexOf(input.charAt(i += 1));
45335           h4 = tab.indexOf(input.charAt(i += 1));
45336
45337           bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
45338
45339           o1 = bits >> 16 & 0xff;
45340           o2 = bits >> 8 & 0xff;
45341           o3 = bits & 0xff;
45342           ac += 1;
45343
45344           if (h3 === 64) {
45345             arr[ac] = String.fromCharCode(o1);
45346           } else if (h4 === 64) {
45347             arr[ac] = String.fromCharCode(o1, o2);
45348           } else {
45349             arr[ac] = String.fromCharCode(o1, o2, o3);
45350           }
45351         } while (i < input.length);
45352
45353         dec = arr.join('');
45354         dec = (utf8) ? utf8Decode(dec) : dec;
45355
45356         return dec;
45357       };
45358
45359       // set custom pad string
45360       this.setPad = function(str) {
45361         pad = str || pad;
45362         return this;
45363       };
45364       // set custom tab string characters
45365       this.setTab = function(str) {
45366         tab = str || tab;
45367         return this;
45368       };
45369       this.setUTF8 = function(bool) {
45370         if (typeof bool === 'boolean') {
45371           utf8 = bool;
45372         }
45373         return this;
45374       };
45375     },
45376
45377     /**
45378      * CRC-32 calculation
45379      * @member Hashes
45380      * @method CRC32
45381      * @static
45382      * @param {String} str Input String
45383      * @return {String}
45384      */
45385     CRC32: function(str) {
45386       var crc = 0,
45387         x = 0,
45388         y = 0,
45389         table, i, iTop;
45390       str = utf8Encode(str);
45391
45392       table = [
45393         '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ',
45394         '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ',
45395         '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ',
45396         '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ',
45397         'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ',
45398         '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ',
45399         'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ',
45400         '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ',
45401         'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ',
45402         '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ',
45403         'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ',
45404         '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ',
45405         'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ',
45406         '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ',
45407         '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ',
45408         '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ',
45409         '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ',
45410         'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ',
45411         '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ',
45412         'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ',
45413         '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ',
45414         'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ',
45415         '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ',
45416         'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ',
45417         '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ',
45418         'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'
45419       ].join('');
45420
45421       crc = crc ^ (-1);
45422       for (i = 0, iTop = str.length; i < iTop; i += 1) {
45423         y = (crc ^ str.charCodeAt(i)) & 0xFF;
45424         x = '0x' + table.substr(y * 9, 8);
45425         crc = (crc >>> 8) ^ x;
45426       }
45427       // always return a positive number (that's what >>> 0 does)
45428       return (crc ^ (-1)) >>> 0;
45429     },
45430     /**
45431      * @member Hashes
45432      * @class MD5
45433      * @constructor
45434      * @param {Object} [config]
45435      *
45436      * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
45437      * Digest Algorithm, as defined in RFC 1321.
45438      * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
45439      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45440      * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
45441      */
45442     MD5: function(options) {
45443       /**
45444        * Private config properties. You may need to tweak these to be compatible with
45445        * the server-side, but the defaults work in most cases.
45446        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
45447        */
45448       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
45449         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
45450         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
45451
45452       // privileged (public) methods
45453       this.hex = function(s) {
45454         return rstr2hex(rstr(s, utf8), hexcase);
45455       };
45456       this.b64 = function(s) {
45457         return rstr2b64(rstr(s), b64pad);
45458       };
45459       this.any = function(s, e) {
45460         return rstr2any(rstr(s, utf8), e);
45461       };
45462       this.raw = function(s) {
45463         return rstr(s, utf8);
45464       };
45465       this.hex_hmac = function(k, d) {
45466         return rstr2hex(rstr_hmac(k, d), hexcase);
45467       };
45468       this.b64_hmac = function(k, d) {
45469         return rstr2b64(rstr_hmac(k, d), b64pad);
45470       };
45471       this.any_hmac = function(k, d, e) {
45472         return rstr2any(rstr_hmac(k, d), e);
45473       };
45474       /**
45475        * Perform a simple self-test to see if the VM is working
45476        * @return {String} Hexadecimal hash sample
45477        */
45478       this.vm_test = function() {
45479         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45480       };
45481       /**
45482        * Enable/disable uppercase hexadecimal returned string
45483        * @param {Boolean}
45484        * @return {Object} this
45485        */
45486       this.setUpperCase = function(a) {
45487         if (typeof a === 'boolean') {
45488           hexcase = a;
45489         }
45490         return this;
45491       };
45492       /**
45493        * Defines a base64 pad string
45494        * @param {String} Pad
45495        * @return {Object} this
45496        */
45497       this.setPad = function(a) {
45498         b64pad = a || b64pad;
45499         return this;
45500       };
45501       /**
45502        * Defines a base64 pad string
45503        * @param {Boolean}
45504        * @return {Object} [this]
45505        */
45506       this.setUTF8 = function(a) {
45507         if (typeof a === 'boolean') {
45508           utf8 = a;
45509         }
45510         return this;
45511       };
45512
45513       // private methods
45514
45515       /**
45516        * Calculate the MD5 of a raw string
45517        */
45518
45519       function rstr(s) {
45520         s = (utf8) ? utf8Encode(s) : s;
45521         return binl2rstr(binl(rstr2binl(s), s.length * 8));
45522       }
45523
45524       /**
45525        * Calculate the HMAC-MD5, of a key and some data (raw strings)
45526        */
45527
45528       function rstr_hmac(key, data) {
45529         var bkey, ipad, opad, hash, i;
45530
45531         key = (utf8) ? utf8Encode(key) : key;
45532         data = (utf8) ? utf8Encode(data) : data;
45533         bkey = rstr2binl(key);
45534         if (bkey.length > 16) {
45535           bkey = binl(bkey, key.length * 8);
45536         }
45537
45538         ipad = Array(16), opad = Array(16);
45539         for (i = 0; i < 16; i += 1) {
45540           ipad[i] = bkey[i] ^ 0x36363636;
45541           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45542         }
45543         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
45544         return binl2rstr(binl(opad.concat(hash), 512 + 128));
45545       }
45546
45547       /**
45548        * Calculate the MD5 of an array of little-endian words, and a bit length.
45549        */
45550
45551       function binl(x, len) {
45552         var i, olda, oldb, oldc, oldd,
45553           a = 1732584193,
45554           b = -271733879,
45555           c = -1732584194,
45556           d = 271733878;
45557
45558         /* append padding */
45559         x[len >> 5] |= 0x80 << ((len) % 32);
45560         x[(((len + 64) >>> 9) << 4) + 14] = len;
45561
45562         for (i = 0; i < x.length; i += 16) {
45563           olda = a;
45564           oldb = b;
45565           oldc = c;
45566           oldd = d;
45567
45568           a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
45569           d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
45570           c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
45571           b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
45572           a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
45573           d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
45574           c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
45575           b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
45576           a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
45577           d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
45578           c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
45579           b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
45580           a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
45581           d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
45582           c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
45583           b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
45584
45585           a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
45586           d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
45587           c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
45588           b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
45589           a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
45590           d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
45591           c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
45592           b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
45593           a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
45594           d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
45595           c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
45596           b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
45597           a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
45598           d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
45599           c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
45600           b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
45601
45602           a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
45603           d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
45604           c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
45605           b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
45606           a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
45607           d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
45608           c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
45609           b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
45610           a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
45611           d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
45612           c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
45613           b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
45614           a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
45615           d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
45616           c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
45617           b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
45618
45619           a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
45620           d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
45621           c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
45622           b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
45623           a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
45624           d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
45625           c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
45626           b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
45627           a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
45628           d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
45629           c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
45630           b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
45631           a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
45632           d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
45633           c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
45634           b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
45635
45636           a = safe_add(a, olda);
45637           b = safe_add(b, oldb);
45638           c = safe_add(c, oldc);
45639           d = safe_add(d, oldd);
45640         }
45641         return Array(a, b, c, d);
45642       }
45643
45644       /**
45645        * These functions implement the four basic operations the algorithm uses.
45646        */
45647
45648       function md5_cmn(q, a, b, x, s, t) {
45649         return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
45650       }
45651
45652       function md5_ff(a, b, c, d, x, s, t) {
45653         return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
45654       }
45655
45656       function md5_gg(a, b, c, d, x, s, t) {
45657         return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
45658       }
45659
45660       function md5_hh(a, b, c, d, x, s, t) {
45661         return md5_cmn(b ^ c ^ d, a, b, x, s, t);
45662       }
45663
45664       function md5_ii(a, b, c, d, x, s, t) {
45665         return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
45666       }
45667     },
45668     /**
45669      * @member Hashes
45670      * @class Hashes.SHA1
45671      * @param {Object} [config]
45672      * @constructor
45673      *
45674      * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
45675      * Version 2.2 Copyright Paul Johnston 2000 - 2009.
45676      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45677      * See http://pajhome.org.uk/crypt/md5 for details.
45678      */
45679     SHA1: function(options) {
45680       /**
45681        * Private config properties. You may need to tweak these to be compatible with
45682        * the server-side, but the defaults work in most cases.
45683        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
45684        */
45685       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
45686         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
45687         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
45688
45689       // public methods
45690       this.hex = function(s) {
45691         return rstr2hex(rstr(s, utf8), hexcase);
45692       };
45693       this.b64 = function(s) {
45694         return rstr2b64(rstr(s, utf8), b64pad);
45695       };
45696       this.any = function(s, e) {
45697         return rstr2any(rstr(s, utf8), e);
45698       };
45699       this.raw = function(s) {
45700         return rstr(s, utf8);
45701       };
45702       this.hex_hmac = function(k, d) {
45703         return rstr2hex(rstr_hmac(k, d));
45704       };
45705       this.b64_hmac = function(k, d) {
45706         return rstr2b64(rstr_hmac(k, d), b64pad);
45707       };
45708       this.any_hmac = function(k, d, e) {
45709         return rstr2any(rstr_hmac(k, d), e);
45710       };
45711       /**
45712        * Perform a simple self-test to see if the VM is working
45713        * @return {String} Hexadecimal hash sample
45714        * @public
45715        */
45716       this.vm_test = function() {
45717         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45718       };
45719       /**
45720        * @description Enable/disable uppercase hexadecimal returned string
45721        * @param {boolean}
45722        * @return {Object} this
45723        * @public
45724        */
45725       this.setUpperCase = function(a) {
45726         if (typeof a === 'boolean') {
45727           hexcase = a;
45728         }
45729         return this;
45730       };
45731       /**
45732        * @description Defines a base64 pad string
45733        * @param {string} Pad
45734        * @return {Object} this
45735        * @public
45736        */
45737       this.setPad = function(a) {
45738         b64pad = a || b64pad;
45739         return this;
45740       };
45741       /**
45742        * @description Defines a base64 pad string
45743        * @param {boolean}
45744        * @return {Object} this
45745        * @public
45746        */
45747       this.setUTF8 = function(a) {
45748         if (typeof a === 'boolean') {
45749           utf8 = a;
45750         }
45751         return this;
45752       };
45753
45754       // private methods
45755
45756       /**
45757        * Calculate the SHA-512 of a raw string
45758        */
45759
45760       function rstr(s) {
45761         s = (utf8) ? utf8Encode(s) : s;
45762         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45763       }
45764
45765       /**
45766        * Calculate the HMAC-SHA1 of a key and some data (raw strings)
45767        */
45768
45769       function rstr_hmac(key, data) {
45770         var bkey, ipad, opad, i, hash;
45771         key = (utf8) ? utf8Encode(key) : key;
45772         data = (utf8) ? utf8Encode(data) : data;
45773         bkey = rstr2binb(key);
45774
45775         if (bkey.length > 16) {
45776           bkey = binb(bkey, key.length * 8);
45777         }
45778         ipad = Array(16), opad = Array(16);
45779         for (i = 0; i < 16; i += 1) {
45780           ipad[i] = bkey[i] ^ 0x36363636;
45781           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45782         }
45783         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45784         return binb2rstr(binb(opad.concat(hash), 512 + 160));
45785       }
45786
45787       /**
45788        * Calculate the SHA-1 of an array of big-endian words, and a bit length
45789        */
45790
45791       function binb(x, len) {
45792         var i, j, t, olda, oldb, oldc, oldd, olde,
45793           w = Array(80),
45794           a = 1732584193,
45795           b = -271733879,
45796           c = -1732584194,
45797           d = 271733878,
45798           e = -1009589776;
45799
45800         /* append padding */
45801         x[len >> 5] |= 0x80 << (24 - len % 32);
45802         x[((len + 64 >> 9) << 4) + 15] = len;
45803
45804         for (i = 0; i < x.length; i += 16) {
45805           olda = a,
45806           oldb = b;
45807           oldc = c;
45808           oldd = d;
45809           olde = e;
45810
45811           for (j = 0; j < 80; j += 1) {
45812             if (j < 16) {
45813               w[j] = x[i + j];
45814             } else {
45815               w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
45816             }
45817             t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
45818               safe_add(safe_add(e, w[j]), sha1_kt(j)));
45819             e = d;
45820             d = c;
45821             c = bit_rol(b, 30);
45822             b = a;
45823             a = t;
45824           }
45825
45826           a = safe_add(a, olda);
45827           b = safe_add(b, oldb);
45828           c = safe_add(c, oldc);
45829           d = safe_add(d, oldd);
45830           e = safe_add(e, olde);
45831         }
45832         return Array(a, b, c, d, e);
45833       }
45834
45835       /**
45836        * Perform the appropriate triplet combination function for the current
45837        * iteration
45838        */
45839
45840       function sha1_ft(t, b, c, d) {
45841         if (t < 20) {
45842           return (b & c) | ((~b) & d);
45843         }
45844         if (t < 40) {
45845           return b ^ c ^ d;
45846         }
45847         if (t < 60) {
45848           return (b & c) | (b & d) | (c & d);
45849         }
45850         return b ^ c ^ d;
45851       }
45852
45853       /**
45854        * Determine the appropriate additive constant for the current iteration
45855        */
45856
45857       function sha1_kt(t) {
45858         return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
45859           (t < 60) ? -1894007588 : -899497514;
45860       }
45861     },
45862     /**
45863      * @class Hashes.SHA256
45864      * @param {config}
45865      *
45866      * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
45867      * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
45868      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45869      * See http://pajhome.org.uk/crypt/md5 for details.
45870      * Also http://anmar.eu.org/projects/jssha2/
45871      */
45872     SHA256: function(options) {
45873       /**
45874        * Private properties configuration variables. You may need to tweak these to be compatible with
45875        * the server-side, but the defaults work in most cases.
45876        * @see this.setUpperCase() method
45877        * @see this.setPad() method
45878        */
45879       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase  */
45880         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=',
45881         /* base-64 pad character. Default '=' for strict RFC compliance   */
45882         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45883         /* enable/disable utf8 encoding */
45884         sha256_K;
45885
45886       /* privileged (public) methods */
45887       this.hex = function(s) {
45888         return rstr2hex(rstr(s, utf8));
45889       };
45890       this.b64 = function(s) {
45891         return rstr2b64(rstr(s, utf8), b64pad);
45892       };
45893       this.any = function(s, e) {
45894         return rstr2any(rstr(s, utf8), e);
45895       };
45896       this.raw = function(s) {
45897         return rstr(s, utf8);
45898       };
45899       this.hex_hmac = function(k, d) {
45900         return rstr2hex(rstr_hmac(k, d));
45901       };
45902       this.b64_hmac = function(k, d) {
45903         return rstr2b64(rstr_hmac(k, d), b64pad);
45904       };
45905       this.any_hmac = function(k, d, e) {
45906         return rstr2any(rstr_hmac(k, d), e);
45907       };
45908       /**
45909        * Perform a simple self-test to see if the VM is working
45910        * @return {String} Hexadecimal hash sample
45911        * @public
45912        */
45913       this.vm_test = function() {
45914         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45915       };
45916       /**
45917        * Enable/disable uppercase hexadecimal returned string
45918        * @param {boolean}
45919        * @return {Object} this
45920        * @public
45921        */
45922       this.setUpperCase = function(a) {
45923         if (typeof a === 'boolean') {
45924           hexcase = a;
45925         }
45926         return this;
45927       };
45928       /**
45929        * @description Defines a base64 pad string
45930        * @param {string} Pad
45931        * @return {Object} this
45932        * @public
45933        */
45934       this.setPad = function(a) {
45935         b64pad = a || b64pad;
45936         return this;
45937       };
45938       /**
45939        * Defines a base64 pad string
45940        * @param {boolean}
45941        * @return {Object} this
45942        * @public
45943        */
45944       this.setUTF8 = function(a) {
45945         if (typeof a === 'boolean') {
45946           utf8 = a;
45947         }
45948         return this;
45949       };
45950
45951       // private methods
45952
45953       /**
45954        * Calculate the SHA-512 of a raw string
45955        */
45956
45957       function rstr(s, utf8) {
45958         s = (utf8) ? utf8Encode(s) : s;
45959         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45960       }
45961
45962       /**
45963        * Calculate the HMAC-sha256 of a key and some data (raw strings)
45964        */
45965
45966       function rstr_hmac(key, data) {
45967         key = (utf8) ? utf8Encode(key) : key;
45968         data = (utf8) ? utf8Encode(data) : data;
45969         var hash, i = 0,
45970           bkey = rstr2binb(key),
45971           ipad = Array(16),
45972           opad = Array(16);
45973
45974         if (bkey.length > 16) {
45975           bkey = binb(bkey, key.length * 8);
45976         }
45977
45978         for (; i < 16; i += 1) {
45979           ipad[i] = bkey[i] ^ 0x36363636;
45980           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45981         }
45982
45983         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45984         return binb2rstr(binb(opad.concat(hash), 512 + 256));
45985       }
45986
45987       /*
45988        * Main sha256 function, with its support functions
45989        */
45990
45991       function sha256_S(X, n) {
45992         return (X >>> n) | (X << (32 - n));
45993       }
45994
45995       function sha256_R(X, n) {
45996         return (X >>> n);
45997       }
45998
45999       function sha256_Ch(x, y, z) {
46000         return ((x & y) ^ ((~x) & z));
46001       }
46002
46003       function sha256_Maj(x, y, z) {
46004         return ((x & y) ^ (x & z) ^ (y & z));
46005       }
46006
46007       function sha256_Sigma0256(x) {
46008         return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));
46009       }
46010
46011       function sha256_Sigma1256(x) {
46012         return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));
46013       }
46014
46015       function sha256_Gamma0256(x) {
46016         return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));
46017       }
46018
46019       function sha256_Gamma1256(x) {
46020         return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));
46021       }
46022
46023       sha256_K = [
46024         1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
46025         1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
46026         264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
46027         113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
46028         1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
46029         430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
46030         1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998
46031       ];
46032
46033       function binb(m, l) {
46034         var HASH = [1779033703, -1150833019, 1013904242, -1521486534,
46035           1359893119, -1694144372, 528734635, 1541459225
46036         ];
46037         var W = new Array(64);
46038         var a, b, c, d, e, f, g, h;
46039         var i, j, T1, T2;
46040
46041         /* append padding */
46042         m[l >> 5] |= 0x80 << (24 - l % 32);
46043         m[((l + 64 >> 9) << 4) + 15] = l;
46044
46045         for (i = 0; i < m.length; i += 16) {
46046           a = HASH[0];
46047           b = HASH[1];
46048           c = HASH[2];
46049           d = HASH[3];
46050           e = HASH[4];
46051           f = HASH[5];
46052           g = HASH[6];
46053           h = HASH[7];
46054
46055           for (j = 0; j < 64; j += 1) {
46056             if (j < 16) {
46057               W[j] = m[j + i];
46058             } else {
46059               W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
46060                 sha256_Gamma0256(W[j - 15])), W[j - 16]);
46061             }
46062
46063             T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
46064               sha256_K[j]), W[j]);
46065             T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
46066             h = g;
46067             g = f;
46068             f = e;
46069             e = safe_add(d, T1);
46070             d = c;
46071             c = b;
46072             b = a;
46073             a = safe_add(T1, T2);
46074           }
46075
46076           HASH[0] = safe_add(a, HASH[0]);
46077           HASH[1] = safe_add(b, HASH[1]);
46078           HASH[2] = safe_add(c, HASH[2]);
46079           HASH[3] = safe_add(d, HASH[3]);
46080           HASH[4] = safe_add(e, HASH[4]);
46081           HASH[5] = safe_add(f, HASH[5]);
46082           HASH[6] = safe_add(g, HASH[6]);
46083           HASH[7] = safe_add(h, HASH[7]);
46084         }
46085         return HASH;
46086       }
46087
46088     },
46089
46090     /**
46091      * @class Hashes.SHA512
46092      * @param {config}
46093      *
46094      * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
46095      * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
46096      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
46097      * See http://pajhome.org.uk/crypt/md5 for details.
46098      */
46099     SHA512: function(options) {
46100       /**
46101        * Private properties configuration variables. You may need to tweak these to be compatible with
46102        * the server-side, but the defaults work in most cases.
46103        * @see this.setUpperCase() method
46104        * @see this.setPad() method
46105        */
46106       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
46107         /* hexadecimal output case format. false - lowercase; true - uppercase  */
46108         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=',
46109         /* base-64 pad character. Default '=' for strict RFC compliance   */
46110         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
46111         /* enable/disable utf8 encoding */
46112         sha512_k;
46113
46114       /* privileged (public) methods */
46115       this.hex = function(s) {
46116         return rstr2hex(rstr(s));
46117       };
46118       this.b64 = function(s) {
46119         return rstr2b64(rstr(s), b64pad);
46120       };
46121       this.any = function(s, e) {
46122         return rstr2any(rstr(s), e);
46123       };
46124       this.raw = function(s) {
46125         return rstr(s, utf8);
46126       };
46127       this.hex_hmac = function(k, d) {
46128         return rstr2hex(rstr_hmac(k, d));
46129       };
46130       this.b64_hmac = function(k, d) {
46131         return rstr2b64(rstr_hmac(k, d), b64pad);
46132       };
46133       this.any_hmac = function(k, d, e) {
46134         return rstr2any(rstr_hmac(k, d), e);
46135       };
46136       /**
46137        * Perform a simple self-test to see if the VM is working
46138        * @return {String} Hexadecimal hash sample
46139        * @public
46140        */
46141       this.vm_test = function() {
46142         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
46143       };
46144       /**
46145        * @description Enable/disable uppercase hexadecimal returned string
46146        * @param {boolean}
46147        * @return {Object} this
46148        * @public
46149        */
46150       this.setUpperCase = function(a) {
46151         if (typeof a === 'boolean') {
46152           hexcase = a;
46153         }
46154         return this;
46155       };
46156       /**
46157        * @description Defines a base64 pad string
46158        * @param {string} Pad
46159        * @return {Object} this
46160        * @public
46161        */
46162       this.setPad = function(a) {
46163         b64pad = a || b64pad;
46164         return this;
46165       };
46166       /**
46167        * @description Defines a base64 pad string
46168        * @param {boolean}
46169        * @return {Object} this
46170        * @public
46171        */
46172       this.setUTF8 = function(a) {
46173         if (typeof a === 'boolean') {
46174           utf8 = a;
46175         }
46176         return this;
46177       };
46178
46179       /* private methods */
46180
46181       /**
46182        * Calculate the SHA-512 of a raw string
46183        */
46184
46185       function rstr(s) {
46186         s = (utf8) ? utf8Encode(s) : s;
46187         return binb2rstr(binb(rstr2binb(s), s.length * 8));
46188       }
46189       /*
46190        * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
46191        */
46192
46193       function rstr_hmac(key, data) {
46194         key = (utf8) ? utf8Encode(key) : key;
46195         data = (utf8) ? utf8Encode(data) : data;
46196
46197         var hash, i = 0,
46198           bkey = rstr2binb(key),
46199           ipad = Array(32),
46200           opad = Array(32);
46201
46202         if (bkey.length > 32) {
46203           bkey = binb(bkey, key.length * 8);
46204         }
46205
46206         for (; i < 32; i += 1) {
46207           ipad[i] = bkey[i] ^ 0x36363636;
46208           opad[i] = bkey[i] ^ 0x5C5C5C5C;
46209         }
46210
46211         hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
46212         return binb2rstr(binb(opad.concat(hash), 1024 + 512));
46213       }
46214
46215       /**
46216        * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
46217        */
46218
46219       function binb(x, len) {
46220         var j, i, l,
46221           W = new Array(80),
46222           hash = new Array(16),
46223           //Initial hash values
46224           H = [
46225             new int64(0x6a09e667, -205731576),
46226             new int64(-1150833019, -2067093701),
46227             new int64(0x3c6ef372, -23791573),
46228             new int64(-1521486534, 0x5f1d36f1),
46229             new int64(0x510e527f, -1377402159),
46230             new int64(-1694144372, 0x2b3e6c1f),
46231             new int64(0x1f83d9ab, -79577749),
46232             new int64(0x5be0cd19, 0x137e2179)
46233           ],
46234           T1 = new int64(0, 0),
46235           T2 = new int64(0, 0),
46236           a = new int64(0, 0),
46237           b = new int64(0, 0),
46238           c = new int64(0, 0),
46239           d = new int64(0, 0),
46240           e = new int64(0, 0),
46241           f = new int64(0, 0),
46242           g = new int64(0, 0),
46243           h = new int64(0, 0),
46244           //Temporary variables not specified by the document
46245           s0 = new int64(0, 0),
46246           s1 = new int64(0, 0),
46247           Ch = new int64(0, 0),
46248           Maj = new int64(0, 0),
46249           r1 = new int64(0, 0),
46250           r2 = new int64(0, 0),
46251           r3 = new int64(0, 0);
46252
46253         if (sha512_k === undefined) {
46254           //SHA512 constants
46255           sha512_k = [
46256             new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
46257             new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
46258             new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
46259             new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
46260             new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
46261             new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
46262             new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
46263             new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
46264             new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
46265             new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
46266             new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
46267             new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
46268             new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
46269             new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
46270             new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
46271             new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
46272             new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
46273             new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
46274             new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
46275             new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
46276             new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
46277             new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
46278             new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
46279             new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
46280             new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
46281             new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
46282             new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
46283             new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
46284             new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
46285             new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
46286             new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
46287             new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
46288             new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
46289             new int64(-354779690, -840897762), new int64(-176337025, -294727304),
46290             new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
46291             new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
46292             new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
46293             new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
46294             new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
46295             new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)
46296           ];
46297         }
46298
46299         for (i = 0; i < 80; i += 1) {
46300           W[i] = new int64(0, 0);
46301         }
46302
46303         // append padding to the source string. The format is described in the FIPS.
46304         x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
46305         x[((len + 128 >> 10) << 5) + 31] = len;
46306         l = x.length;
46307         for (i = 0; i < l; i += 32) { //32 dwords is the block size
46308           int64copy(a, H[0]);
46309           int64copy(b, H[1]);
46310           int64copy(c, H[2]);
46311           int64copy(d, H[3]);
46312           int64copy(e, H[4]);
46313           int64copy(f, H[5]);
46314           int64copy(g, H[6]);
46315           int64copy(h, H[7]);
46316
46317           for (j = 0; j < 16; j += 1) {
46318             W[j].h = x[i + 2 * j];
46319             W[j].l = x[i + 2 * j + 1];
46320           }
46321
46322           for (j = 16; j < 80; j += 1) {
46323             //sigma1
46324             int64rrot(r1, W[j - 2], 19);
46325             int64revrrot(r2, W[j - 2], 29);
46326             int64shr(r3, W[j - 2], 6);
46327             s1.l = r1.l ^ r2.l ^ r3.l;
46328             s1.h = r1.h ^ r2.h ^ r3.h;
46329             //sigma0
46330             int64rrot(r1, W[j - 15], 1);
46331             int64rrot(r2, W[j - 15], 8);
46332             int64shr(r3, W[j - 15], 7);
46333             s0.l = r1.l ^ r2.l ^ r3.l;
46334             s0.h = r1.h ^ r2.h ^ r3.h;
46335
46336             int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
46337           }
46338
46339           for (j = 0; j < 80; j += 1) {
46340             //Ch
46341             Ch.l = (e.l & f.l) ^ (~e.l & g.l);
46342             Ch.h = (e.h & f.h) ^ (~e.h & g.h);
46343
46344             //Sigma1
46345             int64rrot(r1, e, 14);
46346             int64rrot(r2, e, 18);
46347             int64revrrot(r3, e, 9);
46348             s1.l = r1.l ^ r2.l ^ r3.l;
46349             s1.h = r1.h ^ r2.h ^ r3.h;
46350
46351             //Sigma0
46352             int64rrot(r1, a, 28);
46353             int64revrrot(r2, a, 2);
46354             int64revrrot(r3, a, 7);
46355             s0.l = r1.l ^ r2.l ^ r3.l;
46356             s0.h = r1.h ^ r2.h ^ r3.h;
46357
46358             //Maj
46359             Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
46360             Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
46361
46362             int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
46363             int64add(T2, s0, Maj);
46364
46365             int64copy(h, g);
46366             int64copy(g, f);
46367             int64copy(f, e);
46368             int64add(e, d, T1);
46369             int64copy(d, c);
46370             int64copy(c, b);
46371             int64copy(b, a);
46372             int64add(a, T1, T2);
46373           }
46374           int64add(H[0], H[0], a);
46375           int64add(H[1], H[1], b);
46376           int64add(H[2], H[2], c);
46377           int64add(H[3], H[3], d);
46378           int64add(H[4], H[4], e);
46379           int64add(H[5], H[5], f);
46380           int64add(H[6], H[6], g);
46381           int64add(H[7], H[7], h);
46382         }
46383
46384         //represent the hash as an array of 32-bit dwords
46385         for (i = 0; i < 8; i += 1) {
46386           hash[2 * i] = H[i].h;
46387           hash[2 * i + 1] = H[i].l;
46388         }
46389         return hash;
46390       }
46391
46392       //A constructor for 64-bit numbers
46393
46394       function int64(h, l) {
46395         this.h = h;
46396         this.l = l;
46397         //this.toString = int64toString;
46398       }
46399
46400       //Copies src into dst, assuming both are 64-bit numbers
46401
46402       function int64copy(dst, src) {
46403         dst.h = src.h;
46404         dst.l = src.l;
46405       }
46406
46407       //Right-rotates a 64-bit number by shift
46408       //Won't handle cases of shift>=32
46409       //The function revrrot() is for that
46410
46411       function int64rrot(dst, x, shift) {
46412         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
46413         dst.h = (x.h >>> shift) | (x.l << (32 - shift));
46414       }
46415
46416       //Reverses the dwords of the source and then rotates right by shift.
46417       //This is equivalent to rotation by 32+shift
46418
46419       function int64revrrot(dst, x, shift) {
46420         dst.l = (x.h >>> shift) | (x.l << (32 - shift));
46421         dst.h = (x.l >>> shift) | (x.h << (32 - shift));
46422       }
46423
46424       //Bitwise-shifts right a 64-bit number by shift
46425       //Won't handle shift>=32, but it's never needed in SHA512
46426
46427       function int64shr(dst, x, shift) {
46428         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
46429         dst.h = (x.h >>> shift);
46430       }
46431
46432       //Adds two 64-bit numbers
46433       //Like the original implementation, does not rely on 32-bit operations
46434
46435       function int64add(dst, x, y) {
46436         var w0 = (x.l & 0xffff) + (y.l & 0xffff);
46437         var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
46438         var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
46439         var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
46440         dst.l = (w0 & 0xffff) | (w1 << 16);
46441         dst.h = (w2 & 0xffff) | (w3 << 16);
46442       }
46443
46444       //Same, except with 4 addends. Works faster than adding them one by one.
46445
46446       function int64add4(dst, a, b, c, d) {
46447         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
46448         var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
46449         var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
46450         var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
46451         dst.l = (w0 & 0xffff) | (w1 << 16);
46452         dst.h = (w2 & 0xffff) | (w3 << 16);
46453       }
46454
46455       //Same, except with 5 addends
46456
46457       function int64add5(dst, a, b, c, d, e) {
46458         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
46459           w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
46460           w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
46461           w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
46462         dst.l = (w0 & 0xffff) | (w1 << 16);
46463         dst.h = (w2 & 0xffff) | (w3 << 16);
46464       }
46465     },
46466     /**
46467      * @class Hashes.RMD160
46468      * @constructor
46469      * @param {Object} [config]
46470      *
46471      * A JavaScript implementation of the RIPEMD-160 Algorithm
46472      * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
46473      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
46474      * See http://pajhome.org.uk/crypt/md5 for details.
46475      * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
46476      */
46477     RMD160: function(options) {
46478       /**
46479        * Private properties configuration variables. You may need to tweak these to be compatible with
46480        * the server-side, but the defaults work in most cases.
46481        * @see this.setUpperCase() method
46482        * @see this.setPad() method
46483        */
46484       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
46485         /* hexadecimal output case format. false - lowercase; true - uppercase  */
46486         b64pad = (options && typeof options.pad === 'string') ? options.pa : '=',
46487         /* base-64 pad character. Default '=' for strict RFC compliance   */
46488         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
46489         /* enable/disable utf8 encoding */
46490         rmd160_r1 = [
46491           0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
46492           7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
46493           3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
46494           1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
46495           4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
46496         ],
46497         rmd160_r2 = [
46498           5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
46499           6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
46500           15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
46501           8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
46502           12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
46503         ],
46504         rmd160_s1 = [
46505           11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
46506           7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
46507           11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
46508           11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
46509           9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
46510         ],
46511         rmd160_s2 = [
46512           8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
46513           9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
46514           9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
46515           15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
46516           8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
46517         ];
46518
46519       /* privileged (public) methods */
46520       this.hex = function(s) {
46521         return rstr2hex(rstr(s, utf8));
46522       };
46523       this.b64 = function(s) {
46524         return rstr2b64(rstr(s, utf8), b64pad);
46525       };
46526       this.any = function(s, e) {
46527         return rstr2any(rstr(s, utf8), e);
46528       };
46529       this.raw = function(s) {
46530         return rstr(s, utf8);
46531       };
46532       this.hex_hmac = function(k, d) {
46533         return rstr2hex(rstr_hmac(k, d));
46534       };
46535       this.b64_hmac = function(k, d) {
46536         return rstr2b64(rstr_hmac(k, d), b64pad);
46537       };
46538       this.any_hmac = function(k, d, e) {
46539         return rstr2any(rstr_hmac(k, d), e);
46540       };
46541       /**
46542        * Perform a simple self-test to see if the VM is working
46543        * @return {String} Hexadecimal hash sample
46544        * @public
46545        */
46546       this.vm_test = function() {
46547         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
46548       };
46549       /**
46550        * @description Enable/disable uppercase hexadecimal returned string
46551        * @param {boolean}
46552        * @return {Object} this
46553        * @public
46554        */
46555       this.setUpperCase = function(a) {
46556         if (typeof a === 'boolean') {
46557           hexcase = a;
46558         }
46559         return this;
46560       };
46561       /**
46562        * @description Defines a base64 pad string
46563        * @param {string} Pad
46564        * @return {Object} this
46565        * @public
46566        */
46567       this.setPad = function(a) {
46568         if (typeof a !== 'undefined') {
46569           b64pad = a;
46570         }
46571         return this;
46572       };
46573       /**
46574        * @description Defines a base64 pad string
46575        * @param {boolean}
46576        * @return {Object} this
46577        * @public
46578        */
46579       this.setUTF8 = function(a) {
46580         if (typeof a === 'boolean') {
46581           utf8 = a;
46582         }
46583         return this;
46584       };
46585
46586       /* private methods */
46587
46588       /**
46589        * Calculate the rmd160 of a raw string
46590        */
46591
46592       function rstr(s) {
46593         s = (utf8) ? utf8Encode(s) : s;
46594         return binl2rstr(binl(rstr2binl(s), s.length * 8));
46595       }
46596
46597       /**
46598        * Calculate the HMAC-rmd160 of a key and some data (raw strings)
46599        */
46600
46601       function rstr_hmac(key, data) {
46602         key = (utf8) ? utf8Encode(key) : key;
46603         data = (utf8) ? utf8Encode(data) : data;
46604         var i, hash,
46605           bkey = rstr2binl(key),
46606           ipad = Array(16),
46607           opad = Array(16);
46608
46609         if (bkey.length > 16) {
46610           bkey = binl(bkey, key.length * 8);
46611         }
46612
46613         for (i = 0; i < 16; i += 1) {
46614           ipad[i] = bkey[i] ^ 0x36363636;
46615           opad[i] = bkey[i] ^ 0x5C5C5C5C;
46616         }
46617         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
46618         return binl2rstr(binl(opad.concat(hash), 512 + 160));
46619       }
46620
46621       /**
46622        * Convert an array of little-endian words to a string
46623        */
46624
46625       function binl2rstr(input) {
46626         var i, output = '',
46627           l = input.length * 32;
46628         for (i = 0; i < l; i += 8) {
46629           output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
46630         }
46631         return output;
46632       }
46633
46634       /**
46635        * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
46636        */
46637
46638       function binl(x, len) {
46639         var T, j, i, l,
46640           h0 = 0x67452301,
46641           h1 = 0xefcdab89,
46642           h2 = 0x98badcfe,
46643           h3 = 0x10325476,
46644           h4 = 0xc3d2e1f0,
46645           A1, B1, C1, D1, E1,
46646           A2, B2, C2, D2, E2;
46647
46648         /* append padding */
46649         x[len >> 5] |= 0x80 << (len % 32);
46650         x[(((len + 64) >>> 9) << 4) + 14] = len;
46651         l = x.length;
46652
46653         for (i = 0; i < l; i += 16) {
46654           A1 = A2 = h0;
46655           B1 = B2 = h1;
46656           C1 = C2 = h2;
46657           D1 = D2 = h3;
46658           E1 = E2 = h4;
46659           for (j = 0; j <= 79; j += 1) {
46660             T = safe_add(A1, rmd160_f(j, B1, C1, D1));
46661             T = safe_add(T, x[i + rmd160_r1[j]]);
46662             T = safe_add(T, rmd160_K1(j));
46663             T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
46664             A1 = E1;
46665             E1 = D1;
46666             D1 = bit_rol(C1, 10);
46667             C1 = B1;
46668             B1 = T;
46669             T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
46670             T = safe_add(T, x[i + rmd160_r2[j]]);
46671             T = safe_add(T, rmd160_K2(j));
46672             T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
46673             A2 = E2;
46674             E2 = D2;
46675             D2 = bit_rol(C2, 10);
46676             C2 = B2;
46677             B2 = T;
46678           }
46679
46680           T = safe_add(h1, safe_add(C1, D2));
46681           h1 = safe_add(h2, safe_add(D1, E2));
46682           h2 = safe_add(h3, safe_add(E1, A2));
46683           h3 = safe_add(h4, safe_add(A1, B2));
46684           h4 = safe_add(h0, safe_add(B1, C2));
46685           h0 = T;
46686         }
46687         return [h0, h1, h2, h3, h4];
46688       }
46689
46690       // specific algorithm methods
46691
46692       function rmd160_f(j, x, y, z) {
46693         return (0 <= j && j <= 15) ? (x ^ y ^ z) :
46694           (16 <= j && j <= 31) ? (x & y) | (~x & z) :
46695           (32 <= j && j <= 47) ? (x | ~y) ^ z :
46696           (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
46697           (64 <= j && j <= 79) ? x ^ (y | ~z) :
46698           'rmd160_f: j out of range';
46699       }
46700
46701       function rmd160_K1(j) {
46702         return (0 <= j && j <= 15) ? 0x00000000 :
46703           (16 <= j && j <= 31) ? 0x5a827999 :
46704           (32 <= j && j <= 47) ? 0x6ed9eba1 :
46705           (48 <= j && j <= 63) ? 0x8f1bbcdc :
46706           (64 <= j && j <= 79) ? 0xa953fd4e :
46707           'rmd160_K1: j out of range';
46708       }
46709
46710       function rmd160_K2(j) {
46711         return (0 <= j && j <= 15) ? 0x50a28be6 :
46712           (16 <= j && j <= 31) ? 0x5c4dd124 :
46713           (32 <= j && j <= 47) ? 0x6d703ef3 :
46714           (48 <= j && j <= 63) ? 0x7a6d76e9 :
46715           (64 <= j && j <= 79) ? 0x00000000 :
46716           'rmd160_K2: j out of range';
46717       }
46718     }
46719   };
46720
46721   // exposes Hashes
46722   (function(window, undefined) {
46723     var freeExports = false;
46724     {
46725       freeExports = exports;
46726       if (exports && typeof commonjsGlobal === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
46727         window = commonjsGlobal;
46728       }
46729     }
46730
46731     if (typeof undefined === 'function' && typeof undefined.amd === 'object' && undefined.amd) {
46732       // define as an anonymous module, so, through path mapping, it can be aliased
46733       undefined(function() {
46734         return Hashes;
46735       });
46736     } else if (freeExports) {
46737       // in Node.js or RingoJS v0.8.0+
46738       if ('object' === 'object' && module && module.exports === freeExports) {
46739         module.exports = Hashes;
46740       }
46741       // in Narwhal or RingoJS v0.7.0-
46742       else {
46743         freeExports.Hashes = Hashes;
46744       }
46745     } else {
46746       // in a browser or Rhino
46747       window.Hashes = Hashes;
46748     }
46749   }(this));
46750 }()); // IIFE
46751 });
46752
46753 var immutable = extend$2;
46754
46755 var hasOwnProperty = Object.prototype.hasOwnProperty;
46756
46757 function extend$2() {
46758     var target = {};
46759
46760     for (var i = 0; i < arguments.length; i++) {
46761         var source = arguments[i];
46762
46763         for (var key in source) {
46764             if (hasOwnProperty.call(source, key)) {
46765                 target[key] = source[key];
46766             }
46767         }
46768     }
46769
46770     return target
46771 }
46772
46773 var sha1 = new hashes.SHA1();
46774
46775 var ohauth = {};
46776
46777 ohauth.qsString = function(obj) {
46778     return Object.keys(obj).sort().map(function(key) {
46779         return ohauth.percentEncode(key) + '=' +
46780             ohauth.percentEncode(obj[key]);
46781     }).join('&');
46782 };
46783
46784 ohauth.stringQs = function(str) {
46785     return str.split('&').filter(function (pair) {
46786         return pair !== '';
46787     }).reduce(function(obj, pair){
46788         var parts = pair.split('=');
46789         obj[decodeURIComponent(parts[0])] = (null === parts[1]) ?
46790             '' : decodeURIComponent(parts[1]);
46791         return obj;
46792     }, {});
46793 };
46794
46795 ohauth.rawxhr = function(method, url, data, headers, callback) {
46796     var xhr = new XMLHttpRequest(),
46797         twoHundred = /^20\d$/;
46798     xhr.onreadystatechange = function() {
46799         if (4 === xhr.readyState && 0 !== xhr.status) {
46800             if (twoHundred.test(xhr.status)) callback(null, xhr);
46801             else return callback(xhr, null);
46802         }
46803     };
46804     xhr.onerror = function(e) { return callback(e, null); };
46805     xhr.open(method, url, true);
46806     for (var h in headers) xhr.setRequestHeader(h, headers[h]);
46807     xhr.send(data);
46808     return xhr;
46809 };
46810
46811 ohauth.xhr = function(method, url, auth, data, options, callback) {
46812     var headers = (options && options.header) || {
46813         'Content-Type': 'application/x-www-form-urlencoded'
46814     };
46815     headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
46816     return ohauth.rawxhr(method, url, data, headers, callback);
46817 };
46818
46819 ohauth.nonce = function() {
46820     for (var o = ''; o.length < 6;) {
46821         o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
46822     }
46823     return o;
46824 };
46825
46826 ohauth.authHeader = function(obj) {
46827     return Object.keys(obj).sort().map(function(key) {
46828         return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
46829     }).join(', ');
46830 };
46831
46832 ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
46833
46834 ohauth.percentEncode = function(s) {
46835     return encodeURIComponent(s)
46836         .replace(/\!/g, '%21').replace(/\'/g, '%27')
46837         .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
46838 };
46839
46840 ohauth.baseString = function(method, url, params) {
46841     if (params.oauth_signature) delete params.oauth_signature;
46842     return [
46843         method,
46844         ohauth.percentEncode(url),
46845         ohauth.percentEncode(ohauth.qsString(params))].join('&');
46846 };
46847
46848 ohauth.signature = function(oauth_secret, token_secret, baseString) {
46849     return sha1.b64_hmac(
46850         ohauth.percentEncode(oauth_secret) + '&' +
46851         ohauth.percentEncode(token_secret),
46852         baseString);
46853 };
46854
46855 /**
46856  * Takes an options object for configuration (consumer_key,
46857  * consumer_secret, version, signature_method, token, token_secret)
46858  * and returns a function that generates the Authorization header
46859  * for given data.
46860  *
46861  * The returned function takes these parameters:
46862  * - method: GET/POST/...
46863  * - uri: full URI with protocol, port, path and query string
46864  * - extra_params: any extra parameters (that are passed in the POST data),
46865  *   can be an object or a from-urlencoded string.
46866  *
46867  * Returned function returns full OAuth header with "OAuth" string in it.
46868  */
46869
46870 ohauth.headerGenerator = function(options) {
46871     options = options || {};
46872     var consumer_key = options.consumer_key || '',
46873         consumer_secret = options.consumer_secret || '',
46874         signature_method = options.signature_method || 'HMAC-SHA1',
46875         version = options.version || '1.0',
46876         token = options.token || '',
46877         token_secret = options.token_secret || '';
46878
46879     return function(method, uri, extra_params) {
46880         method = method.toUpperCase();
46881         if (typeof extra_params === 'string' && extra_params.length > 0) {
46882             extra_params = ohauth.stringQs(extra_params);
46883         }
46884
46885         var uri_parts = uri.split('?', 2),
46886         base_uri = uri_parts[0];
46887
46888         var query_params = uri_parts.length === 2 ?
46889             ohauth.stringQs(uri_parts[1]) : {};
46890
46891         var oauth_params = {
46892             oauth_consumer_key: consumer_key,
46893             oauth_signature_method: signature_method,
46894             oauth_version: version,
46895             oauth_timestamp: ohauth.timestamp(),
46896             oauth_nonce: ohauth.nonce()
46897         };
46898
46899         if (token) oauth_params.oauth_token = token;
46900
46901         var all_params = immutable({}, oauth_params, query_params, extra_params),
46902             base_str = ohauth.baseString(method, base_uri, all_params);
46903
46904         oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
46905
46906         return 'OAuth ' + ohauth.authHeader(oauth_params);
46907     };
46908 };
46909
46910 var index$13 = ohauth;
46911
46912 var resolveUrl = createCommonjsModule(function (module, exports) {
46913 // Copyright 2014 Simon Lydell
46914 // X11 (“MIT”) Licensed. (See LICENSE.)
46915
46916 void (function(root, factory) {
46917   if (typeof undefined === "function" && undefined.amd) {
46918     undefined(factory);
46919   } else {
46920     module.exports = factory();
46921   }
46922 }(commonjsGlobal, function() {
46923
46924   function resolveUrl(/* ...urls */) {
46925     var numUrls = arguments.length;
46926
46927     if (numUrls === 0) {
46928       throw new Error("resolveUrl requires at least one argument; got none.")
46929     }
46930
46931     var base = document.createElement("base");
46932     base.href = arguments[0];
46933
46934     if (numUrls === 1) {
46935       return base.href
46936     }
46937
46938     var head = document.getElementsByTagName("head")[0];
46939     head.insertBefore(base, head.firstChild);
46940
46941     var a = document.createElement("a");
46942     var resolved;
46943
46944     for (var index = 1; index < numUrls; index++) {
46945       a.href = arguments[index];
46946       resolved = a.href;
46947       base.href = resolved;
46948     }
46949
46950     head.removeChild(base);
46951
46952     return resolved
46953   }
46954
46955   return resolveUrl
46956
46957 }));
46958 });
46959
46960 var assign = make_assign();
46961 var create$2 = make_create();
46962 var trim = make_trim();
46963 var Global = (typeof window !== 'undefined' ? window : commonjsGlobal);
46964
46965 var util = {
46966         assign: assign,
46967         create: create$2,
46968         trim: trim,
46969         bind: bind$1,
46970         slice: slice$8,
46971         each: each$1,
46972         map: map$4,
46973         pluck: pluck$1,
46974         isList: isList$1,
46975         isFunction: isFunction$1,
46976         isObject: isObject$1,
46977         Global: Global
46978 };
46979
46980 function make_assign() {
46981         if (Object.assign) {
46982                 return Object.assign
46983         } else {
46984                 return function shimAssign(obj, props1, props2, etc) {
46985                         for (var i = 1; i < arguments.length; i++) {
46986                                 each$1(Object(arguments[i]), function(val, key) {
46987                                         obj[key] = val;
46988                                 });
46989                         }                       
46990                         return obj
46991                 }
46992         }
46993 }
46994
46995 function make_create() {
46996         if (Object.create) {
46997                 return function create(obj, assignProps1, assignProps2, etc) {
46998                         var assignArgsList = slice$8(arguments, 1);
46999                         return assign.apply(this, [Object.create(obj)].concat(assignArgsList))
47000                 }
47001         } else {
47002                 function F() {} // eslint-disable-line no-inner-declarations
47003                 return function create(obj, assignProps1, assignProps2, etc) {
47004                         var assignArgsList = slice$8(arguments, 1);
47005                         F.prototype = obj;
47006                         return assign.apply(this, [new F()].concat(assignArgsList))
47007                 }
47008         }
47009 }
47010
47011 function make_trim() {
47012         if (String.prototype.trim) {
47013                 return function trim(str) {
47014                         return String.prototype.trim.call(str)
47015                 }
47016         } else {
47017                 return function trim(str) {
47018                         return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
47019                 }
47020         }
47021 }
47022
47023 function bind$1(obj, fn) {
47024         return function() {
47025                 return fn.apply(obj, Array.prototype.slice.call(arguments, 0))
47026         }
47027 }
47028
47029 function slice$8(arr, index) {
47030         return Array.prototype.slice.call(arr, index || 0)
47031 }
47032
47033 function each$1(obj, fn) {
47034         pluck$1(obj, function(val, key) {
47035                 fn(val, key);
47036                 return false
47037         });
47038 }
47039
47040 function map$4(obj, fn) {
47041         var res = (isList$1(obj) ? [] : {});
47042         pluck$1(obj, function(v, k) {
47043                 res[k] = fn(v, k);
47044                 return false
47045         });
47046         return res
47047 }
47048
47049 function pluck$1(obj, fn) {
47050         if (isList$1(obj)) {
47051                 for (var i=0; i<obj.length; i++) {
47052                         if (fn(obj[i], i)) {
47053                                 return obj[i]
47054                         }
47055                 }
47056         } else {
47057                 for (var key in obj) {
47058                         if (obj.hasOwnProperty(key)) {
47059                                 if (fn(obj[key], key)) {
47060                                         return obj[key]
47061                                 }
47062                         }
47063                 }
47064         }
47065 }
47066
47067 function isList$1(val) {
47068         return (val != null && typeof val != 'function' && typeof val.length == 'number')
47069 }
47070
47071 function isFunction$1(val) {
47072         return val && {}.toString.call(val) === '[object Function]'
47073 }
47074
47075 function isObject$1(val) {
47076         return val && {}.toString.call(val) === '[object Object]'
47077 }
47078
47079 var slice$7 = util.slice;
47080 var pluck = util.pluck;
47081 var each = util.each;
47082 var bind = util.bind;
47083 var create$1 = util.create;
47084 var isList = util.isList;
47085 var isFunction = util.isFunction;
47086 var isObject = util.isObject;
47087
47088 var storeEngine = {
47089         createStore: createStore
47090 };
47091
47092 var storeAPI = {
47093         version: '2.0.12',
47094         enabled: false,
47095         
47096         // get returns the value of the given key. If that value
47097         // is undefined, it returns optionalDefaultValue instead.
47098         get: function(key, optionalDefaultValue) {
47099                 var data = this.storage.read(this._namespacePrefix + key);
47100                 return this._deserialize(data, optionalDefaultValue)
47101         },
47102
47103         // set will store the given value at key and returns value.
47104         // Calling set with value === undefined is equivalent to calling remove.
47105         set: function(key, value) {
47106                 if (value === undefined) {
47107                         return this.remove(key)
47108                 }
47109                 this.storage.write(this._namespacePrefix + key, this._serialize(value));
47110                 return value
47111         },
47112
47113         // remove deletes the key and value stored at the given key.
47114         remove: function(key) {
47115                 this.storage.remove(this._namespacePrefix + key);
47116         },
47117
47118         // each will call the given callback once for each key-value pair
47119         // in this store.
47120         each: function(callback) {
47121                 var self = this;
47122                 this.storage.each(function(val, namespacedKey) {
47123                         callback.call(self, self._deserialize(val), (namespacedKey || '').replace(self._namespaceRegexp, ''));
47124                 });
47125         },
47126
47127         // clearAll will remove all the stored key-value pairs in this store.
47128         clearAll: function() {
47129                 this.storage.clearAll();
47130         },
47131
47132         // additional functionality that can't live in plugins
47133         // ---------------------------------------------------
47134
47135         // hasNamespace returns true if this store instance has the given namespace.
47136         hasNamespace: function(namespace) {
47137                 return (this._namespacePrefix == '__storejs_'+namespace+'_')
47138         },
47139
47140         // createStore creates a store.js instance with the first
47141         // functioning storage in the list of storage candidates,
47142         // and applies the the given mixins to the instance.
47143         createStore: function() {
47144                 return createStore.apply(this, arguments)
47145         },
47146         
47147         addPlugin: function(plugin) {
47148                 this._addPlugin(plugin);
47149         },
47150         
47151         namespace: function(namespace) {
47152                 return createStore(this.storage, this.plugins, namespace)
47153         }
47154 };
47155
47156 function _warn() {
47157         var _console = (typeof console == 'undefined' ? null : console);
47158         if (!_console) { return }
47159         var fn = (_console.warn ? _console.warn : _console.log);
47160         fn.apply(_console, arguments);
47161 }
47162
47163 function createStore(storages, plugins, namespace) {
47164         if (!namespace) {
47165                 namespace = '';
47166         }
47167         if (storages && !isList(storages)) {
47168                 storages = [storages];
47169         }
47170         if (plugins && !isList(plugins)) {
47171                 plugins = [plugins];
47172         }
47173
47174         var namespacePrefix = (namespace ? '__storejs_'+namespace+'_' : '');
47175         var namespaceRegexp = (namespace ? new RegExp('^'+namespacePrefix) : null);
47176         var legalNamespaces = /^[a-zA-Z0-9_\-]*$/; // alpha-numeric + underscore and dash
47177         if (!legalNamespaces.test(namespace)) {
47178                 throw new Error('store.js namespaces can only have alphanumerics + underscores and dashes')
47179         }
47180         
47181         var _privateStoreProps = {
47182                 _namespacePrefix: namespacePrefix,
47183                 _namespaceRegexp: namespaceRegexp,
47184
47185                 _testStorage: function(storage) {
47186                         try {
47187                                 var testStr = '__storejs__test__';
47188                                 storage.write(testStr, testStr);
47189                                 var ok = (storage.read(testStr) === testStr);
47190                                 storage.remove(testStr);
47191                                 return ok
47192                         } catch(e) {
47193                                 return false
47194                         }
47195                 },
47196
47197                 _assignPluginFnProp: function(pluginFnProp, propName) {
47198                         var oldFn = this[propName];
47199                         this[propName] = function pluginFn() {
47200                                 var args = slice$7(arguments, 0);
47201                                 var self = this;
47202
47203                                 // super_fn calls the old function which was overwritten by
47204                                 // this mixin.
47205                                 function super_fn() {
47206                                         if (!oldFn) { return }
47207                                         each(arguments, function(arg, i) {
47208                                                 args[i] = arg;
47209                                         });
47210                                         return oldFn.apply(self, args)
47211                                 }
47212
47213                                 // Give mixing function access to super_fn by prefixing all mixin function
47214                                 // arguments with super_fn.
47215                                 var newFnArgs = [super_fn].concat(args);
47216
47217                                 return pluginFnProp.apply(self, newFnArgs)
47218                         };
47219                 },
47220
47221                 _serialize: function(obj) {
47222                         return JSON.stringify(obj)
47223                 },
47224
47225                 _deserialize: function(strVal, defaultVal) {
47226                         if (!strVal) { return defaultVal }
47227                         // It is possible that a raw string value has been previously stored
47228                         // in a storage without using store.js, meaning it will be a raw
47229                         // string value instead of a JSON serialized string. By defaulting
47230                         // to the raw string value in case of a JSON parse error, we allow
47231                         // for past stored values to be forwards-compatible with store.js
47232                         var val = '';
47233                         try { val = JSON.parse(strVal); }
47234                         catch(e) { val = strVal; }
47235
47236                         return (val !== undefined ? val : defaultVal)
47237                 },
47238                 
47239                 _addStorage: function(storage) {
47240                         if (this.enabled) { return }
47241                         if (this._testStorage(storage)) {
47242                                 this.storage = storage;
47243                                 this.enabled = true;
47244                         }
47245                 },
47246
47247                 _addPlugin: function(plugin) {
47248                         var self = this;
47249
47250                         // If the plugin is an array, then add all plugins in the array.
47251                         // This allows for a plugin to depend on other plugins.
47252                         if (isList(plugin)) {
47253                                 each(plugin, function(plugin) {
47254                                         self._addPlugin(plugin);
47255                                 });
47256                                 return
47257                         }
47258
47259                         // Keep track of all plugins we've seen so far, so that we
47260                         // don't add any of them twice.
47261                         var seenPlugin = pluck(this.plugins, function(seenPlugin) {
47262                                 return (plugin === seenPlugin)
47263                         });
47264                         if (seenPlugin) {
47265                                 return
47266                         }
47267                         this.plugins.push(plugin);
47268
47269                         // Check that the plugin is properly formed
47270                         if (!isFunction(plugin)) {
47271                                 throw new Error('Plugins must be function values that return objects')
47272                         }
47273
47274                         var pluginProperties = plugin.call(this);
47275                         if (!isObject(pluginProperties)) {
47276                                 throw new Error('Plugins must return an object of function properties')
47277                         }
47278
47279                         // Add the plugin function properties to this store instance.
47280                         each(pluginProperties, function(pluginFnProp, propName) {
47281                                 if (!isFunction(pluginFnProp)) {
47282                                         throw new Error('Bad plugin property: '+propName+' from plugin '+plugin.name+'. Plugins should only return functions.')
47283                                 }
47284                                 self._assignPluginFnProp(pluginFnProp, propName);
47285                         });
47286                 },
47287                 
47288                 // Put deprecated properties in the private API, so as to not expose it to accidential
47289                 // discovery through inspection of the store object.
47290                 
47291                 // Deprecated: addStorage
47292                 addStorage: function(storage) {
47293                         _warn('store.addStorage(storage) is deprecated. Use createStore([storages])');
47294                         this._addStorage(storage);
47295                 }
47296         };
47297
47298         var store = create$1(_privateStoreProps, storeAPI, {
47299                 plugins: []
47300         });
47301         store.raw = {};
47302         each(store, function(prop, propName) {
47303                 if (isFunction(prop)) {
47304                         store.raw[propName] = bind(store, prop);                        
47305                 }
47306         });
47307         each(storages, function(storage) {
47308                 store._addStorage(storage);
47309         });
47310         each(plugins, function(plugin) {
47311                 store._addPlugin(plugin);
47312         });
47313         return store
47314 }
47315
47316 var Global$1 = util.Global;
47317
47318 var localStorage_1 = {
47319         name: 'localStorage',
47320         read: read,
47321         write: write,
47322         each: each$2,
47323         remove: remove$2,
47324         clearAll: clearAll,
47325 };
47326
47327 function localStorage$1() {
47328         return Global$1.localStorage
47329 }
47330
47331 function read(key) {
47332         return localStorage$1().getItem(key)
47333 }
47334
47335 function write(key, data) {
47336         return localStorage$1().setItem(key, data)
47337 }
47338
47339 function each$2(fn) {
47340         for (var i = localStorage$1().length - 1; i >= 0; i--) {
47341                 var key = localStorage$1().key(i);
47342                 fn(read(key), key);
47343         }
47344 }
47345
47346 function remove$2(key) {
47347         return localStorage$1().removeItem(key)
47348 }
47349
47350 function clearAll() {
47351         return localStorage$1().clear()
47352 }
47353
47354 // oldFF-globalStorage provides storage for Firefox
47355 // versions 6 and 7, where no localStorage, etc
47356 // is available.
47357
47358
47359 var Global$2 = util.Global;
47360
47361 var oldFFGlobalStorage = {
47362         name: 'oldFF-globalStorage',
47363         read: read$1,
47364         write: write$1,
47365         each: each$3,
47366         remove: remove$3,
47367         clearAll: clearAll$1,
47368 };
47369
47370 var globalStorage = Global$2.globalStorage;
47371
47372 function read$1(key) {
47373         return globalStorage[key]
47374 }
47375
47376 function write$1(key, data) {
47377         globalStorage[key] = data;
47378 }
47379
47380 function each$3(fn) {
47381         for (var i = globalStorage.length - 1; i >= 0; i--) {
47382                 var key = globalStorage.key(i);
47383                 fn(globalStorage[key], key);
47384         }
47385 }
47386
47387 function remove$3(key) {
47388         return globalStorage.removeItem(key)
47389 }
47390
47391 function clearAll$1() {
47392         each$3(function(key, _) {
47393                 delete globalStorage[key];
47394         });
47395 }
47396
47397 // oldIE-userDataStorage provides storage for Internet Explorer
47398 // versions 6 and 7, where no localStorage, sessionStorage, etc
47399 // is available.
47400
47401
47402 var Global$3 = util.Global;
47403
47404 var oldIEUserDataStorage = {
47405         name: 'oldIE-userDataStorage',
47406         write: write$2,
47407         read: read$2,
47408         each: each$4,
47409         remove: remove$4,
47410         clearAll: clearAll$2,
47411 };
47412
47413 var storageName = 'storejs';
47414 var doc = Global$3.document;
47415 var _withStorageEl = _makeIEStorageElFunction();
47416 var disable = (Global$3.navigator ? Global$3.navigator.userAgent : '').match(/ (MSIE 8|MSIE 9|MSIE 10)\./); // MSIE 9.x, MSIE 10.x
47417
47418 function write$2(unfixedKey, data) {
47419         if (disable) { return }
47420         var fixedKey = fixKey(unfixedKey);
47421         _withStorageEl(function(storageEl) {
47422                 storageEl.setAttribute(fixedKey, data);
47423                 storageEl.save(storageName);
47424         });
47425 }
47426
47427 function read$2(unfixedKey) {
47428         if (disable) { return }
47429         var fixedKey = fixKey(unfixedKey);
47430         var res = null;
47431         _withStorageEl(function(storageEl) {
47432                 res = storageEl.getAttribute(fixedKey);
47433         });
47434         return res
47435 }
47436
47437 function each$4(callback) {
47438         _withStorageEl(function(storageEl) {
47439                 var attributes = storageEl.XMLDocument.documentElement.attributes;
47440                 for (var i=attributes.length-1; i>=0; i--) {
47441                         var attr = attributes[i];
47442                         callback(storageEl.getAttribute(attr.name), attr.name);
47443                 }
47444         });
47445 }
47446
47447 function remove$4(unfixedKey) {
47448         var fixedKey = fixKey(unfixedKey);
47449         _withStorageEl(function(storageEl) {
47450                 storageEl.removeAttribute(fixedKey);
47451                 storageEl.save(storageName);
47452         });
47453 }
47454
47455 function clearAll$2() {
47456         _withStorageEl(function(storageEl) {
47457                 var attributes = storageEl.XMLDocument.documentElement.attributes;
47458                 storageEl.load(storageName);
47459                 for (var i=attributes.length-1; i>=0; i--) {
47460                         storageEl.removeAttribute(attributes[i].name);
47461                 }
47462                 storageEl.save(storageName);
47463         });
47464 }
47465
47466 // Helpers
47467 //////////
47468
47469 // In IE7, keys cannot start with a digit or contain certain chars.
47470 // See https://github.com/marcuswestin/store.js/issues/40
47471 // See https://github.com/marcuswestin/store.js/issues/83
47472 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
47473 function fixKey(key) {
47474         return key.replace(/^\d/, '___$&').replace(forbiddenCharsRegex, '___')
47475 }
47476
47477 function _makeIEStorageElFunction() {
47478         if (!doc || !doc.documentElement || !doc.documentElement.addBehavior) {
47479                 return null
47480         }
47481         var scriptTag = 'script',
47482                 storageOwner,
47483                 storageContainer,
47484                 storageEl;
47485
47486         // Since #userData storage applies only to specific paths, we need to
47487         // somehow link our data to a specific path.  We choose /favicon.ico
47488         // as a pretty safe option, since all browsers already make a request to
47489         // this URL anyway and being a 404 will not hurt us here.  We wrap an
47490         // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
47491         // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
47492         // since the iframe access rules appear to allow direct access and
47493         // manipulation of the document element, even for a 404 page.  This
47494         // document can be used instead of the current document (which would
47495         // have been limited to the current path) to perform #userData storage.
47496         try {
47497                 /* global ActiveXObject */
47498                 storageContainer = new ActiveXObject('htmlfile');
47499                 storageContainer.open();
47500                 storageContainer.write('<'+scriptTag+'>document.w=window</'+scriptTag+'><iframe src="/favicon.ico"></iframe>');
47501                 storageContainer.close();
47502                 storageOwner = storageContainer.w.frames[0].document;
47503                 storageEl = storageOwner.createElement('div');
47504         } catch(e) {
47505                 // somehow ActiveXObject instantiation failed (perhaps some special
47506                 // security settings or otherwse), fall back to per-path storage
47507                 storageEl = doc.createElement('div');
47508                 storageOwner = doc.body;
47509         }
47510
47511         return function(storeFunction) {
47512                 var args = [].slice.call(arguments, 0);
47513                 args.unshift(storageEl);
47514                 // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
47515                 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
47516                 storageOwner.appendChild(storageEl);
47517                 storageEl.addBehavior('#default#userData');
47518                 storageEl.load(storageName);
47519                 storeFunction.apply(this, args);
47520                 storageOwner.removeChild(storageEl);
47521                 return
47522         }
47523 }
47524
47525 // cookieStorage is useful Safari private browser mode, where localStorage
47526 // doesn't work but cookies do. This implementation is adopted from
47527 // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
47528
47529
47530 var Global$4 = util.Global;
47531 var trim$1 = util.trim;
47532
47533 var cookieStorage = {
47534         name: 'cookieStorage',
47535         read: read$3,
47536         write: write$3,
47537         each: each$5,
47538         remove: remove$5,
47539         clearAll: clearAll$3,
47540 };
47541
47542 var doc$1 = Global$4.document;
47543
47544 function read$3(key) {
47545         if (!key || !_has(key)) { return null }
47546         var regexpStr = "(?:^|.*;\\s*)" +
47547                 escape(key).replace(/[\-\.\+\*]/g, "\\$&") +
47548                 "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
47549         return unescape(doc$1.cookie.replace(new RegExp(regexpStr), "$1"))
47550 }
47551
47552 function each$5(callback) {
47553         var cookies = doc$1.cookie.split(/; ?/g);
47554         for (var i = cookies.length - 1; i >= 0; i--) {
47555                 if (!trim$1(cookies[i])) {
47556                         continue
47557                 }
47558                 var kvp = cookies[i].split('=');
47559                 var key = unescape(kvp[0]);
47560                 var val = unescape(kvp[1]);
47561                 callback(val, key);
47562         }
47563 }
47564
47565 function write$3(key, data) {
47566         if(!key) { return }
47567         doc$1.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
47568 }
47569
47570 function remove$5(key) {
47571         if (!key || !_has(key)) {
47572                 return
47573         }
47574         doc$1.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
47575 }
47576
47577 function clearAll$3() {
47578         each$5(function(_, key) {
47579                 remove$5(key);
47580         });
47581 }
47582
47583 function _has(key) {
47584         return (new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(doc$1.cookie)
47585 }
47586
47587 var Global$5 = util.Global;
47588
47589 var sessionStorage_1 = {
47590         name: 'sessionStorage',
47591         read: read$4,
47592         write: write$4,
47593         each: each$6,
47594         remove: remove$6,
47595         clearAll: clearAll$4
47596 };
47597
47598 function sessionStorage() {
47599         return Global$5.sessionStorage
47600 }
47601
47602 function read$4(key) {
47603         return sessionStorage().getItem(key)
47604 }
47605
47606 function write$4(key, data) {
47607         return sessionStorage().setItem(key, data)
47608 }
47609
47610 function each$6(fn) {
47611         for (var i = sessionStorage().length - 1; i >= 0; i--) {
47612                 var key = sessionStorage().key(i);
47613                 fn(read$4(key), key);
47614         }
47615 }
47616
47617 function remove$6(key) {
47618         return sessionStorage().removeItem(key)
47619 }
47620
47621 function clearAll$4() {
47622         return sessionStorage().clear()
47623 }
47624
47625 // memoryStorage is a useful last fallback to ensure that the store
47626 // is functions (meaning store.get(), store.set(), etc will all function).
47627 // However, stored values will not persist when the browser navigates to
47628 // a new page or reloads the current page.
47629
47630 var memoryStorage_1 = {
47631         name: 'memoryStorage',
47632         read: read$5,
47633         write: write$5,
47634         each: each$7,
47635         remove: remove$7,
47636         clearAll: clearAll$5,
47637 };
47638
47639 var memoryStorage = {};
47640
47641 function read$5(key) {
47642         return memoryStorage[key]
47643 }
47644
47645 function write$5(key, data) {
47646         memoryStorage[key] = data;
47647 }
47648
47649 function each$7(callback) {
47650         for (var key in memoryStorage) {
47651                 if (memoryStorage.hasOwnProperty(key)) {
47652                         callback(memoryStorage[key], key);
47653                 }
47654         }
47655 }
47656
47657 function remove$7(key) {
47658         delete memoryStorage[key];
47659 }
47660
47661 function clearAll$5(key) {
47662         memoryStorage = {};
47663 }
47664
47665 var all$3 = [
47666         // Listed in order of usage preference
47667         localStorage_1,
47668         oldFFGlobalStorage,
47669         oldIEUserDataStorage,
47670         cookieStorage,
47671         sessionStorage_1,
47672         memoryStorage_1
47673 ];
47674
47675 /* eslint-disable */
47676
47677 //  json2.js
47678 //  2016-10-28
47679 //  Public Domain.
47680 //  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
47681 //  See http://www.JSON.org/js.html
47682 //  This code should be minified before deployment.
47683 //  See http://javascript.crockford.com/jsmin.html
47684
47685 //  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
47686 //  NOT CONTROL.
47687
47688 //  This file creates a global JSON object containing two methods: stringify
47689 //  and parse. This file provides the ES5 JSON capability to ES3 systems.
47690 //  If a project might run on IE8 or earlier, then this file should be included.
47691 //  This file does nothing on ES5 systems.
47692
47693 //      JSON.stringify(value, replacer, space)
47694 //          value       any JavaScript value, usually an object or array.
47695 //          replacer    an optional parameter that determines how object
47696 //                      values are stringified for objects. It can be a
47697 //                      function or an array of strings.
47698 //          space       an optional parameter that specifies the indentation
47699 //                      of nested structures. If it is omitted, the text will
47700 //                      be packed without extra whitespace. If it is a number,
47701 //                      it will specify the number of spaces to indent at each
47702 //                      level. If it is a string (such as "\t" or "&nbsp;"),
47703 //                      it contains the characters used to indent at each level.
47704 //          This method produces a JSON text from a JavaScript value.
47705 //          When an object value is found, if the object contains a toJSON
47706 //          method, its toJSON method will be called and the result will be
47707 //          stringified. A toJSON method does not serialize: it returns the
47708 //          value represented by the name/value pair that should be serialized,
47709 //          or undefined if nothing should be serialized. The toJSON method
47710 //          will be passed the key associated with the value, and this will be
47711 //          bound to the value.
47712
47713 //          For example, this would serialize Dates as ISO strings.
47714
47715 //              Date.prototype.toJSON = function (key) {
47716 //                  function f(n) {
47717 //                      // Format integers to have at least two digits.
47718 //                      return (n < 10)
47719 //                          ? "0" + n
47720 //                          : n;
47721 //                  }
47722 //                  return this.getUTCFullYear()   + "-" +
47723 //                       f(this.getUTCMonth() + 1) + "-" +
47724 //                       f(this.getUTCDate())      + "T" +
47725 //                       f(this.getUTCHours())     + ":" +
47726 //                       f(this.getUTCMinutes())   + ":" +
47727 //                       f(this.getUTCSeconds())   + "Z";
47728 //              };
47729
47730 //          You can provide an optional replacer method. It will be passed the
47731 //          key and value of each member, with this bound to the containing
47732 //          object. The value that is returned from your method will be
47733 //          serialized. If your method returns undefined, then the member will
47734 //          be excluded from the serialization.
47735
47736 //          If the replacer parameter is an array of strings, then it will be
47737 //          used to select the members to be serialized. It filters the results
47738 //          such that only members with keys listed in the replacer array are
47739 //          stringified.
47740
47741 //          Values that do not have JSON representations, such as undefined or
47742 //          functions, will not be serialized. Such values in objects will be
47743 //          dropped; in arrays they will be replaced with null. You can use
47744 //          a replacer function to replace those with JSON values.
47745
47746 //          JSON.stringify(undefined) returns undefined.
47747
47748 //          The optional space parameter produces a stringification of the
47749 //          value that is filled with line breaks and indentation to make it
47750 //          easier to read.
47751
47752 //          If the space parameter is a non-empty string, then that string will
47753 //          be used for indentation. If the space parameter is a number, then
47754 //          the indentation will be that many spaces.
47755
47756 //          Example:
47757
47758 //          text = JSON.stringify(["e", {pluribus: "unum"}]);
47759 //          // text is '["e",{"pluribus":"unum"}]'
47760
47761 //          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
47762 //          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
47763
47764 //          text = JSON.stringify([new Date()], function (key, value) {
47765 //              return this[key] instanceof Date
47766 //                  ? "Date(" + this[key] + ")"
47767 //                  : value;
47768 //          });
47769 //          // text is '["Date(---current time---)"]'
47770
47771 //      JSON.parse(text, reviver)
47772 //          This method parses a JSON text to produce an object or array.
47773 //          It can throw a SyntaxError exception.
47774
47775 //          The optional reviver parameter is a function that can filter and
47776 //          transform the results. It receives each of the keys and values,
47777 //          and its return value is used instead of the original value.
47778 //          If it returns what it received, then the structure is not modified.
47779 //          If it returns undefined then the member is deleted.
47780
47781 //          Example:
47782
47783 //          // Parse the text. Values that look like ISO date strings will
47784 //          // be converted to Date objects.
47785
47786 //          myData = JSON.parse(text, function (key, value) {
47787 //              var a;
47788 //              if (typeof value === "string") {
47789 //                  a =
47790 //   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
47791 //                  if (a) {
47792 //                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
47793 //                          +a[5], +a[6]));
47794 //                  }
47795 //              }
47796 //              return value;
47797 //          });
47798
47799 //          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
47800 //              var d;
47801 //              if (typeof value === "string" &&
47802 //                      value.slice(0, 5) === "Date(" &&
47803 //                      value.slice(-1) === ")") {
47804 //                  d = new Date(value.slice(5, -1));
47805 //                  if (d) {
47806 //                      return d;
47807 //                  }
47808 //              }
47809 //              return value;
47810 //          });
47811
47812 //  This is a reference implementation. You are free to copy, modify, or
47813 //  redistribute.
47814
47815 /*jslint
47816     eval, for, this
47817 */
47818
47819 /*property
47820     JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
47821     getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
47822     lastIndex, length, parse, prototype, push, replace, slice, stringify,
47823     test, toJSON, toString, valueOf
47824 */
47825
47826
47827 // Create a JSON object only if one does not already exist. We create the
47828 // methods in a closure to avoid creating global variables.
47829
47830 if (typeof JSON !== "object") {
47831     JSON = {};
47832 }
47833
47834 (function () {
47835     "use strict";
47836
47837     var rx_one = /^[\],:{}\s]*$/;
47838     var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
47839     var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
47840     var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
47841     var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
47842     var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
47843
47844     function f(n) {
47845         // Format integers to have at least two digits.
47846         return n < 10
47847             ? "0" + n
47848             : n;
47849     }
47850
47851     function this_value() {
47852         return this.valueOf();
47853     }
47854
47855     if (typeof Date.prototype.toJSON !== "function") {
47856
47857         Date.prototype.toJSON = function () {
47858
47859             return isFinite(this.valueOf())
47860                 ? this.getUTCFullYear() + "-" +
47861                         f(this.getUTCMonth() + 1) + "-" +
47862                         f(this.getUTCDate()) + "T" +
47863                         f(this.getUTCHours()) + ":" +
47864                         f(this.getUTCMinutes()) + ":" +
47865                         f(this.getUTCSeconds()) + "Z"
47866                 : null;
47867         };
47868
47869         Boolean.prototype.toJSON = this_value;
47870         Number.prototype.toJSON = this_value;
47871         String.prototype.toJSON = this_value;
47872     }
47873
47874     var gap;
47875     var indent;
47876     var meta;
47877     var rep;
47878
47879
47880     function quote(string) {
47881
47882 // If the string contains no control characters, no quote characters, and no
47883 // backslash characters, then we can safely slap some quotes around it.
47884 // Otherwise we must also replace the offending characters with safe escape
47885 // sequences.
47886
47887         rx_escapable.lastIndex = 0;
47888         return rx_escapable.test(string)
47889             ? "\"" + string.replace(rx_escapable, function (a) {
47890                 var c = meta[a];
47891                 return typeof c === "string"
47892                     ? c
47893                     : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
47894             }) + "\""
47895             : "\"" + string + "\"";
47896     }
47897
47898
47899     function str(key, holder) {
47900
47901 // Produce a string from holder[key].
47902
47903         var i;          // The loop counter.
47904         var k;          // The member key.
47905         var v;          // The member value.
47906         var length;
47907         var mind = gap;
47908         var partial;
47909         var value = holder[key];
47910
47911 // If the value has a toJSON method, call it to obtain a replacement value.
47912
47913         if (value && typeof value === "object" &&
47914                 typeof value.toJSON === "function") {
47915             value = value.toJSON(key);
47916         }
47917
47918 // If we were called with a replacer function, then call the replacer to
47919 // obtain a replacement value.
47920
47921         if (typeof rep === "function") {
47922             value = rep.call(holder, key, value);
47923         }
47924
47925 // What happens next depends on the value's type.
47926
47927         switch (typeof value) {
47928         case "string":
47929             return quote(value);
47930
47931         case "number":
47932
47933 // JSON numbers must be finite. Encode non-finite numbers as null.
47934
47935             return isFinite(value)
47936                 ? String(value)
47937                 : "null";
47938
47939         case "boolean":
47940         case "null":
47941
47942 // If the value is a boolean or null, convert it to a string. Note:
47943 // typeof null does not produce "null". The case is included here in
47944 // the remote chance that this gets fixed someday.
47945
47946             return String(value);
47947
47948 // If the type is "object", we might be dealing with an object or an array or
47949 // null.
47950
47951         case "object":
47952
47953 // Due to a specification blunder in ECMAScript, typeof null is "object",
47954 // so watch out for that case.
47955
47956             if (!value) {
47957                 return "null";
47958             }
47959
47960 // Make an array to hold the partial results of stringifying this object value.
47961
47962             gap += indent;
47963             partial = [];
47964
47965 // Is the value an array?
47966
47967             if (Object.prototype.toString.apply(value) === "[object Array]") {
47968
47969 // The value is an array. Stringify every element. Use null as a placeholder
47970 // for non-JSON values.
47971
47972                 length = value.length;
47973                 for (i = 0; i < length; i += 1) {
47974                     partial[i] = str(i, value) || "null";
47975                 }
47976
47977 // Join all of the elements together, separated with commas, and wrap them in
47978 // brackets.
47979
47980                 v = partial.length === 0
47981                     ? "[]"
47982                     : gap
47983                         ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]"
47984                         : "[" + partial.join(",") + "]";
47985                 gap = mind;
47986                 return v;
47987             }
47988
47989 // If the replacer is an array, use it to select the members to be stringified.
47990
47991             if (rep && typeof rep === "object") {
47992                 length = rep.length;
47993                 for (i = 0; i < length; i += 1) {
47994                     if (typeof rep[i] === "string") {
47995                         k = rep[i];
47996                         v = str(k, value);
47997                         if (v) {
47998                             partial.push(quote(k) + (
47999                                 gap
48000                                     ? ": "
48001                                     : ":"
48002                             ) + v);
48003                         }
48004                     }
48005                 }
48006             } else {
48007
48008 // Otherwise, iterate through all of the keys in the object.
48009
48010                 for (k in value) {
48011                     if (Object.prototype.hasOwnProperty.call(value, k)) {
48012                         v = str(k, value);
48013                         if (v) {
48014                             partial.push(quote(k) + (
48015                                 gap
48016                                     ? ": "
48017                                     : ":"
48018                             ) + v);
48019                         }
48020                     }
48021                 }
48022             }
48023
48024 // Join all of the member texts together, separated with commas,
48025 // and wrap them in braces.
48026
48027             v = partial.length === 0
48028                 ? "{}"
48029                 : gap
48030                     ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}"
48031                     : "{" + partial.join(",") + "}";
48032             gap = mind;
48033             return v;
48034         }
48035     }
48036
48037 // If the JSON object does not yet have a stringify method, give it one.
48038
48039     if (typeof JSON.stringify !== "function") {
48040         meta = {    // table of character substitutions
48041             "\b": "\\b",
48042             "\t": "\\t",
48043             "\n": "\\n",
48044             "\f": "\\f",
48045             "\r": "\\r",
48046             "\"": "\\\"",
48047             "\\": "\\\\"
48048         };
48049         JSON.stringify = function (value, replacer, space) {
48050
48051 // The stringify method takes a value and an optional replacer, and an optional
48052 // space parameter, and returns a JSON text. The replacer can be a function
48053 // that can replace values, or an array of strings that will select the keys.
48054 // A default replacer method can be provided. Use of the space parameter can
48055 // produce text that is more easily readable.
48056
48057             var i;
48058             gap = "";
48059             indent = "";
48060
48061 // If the space parameter is a number, make an indent string containing that
48062 // many spaces.
48063
48064             if (typeof space === "number") {
48065                 for (i = 0; i < space; i += 1) {
48066                     indent += " ";
48067                 }
48068
48069 // If the space parameter is a string, it will be used as the indent string.
48070
48071             } else if (typeof space === "string") {
48072                 indent = space;
48073             }
48074
48075 // If there is a replacer, it must be a function or an array.
48076 // Otherwise, throw an error.
48077
48078             rep = replacer;
48079             if (replacer && typeof replacer !== "function" &&
48080                     (typeof replacer !== "object" ||
48081                     typeof replacer.length !== "number")) {
48082                 throw new Error("JSON.stringify");
48083             }
48084
48085 // Make a fake root object containing our value under the key of "".
48086 // Return the result of stringifying the value.
48087
48088             return str("", {"": value});
48089         };
48090     }
48091
48092
48093 // If the JSON object does not yet have a parse method, give it one.
48094
48095     if (typeof JSON.parse !== "function") {
48096         JSON.parse = function (text, reviver) {
48097
48098 // The parse method takes a text and an optional reviver function, and returns
48099 // a JavaScript value if the text is a valid JSON text.
48100
48101             var j;
48102
48103             function walk(holder, key) {
48104
48105 // The walk method is used to recursively walk the resulting structure so
48106 // that modifications can be made.
48107
48108                 var k;
48109                 var v;
48110                 var value = holder[key];
48111                 if (value && typeof value === "object") {
48112                     for (k in value) {
48113                         if (Object.prototype.hasOwnProperty.call(value, k)) {
48114                             v = walk(value, k);
48115                             if (v !== undefined) {
48116                                 value[k] = v;
48117                             } else {
48118                                 delete value[k];
48119                             }
48120                         }
48121                     }
48122                 }
48123                 return reviver.call(holder, key, value);
48124             }
48125
48126
48127 // Parsing happens in four stages. In the first stage, we replace certain
48128 // Unicode characters with escape sequences. JavaScript handles many characters
48129 // incorrectly, either silently deleting them, or treating them as line endings.
48130
48131             text = String(text);
48132             rx_dangerous.lastIndex = 0;
48133             if (rx_dangerous.test(text)) {
48134                 text = text.replace(rx_dangerous, function (a) {
48135                     return "\\u" +
48136                             ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
48137                 });
48138             }
48139
48140 // In the second stage, we run the text against regular expressions that look
48141 // for non-JSON patterns. We are especially concerned with "()" and "new"
48142 // because they can cause invocation, and "=" because it can cause mutation.
48143 // But just to be safe, we want to reject all unexpected forms.
48144
48145 // We split the second stage into 4 regexp operations in order to work around
48146 // crippling inefficiencies in IE's and Safari's regexp engines. First we
48147 // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
48148 // replace all simple value tokens with "]" characters. Third, we delete all
48149 // open brackets that follow a colon or comma or that begin the text. Finally,
48150 // we look to see that the remaining characters are only whitespace or "]" or
48151 // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
48152
48153             if (
48154                 rx_one.test(
48155                     text
48156                         .replace(rx_two, "@")
48157                         .replace(rx_three, "]")
48158                         .replace(rx_four, "")
48159                 )
48160             ) {
48161
48162 // In the third stage we use the eval function to compile the text into a
48163 // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
48164 // in JavaScript: it can begin a block or an object literal. We wrap the text
48165 // in parens to eliminate the ambiguity.
48166
48167                 j = eval("(" + text + ")");
48168
48169 // In the optional fourth stage, we recursively walk the new structure, passing
48170 // each name/value pair to a reviver function for possible transformation.
48171
48172                 return (typeof reviver === "function")
48173                     ? walk({"": j}, "")
48174                     : j;
48175             }
48176
48177 // If the text is not JSON parseable, then a SyntaxError is thrown.
48178
48179             throw new SyntaxError("JSON.parse");
48180         };
48181     }
48182 }());
48183
48184 var json2 = json2Plugin;
48185
48186 function json2Plugin() {
48187         
48188         return {}
48189 }
48190
48191 var plugins = [json2];
48192
48193 var store_legacy = storeEngine.createStore(all$3, plugins);
48194
48195 // # osm-auth
48196 //
48197 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
48198 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
48199 // does not support custom headers, which this uses everywhere.
48200 var index$12 = function(o) {
48201
48202     var oauth = {};
48203
48204     // authenticated users will also have a request token secret, but it's
48205     // not used in transactions with the server
48206     oauth.authenticated = function() {
48207         return !!(token('oauth_token') && token('oauth_token_secret'));
48208     };
48209
48210     oauth.logout = function() {
48211         token('oauth_token', '');
48212         token('oauth_token_secret', '');
48213         token('oauth_request_token_secret', '');
48214         return oauth;
48215     };
48216
48217     // TODO: detect lack of click event
48218     oauth.authenticate = function(callback) {
48219         if (oauth.authenticated()) return callback();
48220
48221         oauth.logout();
48222
48223         // ## Getting a request token
48224         var params = timenonce(getAuth(o)),
48225             url = o.url + '/oauth/request_token';
48226
48227         params.oauth_signature = index$13.signature(
48228             o.oauth_secret, '',
48229             index$13.baseString('POST', url, params));
48230
48231         if (!o.singlepage) {
48232             // Create a 600x550 popup window in the center of the screen
48233             var w = 600, h = 550,
48234                 settings = [
48235                     ['width', w], ['height', h],
48236                     ['left', screen.width / 2 - w / 2],
48237                     ['top', screen.height / 2 - h / 2]].map(function(x) {
48238                         return x.join('=');
48239                     }).join(','),
48240                 popup = window.open('about:blank', 'oauth_window', settings);
48241         }
48242
48243         // Request a request token. When this is complete, the popup
48244         // window is redirected to OSM's authorization page.
48245         index$13.xhr('POST', url, params, null, {}, reqTokenDone);
48246         o.loading();
48247
48248         function reqTokenDone(err, xhr) {
48249             o.done();
48250             if (err) return callback(err);
48251             var resp = index$13.stringQs(xhr.response);
48252             token('oauth_request_token_secret', resp.oauth_token_secret);
48253             var authorize_url = o.url + '/oauth/authorize?' + index$13.qsString({
48254                 oauth_token: resp.oauth_token,
48255                 oauth_callback: resolveUrl(o.landing)
48256             });
48257
48258             if (o.singlepage) {
48259                 location.href = authorize_url;
48260             } else {
48261                 popup.location = authorize_url;
48262             }
48263         }
48264
48265         // Called by a function in a landing page, in the popup window. The
48266         // window closes itself.
48267         window.authComplete = function(token) {
48268             var oauth_token = index$13.stringQs(token.split('?')[1]);
48269             get_access_token(oauth_token.oauth_token);
48270             delete window.authComplete;
48271         };
48272
48273         // ## Getting an request token
48274         //
48275         // At this point we have an `oauth_token`, brought in from a function
48276         // call on a landing page popup.
48277         function get_access_token(oauth_token) {
48278             var url = o.url + '/oauth/access_token',
48279                 params = timenonce(getAuth(o)),
48280                 request_token_secret = token('oauth_request_token_secret');
48281             params.oauth_token = oauth_token;
48282             params.oauth_signature = index$13.signature(
48283                 o.oauth_secret,
48284                 request_token_secret,
48285                 index$13.baseString('POST', url, params));
48286
48287             // ## Getting an access token
48288             //
48289             // The final token required for authentication. At this point
48290             // we have a `request token secret`
48291             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
48292             o.loading();
48293         }
48294
48295         function accessTokenDone(err, xhr) {
48296             o.done();
48297             if (err) return callback(err);
48298             var access_token = index$13.stringQs(xhr.response);
48299             token('oauth_token', access_token.oauth_token);
48300             token('oauth_token_secret', access_token.oauth_token_secret);
48301             callback(null, oauth);
48302         }
48303     };
48304
48305     oauth.bootstrapToken = function(oauth_token, callback) {
48306         // ## Getting an request token
48307         // At this point we have an `oauth_token`, brought in from a function
48308         // call on a landing page popup.
48309         function get_access_token(oauth_token) {
48310             var url = o.url + '/oauth/access_token',
48311                 params = timenonce(getAuth(o)),
48312                 request_token_secret = token('oauth_request_token_secret');
48313             params.oauth_token = oauth_token;
48314             params.oauth_signature = index$13.signature(
48315                 o.oauth_secret,
48316                 request_token_secret,
48317                 index$13.baseString('POST', url, params));
48318
48319             // ## Getting an access token
48320             // The final token required for authentication. At this point
48321             // we have a `request token secret`
48322             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
48323             o.loading();
48324         }
48325
48326         function accessTokenDone(err, xhr) {
48327             o.done();
48328             if (err) return callback(err);
48329             var access_token = index$13.stringQs(xhr.response);
48330             token('oauth_token', access_token.oauth_token);
48331             token('oauth_token_secret', access_token.oauth_token_secret);
48332             callback(null, oauth);
48333         }
48334
48335         get_access_token(oauth_token);
48336     };
48337
48338     // # xhr
48339     //
48340     // A single XMLHttpRequest wrapper that does authenticated calls if the
48341     // user has logged in.
48342     oauth.xhr = function(options, callback) {
48343         if (!oauth.authenticated()) {
48344             if (o.auto) {
48345                 return oauth.authenticate(run);
48346             } else {
48347                 callback('not authenticated', null);
48348                 return;
48349             }
48350         } else {
48351             return run();
48352         }
48353
48354         function run() {
48355             var params = timenonce(getAuth(o)),
48356                 oauth_token_secret = token('oauth_token_secret'),
48357                 url = (options.prefix !== false) ? o.url + options.path : options.path,
48358                 url_parts = url.replace(/#.*$/, '').split('?', 2),
48359                 base_url = url_parts[0],
48360                 query = (url_parts.length === 2) ? url_parts[1] : '';
48361
48362             // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
48363             if ((!options.options || !options.options.header ||
48364                 options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') &&
48365                 options.content) {
48366                 params = immutable(params, index$13.stringQs(options.content));
48367             }
48368
48369             params.oauth_token = token('oauth_token');
48370             params.oauth_signature = index$13.signature(
48371                 o.oauth_secret,
48372                 oauth_token_secret,
48373                 index$13.baseString(options.method, base_url, immutable(params, index$13.stringQs(query)))
48374             );
48375
48376             return index$13.xhr(options.method, url, params, options.content, options.options, done);
48377         }
48378
48379         function done(err, xhr) {
48380             if (err) return callback(err);
48381             else if (xhr.responseXML) return callback(err, xhr.responseXML);
48382             else return callback(err, xhr.response);
48383         }
48384     };
48385
48386     // pre-authorize this object, if we can just get a token and token_secret
48387     // from the start
48388     oauth.preauth = function(c) {
48389         if (!c) return;
48390         if (c.oauth_token) token('oauth_token', c.oauth_token);
48391         if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
48392         return oauth;
48393     };
48394
48395     oauth.options = function(_) {
48396         if (!arguments.length) return o;
48397
48398         o = _;
48399         o.url = o.url || 'https://www.openstreetmap.org';
48400         o.landing = o.landing || 'land.html';
48401         o.singlepage = o.singlepage || false;
48402
48403         // Optional loading and loading-done functions for nice UI feedback.
48404         // by default, no-ops
48405         o.loading = o.loading || function() {};
48406         o.done = o.done || function() {};
48407
48408         return oauth.preauth(o);
48409     };
48410
48411     // 'stamp' an authentication object from `getAuth()`
48412     // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
48413     // and timestamp
48414     function timenonce(o) {
48415         o.oauth_timestamp = index$13.timestamp();
48416         o.oauth_nonce = index$13.nonce();
48417         return o;
48418     }
48419
48420     // get/set tokens. These are prefixed with the base URL so that `osm-auth`
48421     // can be used with multiple APIs and the keys in `localStorage`
48422     // will not clash
48423     var token;
48424
48425     if (store_legacy.enabled) {
48426         token = function (x, y) {
48427             if (arguments.length === 1) return store_legacy.get(o.url + x);
48428             else if (arguments.length === 2) return store_legacy.set(o.url + x, y);
48429         };
48430     } else {
48431         var storage = {};
48432         token = function (x, y) {
48433             if (arguments.length === 1) return storage[o.url + x];
48434             else if (arguments.length === 2) return storage[o.url + x] = y;
48435         };
48436     }
48437
48438     // Get an authentication object. If you just add and remove properties
48439     // from a single object, you'll need to use `delete` to make sure that
48440     // it doesn't contain undesired properties for authentication
48441     function getAuth(o) {
48442         return {
48443             oauth_consumer_key: o.oauth_consumer_key,
48444             oauth_signature_method: 'HMAC-SHA1'
48445         };
48446     }
48447
48448     // potentially pre-authorize
48449     oauth.options(o);
48450
48451     return oauth;
48452 };
48453
48454 var JXON = new (function () {
48455   var
48456     sValueProp = 'keyValue', sAttributesProp = 'keyAttributes', sAttrPref = '@', /* you can customize these values */
48457     aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
48458
48459   function parseText (sValue) {
48460     if (rIsNull.test(sValue)) { return null; }
48461     if (rIsBool.test(sValue)) { return sValue.toLowerCase() === 'true'; }
48462     if (isFinite(sValue)) { return parseFloat(sValue); }
48463     if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
48464     return sValue;
48465   }
48466
48467   function EmptyTree () { }
48468   EmptyTree.prototype.toString = function () { return 'null'; };
48469   EmptyTree.prototype.valueOf = function () { return null; };
48470
48471   function objectify (vValue) {
48472     return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
48473   }
48474
48475   function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) {
48476     var
48477       nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(),
48478       bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
48479
48480     var
48481       sProp, vContent, nLength = 0, sCollectedTxt = '',
48482       vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
48483
48484     if (bChildren) {
48485       for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
48486         oNode = oParentNode.childNodes.item(nItem);
48487         if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is 'CDATASection' (4) */
48488         else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is 'Text' (3) */
48489         else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is 'Element' (1) */
48490       }
48491     }
48492
48493     var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
48494
48495     if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; }
48496
48497     for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
48498       sProp = aCache[nElId].nodeName.toLowerCase();
48499       vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
48500       if (vResult.hasOwnProperty(sProp)) {
48501         if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; }
48502         vResult[sProp].push(vContent);
48503       } else {
48504         vResult[sProp] = vContent;
48505         nLength++;
48506       }
48507     }
48508
48509     if (bAttributes) {
48510       var
48511         nAttrLen = oParentNode.attributes.length,
48512         sAPrefix = bNesteAttr ? '' : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
48513
48514       for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
48515         oAttrib = oParentNode.attributes.item(nAttrib);
48516         oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
48517       }
48518
48519       if (bNesteAttr) {
48520         if (bFreeze) { Object.freeze(oAttrParent); }
48521         vResult[sAttributesProp] = oAttrParent;
48522         nLength -= nAttrLen - 1;
48523       }
48524     }
48525
48526     if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
48527       vResult[sValueProp] = vBuiltVal;
48528     } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
48529       vResult = vBuiltVal;
48530     }
48531
48532     if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); }
48533
48534     aCache.length = nLevelStart;
48535
48536     return vResult;
48537   }
48538
48539   function loadObjTree (oXMLDoc, oParentEl, oParentObj) {
48540     var vValue, oChild;
48541
48542     if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
48543       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
48544     } else if (oParentObj.constructor === Date) {
48545       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));    
48546     }
48547
48548     for (var sName in oParentObj) {
48549       vValue = oParentObj[sName];
48550       if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */
48551       if (sName === sValueProp) {
48552         if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); }
48553       } else if (sName === sAttributesProp) { /* verbosity level is 3 */
48554         for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); }
48555       } else if (sName.charAt(0) === sAttrPref) {
48556         oParentEl.setAttribute(sName.slice(1), vValue);
48557       } else if (vValue.constructor === Array) {
48558         for (var nItem = 0; nItem < vValue.length; nItem++) {
48559           oChild = oXMLDoc.createElement(sName);
48560           loadObjTree(oXMLDoc, oChild, vValue[nItem]);
48561           oParentEl.appendChild(oChild);
48562         }
48563       } else {
48564         oChild = oXMLDoc.createElement(sName);
48565         if (vValue instanceof Object) {
48566           loadObjTree(oXMLDoc, oChild, vValue);
48567         } else if (vValue !== null && vValue !== true) {
48568           oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
48569         }
48570         oParentEl.appendChild(oChild);
48571      }
48572    }
48573   }
48574
48575   this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
48576     var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 : /* put here the default verbosity level: */ 1;
48577     return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);    
48578   };
48579
48580   this.unbuild = function (oObjTree) {    
48581     var oNewDoc = document.implementation.createDocument('', '', null);
48582     loadObjTree(oNewDoc, oNewDoc, oObjTree);
48583     return oNewDoc;
48584   };
48585
48586   this.stringify = function (oObjTree) {
48587     return (new XMLSerializer()).serializeToString(JXON.unbuild(oObjTree));
48588   };
48589 })();
48590
48591 // var myObject = JXON.build(doc);
48592 // we got our javascript object! try: alert(JSON.stringify(myObject));
48593
48594 // var newDoc = JXON.unbuild(myObject);
48595 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
48596
48597 var dispatch$3 = dispatch('authLoading', 'authDone', 'change', 'loading', 'loaded');
48598 var urlroot = 'https://www.openstreetmap.org';
48599 var blacklists = ['.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*'];
48600 var inflight$1 = {};
48601 var loadedTiles = {};
48602 var tileZoom$1 = 16;
48603 var oauth = index$12({
48604         url: urlroot,
48605         oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
48606         oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
48607         loading: authLoading,
48608         done: authDone
48609     });
48610 var rateLimitError;
48611 var userChangesets;
48612 var userDetails;
48613 var off;
48614
48615
48616 function authLoading() {
48617     dispatch$3.call('authLoading');
48618 }
48619
48620
48621 function authDone() {
48622     dispatch$3.call('authDone');
48623 }
48624
48625
48626 function abortRequest$1(i) {
48627     if (i) {
48628         i.abort();
48629     }
48630 }
48631
48632
48633 function getLoc(attrs) {
48634     var lon = attrs.lon && attrs.lon.value,
48635         lat = attrs.lat && attrs.lat.value;
48636     return [parseFloat(lon), parseFloat(lat)];
48637 }
48638
48639
48640 function getNodes(obj) {
48641     var elems = obj.getElementsByTagName('nd'),
48642         nodes = new Array(elems.length);
48643     for (var i = 0, l = elems.length; i < l; i++) {
48644         nodes[i] = 'n' + elems[i].attributes.ref.value;
48645     }
48646     return nodes;
48647 }
48648
48649
48650 function getTags(obj) {
48651     var elems = obj.getElementsByTagName('tag'),
48652         tags = {};
48653     for (var i = 0, l = elems.length; i < l; i++) {
48654         var attrs = elems[i].attributes;
48655         tags[attrs.k.value] = attrs.v.value;
48656     }
48657
48658     return tags;
48659 }
48660
48661
48662 function getMembers(obj) {
48663     var elems = obj.getElementsByTagName('member'),
48664         members = new Array(elems.length);
48665     for (var i = 0, l = elems.length; i < l; i++) {
48666         var attrs = elems[i].attributes;
48667         members[i] = {
48668             id: attrs.type.value[0] + attrs.ref.value,
48669             type: attrs.type.value,
48670             role: attrs.role.value
48671         };
48672     }
48673     return members;
48674 }
48675
48676
48677 function getVisible(attrs) {
48678     return (!attrs.visible || attrs.visible.value !== 'false');
48679 }
48680
48681
48682 var parsers = {
48683     node: function nodeData(obj) {
48684         var attrs = obj.attributes;
48685         return new osmNode({
48686             id: osmEntity$$1.id.fromOSM('node', attrs.id.value),
48687             visible: getVisible(attrs),
48688             version: attrs.version.value,
48689             changeset: attrs.changeset && attrs.changeset.value,
48690             timestamp: attrs.timestamp && attrs.timestamp.value,
48691             user: attrs.user && attrs.user.value,
48692             uid: attrs.uid && attrs.uid.value,
48693             loc: getLoc(attrs),
48694             tags: getTags(obj)
48695         });
48696     },
48697
48698     way: function wayData(obj) {
48699         var attrs = obj.attributes;
48700         return new osmWay({
48701             id: osmEntity$$1.id.fromOSM('way', attrs.id.value),
48702             visible: getVisible(attrs),
48703             version: attrs.version.value,
48704             changeset: attrs.changeset && attrs.changeset.value,
48705             timestamp: attrs.timestamp && attrs.timestamp.value,
48706             user: attrs.user && attrs.user.value,
48707             uid: attrs.uid && attrs.uid.value,
48708             tags: getTags(obj),
48709             nodes: getNodes(obj),
48710         });
48711     },
48712
48713     relation: function relationData(obj) {
48714         var attrs = obj.attributes;
48715         return new osmRelation({
48716             id: osmEntity$$1.id.fromOSM('relation', attrs.id.value),
48717             visible: getVisible(attrs),
48718             version: attrs.version.value,
48719             changeset: attrs.changeset && attrs.changeset.value,
48720             timestamp: attrs.timestamp && attrs.timestamp.value,
48721             user: attrs.user && attrs.user.value,
48722             uid: attrs.uid && attrs.uid.value,
48723             tags: getTags(obj),
48724             members: getMembers(obj)
48725         });
48726     }
48727 };
48728
48729
48730 function parse$1(xml$$1) {
48731     if (!xml$$1 || !xml$$1.childNodes) return;
48732
48733     var root = xml$$1.childNodes[0],
48734         children = root.childNodes,
48735         entities = [];
48736
48737     for (var i = 0, l = children.length; i < l; i++) {
48738         var child = children[i],
48739             parser = parsers[child.nodeName];
48740         if (parser) {
48741             entities.push(parser(child));
48742         }
48743     }
48744
48745     return entities;
48746 }
48747
48748
48749 var serviceOsm = {
48750
48751     init: function() {
48752         utilRebind(this, dispatch$3, 'on');
48753     },
48754
48755
48756     reset: function() {
48757         userChangesets = undefined;
48758         userDetails = undefined;
48759         rateLimitError = undefined;
48760         lodash.forEach(inflight$1, abortRequest$1);
48761         loadedTiles = {};
48762         inflight$1 = {};
48763         return this;
48764     },
48765
48766
48767     changesetURL: function(changesetId) {
48768         return urlroot + '/changeset/' + changesetId;
48769     },
48770
48771
48772     changesetsURL: function(center, zoom$$1) {
48773         var precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2));
48774         return urlroot + '/history#map=' +
48775             Math.floor(zoom$$1) + '/' +
48776             center[1].toFixed(precision) + '/' +
48777             center[0].toFixed(precision);
48778     },
48779
48780
48781     entityURL: function(entity) {
48782         return urlroot + '/' + entity.type + '/' + entity.osmId();
48783     },
48784
48785
48786     historyURL: function(entity) {
48787         return urlroot + '/' + entity.type + '/' + entity.osmId() + '/history';
48788     },
48789
48790
48791     userURL: function(username) {
48792         return urlroot + '/user/' + username;
48793     },
48794
48795
48796     loadFromAPI: function(path$$1, callback) {
48797         var that = this;
48798
48799         function done(err, xml$$1) {
48800             var isAuthenticated = that.authenticated();
48801
48802             // 400 Bad Request, 401 Unauthorized, 403 Forbidden
48803             // Logout and retry the request..
48804             if (isAuthenticated && err &&
48805                     (err.status === 400 || err.status === 401 || err.status === 403)) {
48806                 that.logout();
48807                 that.loadFromAPI(path$$1, callback);
48808
48809             // else, no retry..
48810             } else {
48811                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
48812                 // Set the rateLimitError flag and trigger a warning..
48813                 if (!isAuthenticated && !rateLimitError && err &&
48814                         (err.status === 509 || err.status === 429)) {
48815                     rateLimitError = err;
48816                     dispatch$3.call('change');
48817                 }
48818
48819                 if (callback) {
48820                     callback(err, parse$1(xml$$1));
48821                 }
48822             }
48823         }
48824
48825         if (this.authenticated()) {
48826             return oauth.xhr({ method: 'GET', path: path$$1 }, done);
48827         } else {
48828             var url = urlroot + path$$1;
48829             return xml(url).get(done);
48830         }
48831     },
48832
48833
48834     loadEntity: function(id, callback) {
48835         var type = osmEntity$$1.id.type(id),
48836             osmID = osmEntity$$1.id.toOSM(id);
48837
48838         this.loadFromAPI(
48839             '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
48840             function(err, entities) {
48841                 if (callback) callback(err, { data: entities });
48842             }
48843         );
48844     },
48845
48846
48847     loadEntityVersion: function(id, version$$1, callback) {
48848         var type = osmEntity$$1.id.type(id),
48849             osmID = osmEntity$$1.id.toOSM(id);
48850
48851         this.loadFromAPI(
48852             '/api/0.6/' + type + '/' + osmID + '/' + version$$1,
48853             function(err, entities) {
48854                 if (callback) callback(err, { data: entities });
48855             }
48856         );
48857     },
48858
48859
48860     loadMultiple: function(ids, callback) {
48861         var that = this;
48862         lodash.each(lodash.groupBy(lodash.uniq(ids), osmEntity$$1.id.type), function(v, k) {
48863             var type = k + 's',
48864                 osmIDs = lodash.map(v, osmEntity$$1.id.toOSM);
48865
48866             lodash.each(lodash.chunk(osmIDs, 150), function(arr) {
48867                 that.loadFromAPI(
48868                     '/api/0.6/' + type + '?' + type + '=' + arr.join(),
48869                     function(err, entities) {
48870                         if (callback) callback(err, { data: entities });
48871                     }
48872                 );
48873             });
48874         });
48875     },
48876
48877
48878     authenticated: function() {
48879         return oauth.authenticated();
48880     },
48881
48882
48883     putChangeset: function(changeset, changes, callback) {
48884
48885         // Create the changeset..
48886         oauth.xhr({
48887             method: 'PUT',
48888             path: '/api/0.6/changeset/create',
48889             options: { header: { 'Content-Type': 'text/xml' } },
48890             content: JXON.stringify(changeset.asJXON())
48891         }, createdChangeset);
48892
48893
48894         function createdChangeset(err, changeset_id) {
48895             if (err) return callback(err);
48896             changeset = changeset.update({ id: changeset_id });
48897
48898             // Upload the changeset..
48899             oauth.xhr({
48900                 method: 'POST',
48901                 path: '/api/0.6/changeset/' + changeset_id + '/upload',
48902                 options: { header: { 'Content-Type': 'text/xml' } },
48903                 content: JXON.stringify(changeset.osmChangeJXON(changes))
48904             }, uploadedChangeset);
48905         }
48906
48907
48908         function uploadedChangeset(err) {
48909             if (err) return callback(err);
48910
48911             // Upload was successful, safe to call the callback.
48912             // Add delay to allow for postgres replication #1646 #2678
48913             window.setTimeout(function() {
48914                 callback(null, changeset);
48915             }, 2500);
48916
48917             // Still attempt to close changeset, but ignore response because #2667
48918             oauth.xhr({
48919                 method: 'PUT',
48920                 path: '/api/0.6/changeset/' + changeset.id + '/close',
48921                 options: { header: { 'Content-Type': 'text/xml' } }
48922             }, function() { return true; });
48923         }
48924     },
48925
48926
48927     userDetails: function(callback) {
48928         if (userDetails) {
48929             callback(undefined, userDetails);
48930             return;
48931         }
48932
48933         function done(err, user_details) {
48934             if (err) return callback(err);
48935
48936             var u = user_details.getElementsByTagName('user')[0],
48937                 img = u.getElementsByTagName('img'),
48938                 image_url = '';
48939
48940             if (img && img[0] && img[0].getAttribute('href')) {
48941                 image_url = img[0].getAttribute('href');
48942             }
48943
48944             var changesets = u.getElementsByTagName('changesets'),
48945                 changesets_count = 0;
48946
48947             if (changesets && changesets[0] && changesets[0].getAttribute('count')) {
48948                 changesets_count = changesets[0].getAttribute('count');
48949             }
48950
48951             userDetails = {
48952                 id: u.attributes.id.value,
48953                 display_name: u.attributes.display_name.value,
48954                 image_url: image_url,
48955                 changesets_count: changesets_count
48956             };
48957
48958             callback(undefined, userDetails);
48959         }
48960
48961         oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
48962     },
48963
48964
48965     userChangesets: function(callback) {
48966         if (userChangesets) {
48967             callback(undefined, userChangesets);
48968             return;
48969         }
48970
48971         this.userDetails(function(err, user) {
48972             if (err) {
48973                 callback(err);
48974                 return;
48975             }
48976
48977             function done(err, changesets) {
48978                 if (err) {
48979                     callback(err);
48980                 } else {
48981                     userChangesets = Array.prototype.map.call(
48982                         changesets.getElementsByTagName('changeset'),
48983                         function (changeset) {
48984                             return { tags: getTags(changeset) };
48985                         }
48986                     ).filter(function (changeset) {
48987                         var comment = changeset.tags.comment;
48988                         return comment && comment !== '';
48989                     });
48990                     callback(undefined, userChangesets);
48991                 }
48992             }
48993
48994             oauth.xhr({ method: 'GET', path: '/api/0.6/changesets?user=' + user.id }, done);
48995         });
48996     },
48997
48998
48999     status: function(callback) {
49000         function done(xml$$1) {
49001             // update blacklists
49002             var elements = xml$$1.getElementsByTagName('blacklist'),
49003                 regexes = [];
49004             for (var i = 0; i < elements.length; i++) {
49005                 var regex = elements[i].getAttribute('regex');  // needs unencode?
49006                 if (regex) {
49007                     regexes.push(regex);
49008                 }
49009             }
49010             if (regexes.length) {
49011                 blacklists = regexes;
49012             }
49013
49014
49015             if (rateLimitError) {
49016                 callback(rateLimitError, 'rateLimited');
49017             } else {
49018                 var apiStatus = xml$$1.getElementsByTagName('status'),
49019                     val = apiStatus[0].getAttribute('api');
49020
49021                 callback(undefined, val);
49022             }
49023         }
49024
49025         xml(urlroot + '/api/capabilities').get()
49026             .on('load', done)
49027             .on('error', callback);
49028     },
49029
49030
49031     imageryBlacklists: function() {
49032         return blacklists;
49033     },
49034
49035
49036     tileZoom: function(_) {
49037         if (!arguments.length) return tileZoom$1;
49038         tileZoom$1 = _;
49039         return this;
49040     },
49041
49042
49043     loadTiles: function(projection$$1, dimensions, callback) {
49044         if (off) return;
49045
49046         var that = this,
49047             s = projection$$1.scale() * 2 * Math.PI,
49048             z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
49049             ts = 256 * Math.pow(2, z - tileZoom$1),
49050             origin = [
49051                 s / 2 - projection$$1.translate()[0],
49052                 s / 2 - projection$$1.translate()[1]
49053             ];
49054
49055         var tiles = d3geoTile()
49056             .scaleExtent([tileZoom$1, tileZoom$1])
49057             .scale(s)
49058             .size(dimensions)
49059             .translate(projection$$1.translate())()
49060             .map(function(tile) {
49061                 var x = tile[0] * ts - origin[0],
49062                     y = tile[1] * ts - origin[1];
49063
49064                 return {
49065                     id: tile.toString(),
49066                     extent: geoExtent$$1(
49067                         projection$$1.invert([x, y + ts]),
49068                         projection$$1.invert([x + ts, y]))
49069                 };
49070             });
49071
49072         lodash.filter(inflight$1, function(v, i) {
49073             var wanted = lodash.find(tiles, function(tile) {
49074                 return i === tile.id;
49075             });
49076             if (!wanted) delete inflight$1[i];
49077             return !wanted;
49078         }).map(abortRequest$1);
49079
49080         tiles.forEach(function(tile) {
49081             var id = tile.id;
49082
49083             if (loadedTiles[id] || inflight$1[id]) return;
49084
49085             if (lodash.isEmpty(inflight$1)) {
49086                 dispatch$3.call('loading');
49087             }
49088
49089             inflight$1[id] = that.loadFromAPI(
49090                 '/api/0.6/map?bbox=' + tile.extent.toParam(),
49091                 function(err, parsed) {
49092                     delete inflight$1[id];
49093                     if (!err) {
49094                         loadedTiles[id] = true;
49095                     }
49096
49097                     if (callback) {
49098                         callback(err, lodash.extend({ data: parsed }, tile));
49099                     }
49100
49101                     if (lodash.isEmpty(inflight$1)) {
49102                         dispatch$3.call('loaded');
49103                     }
49104                 }
49105             );
49106         });
49107     },
49108
49109
49110     switch: function(options) {
49111         urlroot = options.urlroot;
49112
49113         oauth.options(lodash.extend({
49114             url: urlroot,
49115             loading: authLoading,
49116             done: authDone
49117         }, options));
49118
49119         dispatch$3.call('change');
49120         this.reset();
49121         this.userChangesets(function() {});  // eagerly load user details/changesets
49122         return this;
49123     },
49124
49125
49126     toggle: function(_) {
49127         off = !_;
49128         return this;
49129     },
49130
49131
49132     loadedTiles: function(_) {
49133         if (!arguments.length) return loadedTiles;
49134         loadedTiles = _;
49135         return this;
49136     },
49137
49138
49139     logout: function() {
49140         userChangesets = undefined;
49141         userDetails = undefined;
49142         oauth.logout();
49143         dispatch$3.call('change');
49144         return this;
49145     },
49146
49147
49148     authenticate: function(callback) {
49149         var that = this;
49150         userChangesets = undefined;
49151         userDetails = undefined;
49152
49153         function done(err, res) {
49154             rateLimitError = undefined;
49155             dispatch$3.call('change');
49156             if (callback) callback(err, res);
49157             that.userChangesets(function() {});  // eagerly load user details/changesets
49158         }
49159
49160         return oauth.authenticate(done);
49161     }
49162 };
49163
49164 var apibase$2 = 'https://taginfo.openstreetmap.org/api/4/';
49165 var inflight$2 = {};
49166 var popularKeys = {};
49167 var taginfoCache = {};
49168 var tag_sorts = {
49169         point: 'count_nodes',
49170         vertex: 'count_nodes',
49171         area: 'count_ways',
49172         line: 'count_ways'
49173     };
49174 var tag_sort_members = {
49175         point: 'count_node_members',
49176         vertex: 'count_node_members',
49177         area: 'count_way_members',
49178         line: 'count_way_members',
49179         relation: 'count_relation_members'
49180     };
49181 var tag_filters = {
49182         point: 'nodes',
49183         vertex: 'nodes',
49184         area: 'ways',
49185         line: 'ways'
49186     };
49187 var tag_members_fractions = {
49188         point: 'count_node_members_fraction',
49189         vertex: 'count_node_members_fraction',
49190         area: 'count_way_members_fraction',
49191         line: 'count_way_members_fraction',
49192         relation: 'count_relation_members_fraction'
49193     };
49194
49195
49196 function sets(params, n, o) {
49197     if (params.geometry && o[params.geometry]) {
49198         params[n] = o[params.geometry];
49199     }
49200     return params;
49201 }
49202
49203
49204 function setFilter(params) {
49205     return sets(params, 'filter', tag_filters);
49206 }
49207
49208
49209 function setSort(params) {
49210     return sets(params, 'sortname', tag_sorts);
49211 }
49212
49213
49214 function setSortMembers(params) {
49215     return sets(params, 'sortname', tag_sort_members);
49216 }
49217
49218
49219 function clean(params) {
49220     return lodash.omit(params, ['geometry', 'debounce']);
49221 }
49222
49223
49224 function filterKeys(type) {
49225     var count_type = type ? 'count_' + type : 'count_all';
49226     return function(d) {
49227         return parseFloat(d[count_type]) > 2500 || d.in_wiki;
49228     };
49229 }
49230
49231
49232 function filterMultikeys(prefix) {
49233     return function(d) {
49234         // d.key begins with prefix, and d.key contains no additional ':'s
49235         var re = new RegExp('^' + prefix + '(.*)$');
49236         var matches = d.key.match(re) || [];
49237         return (matches.length === 2 && matches[1].indexOf(':') === -1);
49238     };
49239 }
49240
49241
49242 function filterValues(allowUpperCase) {
49243     return function(d) {
49244         if (d.value.match(/[;,]/) !== null) return false;  // exclude some punctuation
49245         if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false;  // exclude uppercase letters
49246         return parseFloat(d.fraction) > 0.0 || d.in_wiki;
49247     };
49248 }
49249
49250
49251 function filterRoles(geometry) {
49252     return function(d) {
49253         if (d.role === '') return false; // exclude empty role
49254         if (d.role.match(/[A-Z*;,]/) !== null) return false;  // exclude uppercase letters and some punctuation
49255         return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
49256     };
49257 }
49258
49259
49260 function valKey(d) {
49261     return {
49262         value: d.key,
49263         title: d.key
49264     };
49265 }
49266
49267
49268 function valKeyDescription(d) {
49269     return {
49270         value: d.value,
49271         title: d.description || d.value
49272     };
49273 }
49274
49275
49276 function roleKey(d) {
49277     return {
49278         value: d.role,
49279         title: d.role
49280     };
49281 }
49282
49283
49284 // sort keys with ':' lower than keys without ':'
49285 function sortKeys(a, b) {
49286     return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
49287         : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
49288         : 0;
49289 }
49290
49291
49292 var debouncedRequest = lodash.debounce(request$1, 500, { leading: false });
49293
49294 function request$1(url, params, exactMatch, callback, loaded) {
49295     if (inflight$2[url]) return;
49296
49297     if (checkCache(url, params, exactMatch, callback)) return;
49298
49299     inflight$2[url] = json(url, function (err, data) {
49300         delete inflight$2[url];
49301         loaded(err, data);
49302     });
49303 }
49304
49305
49306 function checkCache(url, params, exactMatch, callback) {
49307     var rp = params.rp || 25,
49308         testQuery = params.query || '',
49309         testUrl = url;
49310
49311     do {
49312         var hit = taginfoCache[testUrl];
49313
49314         // exact match, or shorter match yielding fewer than max results (rp)
49315         if (hit && (url === testUrl || hit.length < rp)) {
49316             callback(null, hit);
49317             return true;
49318         }
49319
49320         // don't try to shorten the query
49321         if (exactMatch || !testQuery.length) return false;
49322
49323         // do shorten the query to see if we already have a cached result
49324         // that has returned fewer than max results (rp)
49325         testQuery = testQuery.slice(0, -1);
49326         testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
49327     } while (testQuery.length >= 0);
49328
49329     return false;
49330 }
49331
49332
49333 var serviceTaginfo = {
49334
49335     init: function() {
49336         inflight$2 = {};
49337         taginfoCache = {};
49338         popularKeys = {};
49339
49340         // Fetch popular keys.  We'll exclude these from `values`
49341         // lookups because they stress taginfo, and they aren't likely
49342         // to yield meaningful autocomplete results.. see #3955
49343         var params = { rp: 100, sortname: 'values_all', sortorder: 'desc', page: 1, debounce: false };
49344         this.keys(params, function(err, data) {
49345             if (err) return;
49346             data.forEach(function(d) {
49347                 if (d.value === 'opening_hours') return;  // exception
49348                 popularKeys[d.value] = true;
49349             });
49350         });
49351     },
49352
49353
49354     reset: function() {
49355         lodash.forEach(inflight$2, function(req) { req.abort(); });
49356         inflight$2 = {};
49357     },
49358
49359
49360     keys: function(params, callback) {
49361         var doRequest = params.debounce ? debouncedRequest : request$1;
49362         params = clean(setSort(params));
49363         params = lodash.extend({ rp: 10, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
49364
49365         var url = apibase$2 + 'keys/all?' + utilQsString(params);
49366         doRequest(url, params, false, callback, function(err, d) {
49367             if (err) {
49368                 callback(err);
49369             } else {
49370                 var f = filterKeys(params.filter);
49371                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
49372                 taginfoCache[url] = result;
49373                 callback(null, result);
49374             }
49375         });
49376     },
49377
49378
49379     multikeys: function(params, callback) {
49380         var doRequest = params.debounce ? debouncedRequest : request$1;
49381         params = clean(setSort(params));
49382         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
49383         var prefix = params.query;
49384
49385         var url = apibase$2 + 'keys/all?' + utilQsString(params);
49386         doRequest(url, params, true, callback, function(err, d) {
49387             if (err) {
49388                 callback(err);
49389             } else {
49390                 var f = filterMultikeys(prefix);
49391                 var result = d.data.filter(f).map(valKey);
49392                 taginfoCache[url] = result;
49393                 callback(null, result);
49394             }
49395         });
49396     },
49397
49398
49399     values: function(params, callback) {
49400         // Exclude popular keys from values lookups.. see #3955
49401         var key = params.key;
49402         if (key && popularKeys[key]) {
49403             callback(null, []);
49404             return;
49405         }
49406
49407         var doRequest = params.debounce ? debouncedRequest : request$1;
49408         params = clean(setSort(setFilter(params)));
49409         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
49410
49411         var url = apibase$2 + 'key/values?' + utilQsString(params);
49412         doRequest(url, params, false, callback, function(err, d) {
49413             if (err) {
49414                 callback(err);
49415             } else {
49416                 // In most cases we prefer taginfo value results with lowercase letters.
49417                 // A few OSM keys expect values to contain uppercase values (see #3377).
49418                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
49419                 // but these are the fields where taginfo value lookup is most useful.
49420                 var re = /network|taxon|genus|species|brand|grape_variety|_hours|_times/;
49421                 var allowUpperCase = (params.key.match(re) !== null);
49422                 var f = filterValues(allowUpperCase);
49423
49424                 var result = d.data.filter(f).map(valKeyDescription);
49425                 taginfoCache[url] = result;
49426                 callback(null, result);
49427             }
49428         });
49429     },
49430
49431
49432     roles: function(params, callback) {
49433         var doRequest = params.debounce ? debouncedRequest : request$1;
49434         var geometry = params.geometry;
49435         params = clean(setSortMembers(params));
49436         params = lodash.extend({ rp: 25, sortname: 'count_all_members', sortorder: 'desc', page: 1 }, params);
49437
49438         var url = apibase$2 + 'relation/roles?' + utilQsString(params);
49439         doRequest(url, params, true, callback, function(err, d) {
49440             if (err) {
49441                 callback(err);
49442             } else {
49443                 var f = filterRoles(geometry);
49444                 var result = d.data.filter(f).map(roleKey);
49445                 taginfoCache[url] = result;
49446                 callback(null, result);
49447             }
49448         });
49449     },
49450
49451
49452     docs: function(params, callback) {
49453         var doRequest = params.debounce ? debouncedRequest : request$1;
49454         params = clean(setSort(params));
49455
49456         var path$$1 = 'key/wiki_pages?';
49457         if (params.value) path$$1 = 'tag/wiki_pages?';
49458         else if (params.rtype) path$$1 = 'relation/wiki_pages?';
49459
49460         var url = apibase$2 + path$$1 + utilQsString(params);
49461         doRequest(url, params, true, callback, function(err, d) {
49462             if (err) {
49463                 callback(err);
49464             } else {
49465                 taginfoCache[url] = d.data;
49466                 callback(null, d.data);
49467             }
49468         });
49469     },
49470
49471
49472     apibase: function(_) {
49473         if (!arguments.length) return apibase$2;
49474         apibase$2 = _;
49475         return this;
49476     }
49477
49478 };
49479
49480 var jsonpCache = {};
49481 window.jsonpCache = jsonpCache;
49482
49483 function jsonpRequest(url, callback) {
49484
49485   if (window.JSONP_FIX) {
49486     if (window.JSONP_DELAY === 0) {
49487       callback(window.JSONP_FIX);
49488     } else {
49489       setTimeout(function() {
49490         callback(window.JSONP_FIX);
49491       }, window.JSONP_DELAY || 0);
49492     }
49493     return;
49494   }
49495
49496   function rand() {
49497     var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
49498       c = '', i = -1;
49499     while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
49500     return c;
49501   }
49502
49503   function create(url) {
49504     var e = url.match(/callback=(\w+)/),
49505       c = e ? e[1] : rand();
49506     jsonpCache[c] = function(data) {
49507       callback(data);
49508       delete jsonpCache[c];
49509       script.remove();
49510     };
49511     return 'jsonpCache.' + c;
49512   }
49513
49514   var cb = create(url),
49515     script = select('head')
49516     .append('script')
49517     .attr('type', 'text/javascript')
49518     .attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
49519 }
49520
49521 var endpoint = 'https://www.wikidata.org/w/api.php?';
49522
49523 var serviceWikidata = {
49524
49525     init: function() {},
49526     reset: function() {},
49527
49528
49529     // Given a Wikipedia language and article title, return an array of
49530     // corresponding Wikidata entities.
49531     itemsByTitle: function(lang, title, callback) {
49532         if (!title) {
49533             callback('', {});
49534             return;
49535         }
49536
49537         lang = lang || 'en';
49538         jsonpRequest(endpoint + utilQsString({
49539             action: 'wbgetentities',
49540             format: 'json',
49541             sites: lang.replace(/-/g, '_') + 'wiki',
49542             titles: title,
49543             languages: 'en', // shrink response by filtering to one language
49544             callback: '{callback}'
49545         }), function(data) {
49546             if (!data || data.error) {
49547                 callback('', {});
49548             } else {
49549                 callback(title, data.entities || {});
49550             }
49551         });
49552     }
49553
49554 };
49555
49556 var endpoint$1 = 'https://en.wikipedia.org/w/api.php?';
49557
49558 var serviceWikipedia = {
49559
49560     init: function() {},
49561     reset: function() {},
49562
49563
49564     search: function(lang, query, callback) {
49565         if (!query) {
49566             callback('', []);
49567             return;
49568         }
49569
49570         lang = lang || 'en';
49571         jsonpRequest(endpoint$1.replace('en', lang) +
49572             utilQsString({
49573                 action: 'query',
49574                 list: 'search',
49575                 srlimit: '10',
49576                 srinfo: 'suggestion',
49577                 format: 'json',
49578                 callback: '{callback}',
49579                 srsearch: query
49580             }), function(data) {
49581                 if (!data || !data.query || !data.query.search || data.error) {
49582                     callback('', []);
49583                 } else {
49584                     var results = data.query.search.map(function(d) { return d.title; });
49585                     callback(query, results);
49586                 }
49587             }
49588         );
49589     },
49590
49591
49592     suggestions: function(lang, query, callback) {
49593         if (!query) {
49594             callback('', []);
49595             return;
49596         }
49597
49598         lang = lang || 'en';
49599         jsonpRequest(endpoint$1.replace('en', lang) +
49600             utilQsString({
49601                 action: 'opensearch',
49602                 namespace: 0,
49603                 suggest: '',
49604                 format: 'json',
49605                 callback: '{callback}',
49606                 search: query
49607             }), function(data) {
49608                 if (!data || data.error) {
49609                     callback('', []);
49610                 } else {
49611                     callback(data[0], data[1] || []);
49612                 }
49613             }
49614         );
49615     },
49616
49617
49618     translations: function(lang, title, callback) {
49619         if (!title) {
49620             callback({});
49621             return;
49622         }
49623
49624         jsonpRequest(endpoint$1.replace('en', lang) +
49625             utilQsString({
49626                 action: 'query',
49627                 prop: 'langlinks',
49628                 format: 'json',
49629                 callback: '{callback}',
49630                 lllimit: 500,
49631                 titles: title
49632             }), function(data) {
49633                 if (!data || !data.query || !data.query.pages || data.error) {
49634                     callback({});
49635                 } else {
49636                     var list = data.query.pages[Object.keys(data.query.pages)[0]],
49637                         translations = {};
49638                     if (list && list.langlinks) {
49639                         list.langlinks.forEach(function(d) {
49640                             translations[d.lang] = d['*'];
49641                         });
49642                     }
49643                     callback(translations);
49644                 }
49645             }
49646         );
49647     }
49648
49649 };
49650
49651 var services = {
49652     mapillary: serviceMapillary,
49653     geocoder: serviceNominatim,
49654     osm: serviceOsm,
49655     taginfo: serviceTaginfo,
49656     wikidata: serviceWikidata,
49657     wikipedia: serviceWikipedia
49658 };
49659
49660 function svgMapillaryImages(projection$$1, context, dispatch$$1) {
49661     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
49662         minZoom = 12,
49663         minViewfieldZoom = 17,
49664         layer = select(null),
49665         _mapillary;
49666
49667
49668     function init() {
49669         if (svgMapillaryImages.initialized) return;  // run once
49670         svgMapillaryImages.enabled = false;
49671         svgMapillaryImages.initialized = true;
49672     }
49673
49674
49675     function getMapillary() {
49676         if (services.mapillary && !_mapillary) {
49677             _mapillary = services.mapillary;
49678             _mapillary.event.on('loadedImages', throttledRedraw);
49679         } else if (!services.mapillary && _mapillary) {
49680             _mapillary = null;
49681         }
49682
49683         return _mapillary;
49684     }
49685
49686
49687     function showLayer() {
49688         var mapillary = getMapillary();
49689         if (!mapillary) return;
49690
49691         mapillary.loadViewer(context);
49692         editOn();
49693
49694         layer
49695             .style('opacity', 0)
49696             .transition()
49697             .duration(500)
49698             .style('opacity', 1)
49699             .on('end', function () { dispatch$$1.call('change'); });
49700     }
49701
49702
49703     function hideLayer() {
49704         var mapillary = getMapillary();
49705         if (mapillary) {
49706             mapillary.hideViewer();
49707         }
49708
49709         throttledRedraw.cancel();
49710
49711         layer
49712             .transition()
49713             .duration(500)
49714             .style('opacity', 0)
49715             .on('end', editOff);
49716     }
49717
49718
49719     function editOn() {
49720         layer.style('display', 'block');
49721     }
49722
49723
49724     function editOff() {
49725         layer.selectAll('.viewfield-group').remove();
49726         layer.style('display', 'none');
49727     }
49728
49729
49730     function click(d) {
49731         var mapillary = getMapillary();
49732         if (!mapillary) return;
49733
49734         context.map().centerEase(d.loc);
49735
49736         mapillary
49737             .selectedImage(d.key, true)
49738             .updateViewer(d.key, context)
49739             .showViewer();
49740     }
49741
49742
49743     function transform$$1(d) {
49744         var t = svgPointTransform(projection$$1)(d);
49745         if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
49746         return t;
49747     }
49748
49749
49750     function update() {
49751         var mapillary = getMapillary(),
49752             data = (mapillary ? mapillary.images(projection$$1) : []),
49753             imageKey = mapillary ? mapillary.selectedImage() : null;
49754
49755         var markers = layer.selectAll('.viewfield-group')
49756             .data(data, function(d) { return d.key; });
49757
49758         markers.exit()
49759             .remove();
49760
49761         var enter = markers.enter()
49762             .append('g')
49763             .attr('class', 'viewfield-group')
49764             .classed('selected', function(d) { return d.key === imageKey; })
49765             .on('click', click);
49766
49767         markers = markers
49768             .merge(enter)
49769             .attr('transform', transform$$1);
49770
49771
49772        var viewfields = markers.selectAll('.viewfield')
49773             .data(~~context.map().zoom() >= minViewfieldZoom ? [0] : []);
49774
49775         viewfields.exit()
49776             .remove();
49777
49778         viewfields.enter()
49779             .append('path')
49780             .attr('class', 'viewfield')
49781             .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
49782             .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');
49783
49784         markers.selectAll('circle')
49785             .data([0])
49786             .enter()
49787             .append('circle')
49788             .attr('dx', '0')
49789             .attr('dy', '0')
49790             .attr('r', '6');
49791     }
49792
49793
49794     function drawImages(selection$$1) {
49795         var enabled = svgMapillaryImages.enabled,
49796             mapillary = getMapillary();
49797
49798         layer = selection$$1.selectAll('.layer-mapillary-images')
49799             .data(mapillary ? [0] : []);
49800
49801         layer.exit()
49802             .remove();
49803
49804         layer = layer.enter()
49805             .append('g')
49806             .attr('class', 'layer-mapillary-images')
49807             .style('display', enabled ? 'block' : 'none')
49808             .merge(layer);
49809
49810         if (enabled) {
49811             if (mapillary && ~~context.map().zoom() >= minZoom) {
49812                 editOn();
49813                 update();
49814                 mapillary.loadImages(projection$$1);
49815             } else {
49816                 editOff();
49817             }
49818         }
49819     }
49820
49821
49822     drawImages.enabled = function(_) {
49823         if (!arguments.length) return svgMapillaryImages.enabled;
49824         svgMapillaryImages.enabled = _;
49825         if (svgMapillaryImages.enabled) {
49826             showLayer();
49827         } else {
49828             hideLayer();
49829         }
49830         dispatch$$1.call('change');
49831         return this;
49832     };
49833
49834
49835     drawImages.supported = function() {
49836         return !!getMapillary();
49837     };
49838
49839
49840     init();
49841     return drawImages;
49842 }
49843
49844 function svgMapillarySigns(projection$$1, context, dispatch$$1) {
49845     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
49846         minZoom = 12,
49847         layer = select(null),
49848         _mapillary;
49849
49850
49851     function init() {
49852         if (svgMapillarySigns.initialized) return;  // run once
49853         svgMapillarySigns.enabled = false;
49854         svgMapillarySigns.initialized = true;
49855     }
49856
49857
49858     function getMapillary() {
49859         if (services.mapillary && !_mapillary) {
49860             _mapillary = services.mapillary;
49861             _mapillary.event.on('loadedSigns', throttledRedraw);
49862         } else if (!services.mapillary && _mapillary) {
49863             _mapillary = null;
49864         }
49865         return _mapillary;
49866     }
49867
49868
49869     function showLayer() {
49870         editOn();
49871     }
49872
49873
49874     function hideLayer() {
49875         throttledRedraw.cancel();
49876         editOff();
49877     }
49878
49879
49880     function editOn() {
49881         layer.style('display', 'block');
49882     }
49883
49884
49885     function editOff() {
49886         layer.selectAll('.icon-sign').remove();
49887         layer.style('display', 'none');
49888     }
49889
49890
49891     function click(d) {
49892         var mapillary = getMapillary();
49893         if (!mapillary) return;
49894
49895         context.map().centerEase(d.loc);
49896
49897         var selected = mapillary.selectedImage(),
49898             imageKey;
49899
49900         // Pick one of the images the sign was detected in,
49901         // preference given to an image already selected.
49902         d.detections.forEach(function(detection) {
49903             if (!imageKey || selected === detection.image_key) {
49904                 imageKey = detection.image_key;
49905             }
49906         });
49907
49908         mapillary
49909             .selectedImage(imageKey, true)
49910             .updateViewer(imageKey, context)
49911             .showViewer();
49912     }
49913
49914
49915     function update() {
49916         var mapillary = getMapillary(),
49917             data = (mapillary ? mapillary.signs(projection$$1) : []),
49918             imageKey = mapillary ? mapillary.selectedImage() : null;
49919
49920         var signs = layer.selectAll('.icon-sign')
49921             .data(data, function(d) { return d.key; });
49922
49923         signs.exit()
49924             .remove();
49925
49926         var enter = signs.enter()
49927             .append('foreignObject')
49928             .attr('class', 'icon-sign')
49929             .attr('width', '24px')      // for Firefox
49930             .attr('height', '24px')     // for Firefox
49931             .classed('selected', function(d) {
49932                 return lodash.some(d.detections, function(detection) {
49933                     return detection.image_key === imageKey;
49934                 });
49935             })
49936             .on('click', click);
49937
49938         enter
49939             .append('xhtml:body')
49940             .attr('class', 'icon-sign-body')
49941             .html(mapillary.signHTML);
49942
49943         signs
49944             .merge(enter)
49945             .attr('x', function(d) { return projection$$1(d.loc)[0] - 12; })   // offset by -12px to
49946             .attr('y', function(d) { return projection$$1(d.loc)[1] - 12; });  // center signs on loc
49947     }
49948
49949
49950     function drawSigns(selection$$1) {
49951         var enabled = svgMapillarySigns.enabled,
49952             mapillary = getMapillary();
49953
49954         layer = selection$$1.selectAll('.layer-mapillary-signs')
49955             .data(mapillary ? [0] : []);
49956
49957         layer.exit()
49958             .remove();
49959
49960         layer = layer.enter()
49961             .append('g')
49962             .attr('class', 'layer-mapillary-signs')
49963             .style('display', enabled ? 'block' : 'none')
49964             .merge(layer);
49965
49966         if (enabled) {
49967             if (mapillary && ~~context.map().zoom() >= minZoom) {
49968                 editOn();
49969                 update();
49970                 mapillary.loadSigns(context, projection$$1);
49971             } else {
49972                 editOff();
49973             }
49974         }
49975     }
49976
49977
49978     drawSigns.enabled = function(_) {
49979         if (!arguments.length) return svgMapillarySigns.enabled;
49980         svgMapillarySigns.enabled = _;
49981         if (svgMapillarySigns.enabled) {
49982             showLayer();
49983         } else {
49984             hideLayer();
49985         }
49986         dispatch$$1.call('change');
49987         return this;
49988     };
49989
49990
49991     drawSigns.supported = function() {
49992         var mapillary = getMapillary();
49993         return (mapillary && mapillary.signsSupported());
49994     };
49995
49996
49997     init();
49998     return drawSigns;
49999 }
50000
50001 function svgOsm() {
50002     return function drawOsm(selection) {
50003         var layers = selection.selectAll('.layer-osm')
50004             .data(['areas', 'lines', 'hit', 'halo', 'label']);
50005
50006         layers.enter()
50007             .append('g')
50008             .attr('class', function(d) { return 'layer-osm layer-' + d; });
50009     };
50010 }
50011
50012 function svgLayers(projection$$1, context) {
50013     var dispatch$$1 = dispatch('change'),
50014         svg = select(null),
50015         layers = [
50016             { id: 'osm', layer: svgOsm(projection$$1, context, dispatch$$1) },
50017             { id: 'gpx', layer: svgGpx(projection$$1, context, dispatch$$1) },
50018             { id: 'mapillary-images', layer: svgMapillaryImages(projection$$1, context, dispatch$$1) },
50019             { id: 'mapillary-signs',  layer: svgMapillarySigns(projection$$1, context, dispatch$$1) },
50020             { id: 'debug', layer: svgDebug(projection$$1, context, dispatch$$1) }
50021         ];
50022
50023
50024     function drawLayers(selection$$1) {
50025         svg = selection$$1.selectAll('.surface')
50026             .data([0]);
50027
50028         svg = svg.enter()
50029             .append('svg')
50030             .attr('class', 'surface')
50031             .merge(svg);
50032
50033         var defs = svg.selectAll('.surface-defs')
50034             .data([0]);
50035
50036         defs.enter()
50037             .append('defs')
50038             .attr('class', 'surface-defs');
50039
50040         var groups = svg.selectAll('.data-layer')
50041             .data(layers);
50042
50043         groups.exit()
50044             .remove();
50045
50046         groups.enter()
50047             .append('g')
50048             .attr('class', function(d) { return 'data-layer data-layer-' + d.id; })
50049             .merge(groups)
50050             .each(function(d) { select(this).call(d.layer); });
50051     }
50052
50053
50054     drawLayers.all = function() {
50055         return layers;
50056     };
50057
50058
50059     drawLayers.layer = function(id) {
50060         var obj = lodash.find(layers, function(o) {return o.id === id;});
50061         return obj && obj.layer;
50062     };
50063
50064
50065     drawLayers.only = function(what) {
50066         var arr = [].concat(what);
50067         drawLayers.remove(lodash.difference(lodash.map(layers, 'id'), arr));
50068         return this;
50069     };
50070
50071
50072     drawLayers.remove = function(what) {
50073         var arr = [].concat(what);
50074         arr.forEach(function(id) {
50075             layers = lodash.reject(layers, function(o) {return o.id === id;});
50076         });
50077         dispatch$$1.call('change');
50078         return this;
50079     };
50080
50081
50082     drawLayers.add = function(what) {
50083         var arr = [].concat(what);
50084         arr.forEach(function(obj) {
50085             if ('id' in obj && 'layer' in obj) {
50086                 layers.push(obj);
50087             }
50088         });
50089         dispatch$$1.call('change');
50090         return this;
50091     };
50092
50093
50094     drawLayers.dimensions = function(_) {
50095         if (!arguments.length) return utilGetDimensions(svg);
50096         utilSetDimensions(svg, _);
50097         return this;
50098     };
50099
50100
50101     return utilRebind(drawLayers, dispatch$$1, 'on');
50102 }
50103
50104 function svgLines$$1(projection$$1, context) {
50105     var detected = utilDetect();
50106
50107     var highway_stack = {
50108         motorway: 0,
50109         motorway_link: 1,
50110         trunk: 2,
50111         trunk_link: 3,
50112         primary: 4,
50113         primary_link: 5,
50114         secondary: 6,
50115         tertiary: 7,
50116         unclassified: 8,
50117         residential: 9,
50118         service: 10,
50119         footway: 11
50120     };
50121
50122
50123     function drawLines(selection$$1, graph, entities, filter) {
50124
50125
50126         function waystack(a, b) {
50127             var selected = context.selectedIDs(),
50128                 scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0,
50129                 scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
50130
50131             if (a.tags.highway) { scoreA -= highway_stack[a.tags.highway]; }
50132             if (b.tags.highway) { scoreB -= highway_stack[b.tags.highway]; }
50133             return scoreA - scoreB;
50134         }
50135
50136
50137         function drawLineGroup(selection$$1, klass, isSelected) {
50138             var lines = selection$$1
50139                 .selectAll('path')
50140                 .filter(filter)
50141                 .data(getPathData(isSelected), osmEntity$$1.key);
50142
50143             lines.exit()
50144                 .remove();
50145
50146             // Optimization: call simple TagClasses only on enter selection. This
50147             // works because osmEntity.key is defined to include the entity v attribute.
50148             lines.enter()
50149                 .append('path')
50150                 .attr('class', function(d) {
50151                     return 'way line ' + klass + ' ' + d.id + (isSelected ? ' selected' : '') +
50152                         (oldMultiPolygonOuters[d.id] ? ' old-multipolygon' : '');
50153                 })
50154                 .call(svgTagClasses())
50155                 .merge(lines)
50156                 .sort(waystack)
50157                 .attr('d', getPath)
50158                 .call(svgTagClasses().tags(svgRelationMemberTags(graph)));
50159
50160             return selection$$1;
50161         }
50162
50163
50164         function getPathData(isSelected) {
50165             return function() {
50166                 var layer = this.parentNode.__data__;
50167                 var data = pathdata[layer] || [];
50168                 return data.filter(function(d) {
50169                     if (isSelected)
50170                         return context.selectedIDs().indexOf(d.id) !== -1;
50171                     else
50172                         return context.selectedIDs().indexOf(d.id) === -1;
50173                 });
50174             };
50175         }
50176
50177
50178         var getPath = svgPath(projection$$1, graph),
50179             ways = [],
50180             pathdata = {},
50181             onewaydata = {},
50182             oldMultiPolygonOuters = {};
50183
50184         for (var i = 0; i < entities.length; i++) {
50185             var entity = entities[i],
50186                 outer = osmSimpleMultipolygonOuterMember(entity, graph);
50187             if (outer) {
50188                 ways.push(entity.mergeTags(outer.tags));
50189                 oldMultiPolygonOuters[outer.id] = true;
50190             } else if (entity.geometry(graph) === 'line') {
50191                 ways.push(entity);
50192             }
50193         }
50194
50195         ways = ways.filter(getPath);
50196         pathdata = lodash.groupBy(ways, function(way) { return way.layer(); });
50197
50198         lodash.forOwn(pathdata, function(v, k) {
50199             onewaydata[k] = lodash(v)
50200                 .filter(function(d) { return d.isOneWay(); })
50201                 .map(svgOneWaySegments(projection$$1, graph, 35))
50202                 .flatten()
50203                 .valueOf();
50204         });
50205
50206
50207         var layer = selection$$1.selectAll('.layer-lines');
50208
50209         var layergroup = layer
50210             .selectAll('g.layergroup')
50211             .data(sequence(-10, 11));
50212
50213         layergroup = layergroup.enter()
50214             .append('g')
50215             .attr('class', function(d) { return 'layergroup layer' + String(d); })
50216             .merge(layergroup);
50217
50218         layergroup
50219             .selectAll('g.linegroup')
50220             .data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted'])
50221             .enter()
50222             .append('g')
50223             .attr('class', function(d) { return 'linegroup line-' + d; });
50224
50225
50226         layergroup.selectAll('g.line-shadow')
50227             .call(drawLineGroup, 'shadow', false);
50228         layergroup.selectAll('g.line-casing')
50229             .call(drawLineGroup, 'casing', false);
50230         layergroup.selectAll('g.line-stroke')
50231             .call(drawLineGroup, 'stroke', false);
50232
50233         layergroup.selectAll('g.line-shadow-highlighted')
50234             .call(drawLineGroup, 'shadow', true);
50235         layergroup.selectAll('g.line-casing-highlighted')
50236             .call(drawLineGroup, 'casing', true);
50237         layergroup.selectAll('g.line-stroke-highlighted')
50238             .call(drawLineGroup, 'stroke', true);
50239
50240
50241         var onewaygroup = layergroup
50242             .selectAll('g.onewaygroup')
50243             .data(['oneway']);
50244
50245         onewaygroup = onewaygroup.enter()
50246             .append('g')
50247             .attr('class', 'onewaygroup')
50248             .merge(onewaygroup);
50249
50250         var oneways = onewaygroup
50251             .selectAll('path')
50252             .filter(filter)
50253             .data(
50254                 function() { return onewaydata[this.parentNode.__data__] || []; },
50255                 function(d) { return [d.id, d.index]; }
50256             );
50257
50258         oneways.exit()
50259             .remove();
50260
50261         oneways = oneways.enter()
50262             .append('path')
50263             .attr('class', 'oneway')
50264             .attr('marker-mid', 'url(#oneway-marker)')
50265             .merge(oneways)
50266             .attr('d', function(d) { return d.d; });
50267
50268         if (detected.ie) {
50269             oneways.each(function() { this.parentNode.insertBefore(this, this); });
50270         }
50271     }
50272
50273
50274     return drawLines;
50275 }
50276
50277 function svgMidpoints$$1(projection, context) {
50278
50279     return function drawMidpoints(selection, graph, entities, filter, extent) {
50280         var layer = selection.selectAll('.layer-hit');
50281
50282         var mode = context.mode();
50283         if (mode && mode.id !== 'select') {
50284             layer.selectAll('g.midpoint').remove();
50285             return;
50286         }
50287
50288         var poly = extent.polygon(),
50289             midpoints = {};
50290
50291         for (var i = 0; i < entities.length; i++) {
50292             var entity = entities[i];
50293
50294             if (entity.type !== 'way')
50295                 continue;
50296             if (!filter(entity))
50297                 continue;
50298             if (context.selectedIDs().indexOf(entity.id) < 0)
50299                 continue;
50300
50301             var nodes = graph.childNodes(entity);
50302             for (var j = 0; j < nodes.length - 1; j++) {
50303
50304                 var a = nodes[j],
50305                     b = nodes[j + 1],
50306                     id = [a.id, b.id].sort().join('-');
50307
50308                 if (midpoints[id]) {
50309                     midpoints[id].parents.push(entity);
50310                 } else {
50311                     if (geoEuclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
50312                         var point = geoInterp(a.loc, b.loc, 0.5),
50313                             loc = null;
50314
50315                         if (extent.intersects(point)) {
50316                             loc = point;
50317                         } else {
50318                             for (var k = 0; k < 4; k++) {
50319                                 point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
50320                                 if (point &&
50321                                     geoEuclideanDistance(projection(a.loc), projection(point)) > 20 &&
50322                                     geoEuclideanDistance(projection(b.loc), projection(point)) > 20)
50323                                 {
50324                                     loc = point;
50325                                     break;
50326                                 }
50327                             }
50328                         }
50329
50330                         if (loc) {
50331                             midpoints[id] = {
50332                                 type: 'midpoint',
50333                                 id: id,
50334                                 loc: loc,
50335                                 edge: [a.id, b.id],
50336                                 parents: [entity]
50337                             };
50338                         }
50339                     }
50340                 }
50341             }
50342         }
50343
50344
50345         function midpointFilter(d) {
50346             if (midpoints[d.id])
50347                 return true;
50348
50349             for (var i = 0; i < d.parents.length; i++) {
50350                 if (filter(d.parents[i])) {
50351                     return true;
50352                 }
50353             }
50354
50355             return false;
50356         }
50357
50358
50359         var groups = layer
50360             .selectAll('g.midpoint')
50361             .filter(midpointFilter)
50362             .data(lodash.values(midpoints), function(d) { return d.id; });
50363
50364         groups.exit()
50365             .remove();
50366
50367         var enter = groups.enter()
50368             .insert('g', ':first-child')
50369             .attr('class', 'midpoint');
50370
50371         enter.append('polygon')
50372             .attr('points', '-6,8 10,0 -6,-8')
50373             .attr('class', 'shadow');
50374
50375         enter.append('polygon')
50376             .attr('points', '-3,4 5,0 -3,-4')
50377             .attr('class', 'fill');
50378
50379         groups = groups
50380             .merge(enter)
50381             .attr('transform', function(d) {
50382                 var translate = svgPointTransform(projection),
50383                     a = graph.entity(d.edge[0]),
50384                     b = graph.entity(d.edge[1]),
50385                     angleVal = Math.round(geoAngle(a, b, projection) * (180 / Math.PI));
50386                 return translate(d) + ' rotate(' + angleVal + ')';
50387             })
50388             .call(svgTagClasses().tags(
50389                 function(d) { return d.parents[0].tags; }
50390             ));
50391
50392         // Propagate data bindings.
50393         groups.select('polygon.shadow');
50394         groups.select('polygon.fill');
50395
50396     };
50397 }
50398
50399 function svgOneWaySegments(projection$$1, graph, dt) {
50400     return function(entity) {
50401         var a,
50402             b,
50403             i = 0,
50404             offset = dt,
50405             segments = [],
50406             clip = identity$5().clipExtent(projection$$1.clipExtent()).stream,
50407             coordinates = graph.childNodes(entity).map(function(n) {
50408                 return n.loc;
50409             });
50410
50411         if (entity.tags.oneway === '-1') coordinates.reverse();
50412
50413         geoStream({
50414             type: 'LineString',
50415             coordinates: coordinates
50416         }, projection$$1.stream(clip({
50417             lineStart: function() {},
50418             lineEnd: function() {
50419                 a = null;
50420             },
50421             point: function(x, y) {
50422                 b = [x, y];
50423
50424                 if (a) {
50425                     var span = geoEuclideanDistance(a, b) - offset;
50426
50427                     if (span >= 0) {
50428                         var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
50429                             dx = dt * Math.cos(angle),
50430                             dy = dt * Math.sin(angle),
50431                             p = [a[0] + offset * Math.cos(angle),
50432                                  a[1] + offset * Math.sin(angle)];
50433
50434                         var segment = 'M' + a[0] + ',' + a[1] +
50435                                       'L' + p[0] + ',' + p[1];
50436
50437                         for (span -= dt; span >= 0; span -= dt) {
50438                             p[0] += dx;
50439                             p[1] += dy;
50440                             segment += 'L' + p[0] + ',' + p[1];
50441                         }
50442
50443                         segment += 'L' + b[0] + ',' + b[1];
50444                         segments.push({id: entity.id, index: i, d: segment});
50445                     }
50446
50447                     offset = -span;
50448                     i++;
50449                 }
50450
50451                 a = b;
50452             }
50453         })));
50454
50455         return segments;
50456     };
50457 }
50458
50459 function svgPath(projection$$1, graph, isArea) {
50460
50461     // Explanation of magic numbers:
50462     // "padding" here allows space for strokes to extend beyond the viewport,
50463     // so that the stroke isn't drawn along the edge of the viewport when
50464     // the shape is clipped.
50465     //
50466     // When drawing lines, pad viewport by 5px.
50467     // When drawing areas, pad viewport by 65px in each direction to allow
50468     // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
50469
50470     var cache = {},
50471         padding = isArea ? 65 : 5,
50472         viewport = projection$$1.clipExtent(),
50473         paddedExtent = [
50474             [viewport[0][0] - padding, viewport[0][1] - padding],
50475             [viewport[1][0] + padding, viewport[1][1] + padding]
50476         ],
50477         clip = identity$5().clipExtent(paddedExtent).stream,
50478         project = projection$$1.stream,
50479         path$$1 = index$4()
50480             .projection({stream: function(output) { return project(clip(output)); }});
50481
50482     return function(entity) {
50483         if (entity.id in cache) {
50484             return cache[entity.id];
50485         } else {
50486             return cache[entity.id] = path$$1(entity.asGeoJSON(graph));
50487         }
50488     };
50489 }
50490
50491 function svgPoints$$1(projection, context) {
50492
50493     function markerPath(selection, klass) {
50494         selection
50495             .attr('class', klass)
50496             .attr('transform', 'translate(-8, -23)')
50497             .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');
50498     }
50499
50500     function sortY(a, b) {
50501         return b.loc[1] - a.loc[1];
50502     }
50503
50504
50505     return function drawPoints(selection, graph, entities, filter) {
50506         var wireframe = context.surface().classed('fill-wireframe'),
50507             points = wireframe ? [] : lodash.filter(entities, function(e) {
50508                 return e.geometry(graph) === 'point';
50509             });
50510
50511         points.sort(sortY);
50512
50513         var layer = selection.selectAll('.layer-hit');
50514
50515         var groups = layer.selectAll('g.point')
50516             .filter(filter)
50517             .data(points, osmEntity$$1.key);
50518
50519         groups.exit()
50520             .remove();
50521
50522         var enter = groups.enter()
50523             .append('g')
50524             .attr('class', function(d) { return 'node point ' + d.id; })
50525             .order();
50526
50527         enter.append('path')
50528             .call(markerPath, 'shadow');
50529
50530         enter.append('ellipse')
50531             .attr('cx', 0.5)
50532             .attr('cy', 1)
50533             .attr('rx', 6.5)
50534             .attr('ry', 3)
50535             .attr('class', 'stroke');
50536
50537         enter.append('path')
50538             .call(markerPath, 'stroke');
50539
50540         enter.append('use')
50541             .attr('transform', 'translate(-5, -19)')
50542             .attr('class', 'icon')
50543             .attr('width', '11px')
50544             .attr('height', '11px');
50545
50546         groups = groups
50547             .merge(enter)
50548             .attr('transform', svgPointTransform(projection))
50549             .call(svgTagClasses());
50550
50551         // Selecting the following implicitly
50552         // sets the data (point entity) on the element
50553         groups.select('.shadow');
50554         groups.select('.stroke');
50555         groups.select('.icon')
50556             .attr('xlink:href', function(entity) {
50557                 var preset = context.presets().match(entity, graph),
50558                     picon = preset && preset.icon;
50559
50560                 if (!picon)
50561                     return '';
50562                 else {
50563                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
50564                     return '#' + picon + (isMaki ? '-11' : '');
50565                 }
50566             });
50567     };
50568 }
50569
50570 function svgRelationMemberTags(graph) {
50571     return function(entity) {
50572         var tags = entity.tags;
50573         graph.parentRelations(entity).forEach(function(relation) {
50574             var type = relation.tags.type;
50575             if (type === 'multipolygon' || type === 'boundary') {
50576                 tags = lodash.extend({}, relation.tags, tags);
50577             }
50578         });
50579         return tags;
50580     };
50581 }
50582
50583 function svgTagClasses() {
50584     var primaries = [
50585             'building', 'highway', 'railway', 'waterway', 'aeroway',
50586             'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
50587             'leisure', 'military', 'place'
50588         ],
50589         statuses = [
50590             'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
50591             'razed', 'demolished', 'obliterated'
50592         ],
50593         secondaries = [
50594             'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
50595             'surface', 'tracktype', 'crossing', 'service', 'sport'
50596         ],
50597         tagClassRe = /^tag-/,
50598         tags = function(entity) { return entity.tags; };
50599
50600
50601     var tagClasses = function(selection$$1) {
50602         selection$$1.each(function tagClassesEach(entity) {
50603             var value = this.className,
50604                 classes, primary, status;
50605
50606             if (value.baseVal !== undefined) value = value.baseVal;
50607
50608             classes = value.trim().split(/\s+/).filter(function(name) {
50609                 return name.length && !tagClassRe.test(name);
50610             }).join(' ');
50611
50612             var t = tags(entity), i, k, v;
50613
50614             // pick at most one primary classification tag..
50615             for (i = 0; i < primaries.length; i++) {
50616                 k = primaries[i];
50617                 v = t[k];
50618                 if (!v || v === 'no') continue;
50619
50620                 primary = k;
50621                 if (statuses.indexOf(v) !== -1) {   // e.g. `railway=abandoned`
50622                     status = v;
50623                     classes += ' tag-' + k;
50624                 } else {
50625                     classes += ' tag-' + k + ' tag-' + k + '-' + v;
50626                 }
50627
50628                 break;
50629             }
50630
50631             // add at most one status tag, only if relates to primary tag..
50632             if (!status) {
50633                 for (i = 0; i < statuses.length; i++) {
50634                     k = statuses[i];
50635                     v = t[k];
50636                     if (!v || v === 'no') continue;
50637
50638                     if (v === 'yes') {   // e.g. `railway=rail + abandoned=yes`
50639                         status = k;
50640                     }
50641                     else if (primary && primary === v) {  // e.g. `railway=rail + abandoned=railway`
50642                         status = k;
50643                     } else if (!primary && primaries.indexOf(v) !== -1) {  // e.g. `abandoned=railway`
50644                         status = k;
50645                         primary = v;
50646                         classes += ' tag-' + v;
50647                     }  // else ignore e.g.  `highway=path + abandoned=railway`
50648
50649                     if (status) break;
50650                 }
50651             }
50652
50653             if (status) {
50654                 classes += ' tag-status tag-status-' + status;
50655             }
50656
50657             // add any secondary (structure) tags
50658             for (i = 0; i < secondaries.length; i++) {
50659                 k = secondaries[i];
50660                 v = t[k];
50661                 if (!v || v === 'no') continue;
50662                 classes += ' tag-' + k + ' tag-' + k + '-' + v;
50663             }
50664
50665             // For highways, look for surface tagging..
50666             if (primary === 'highway') {
50667                 var paved = (t.highway !== 'track');
50668                 for (k in t) {
50669                     v = t[k];
50670                     if (k in osmPavedTags) {
50671                         paved = !!osmPavedTags[k][v];
50672                         break;
50673                     }
50674                 }
50675                 if (!paved) {
50676                     classes += ' tag-unpaved';
50677                 }
50678             }
50679
50680             classes = classes.trim();
50681
50682             if (classes !== value) {
50683                 select(this).attr('class', classes);
50684             }
50685         });
50686     };
50687
50688
50689     tagClasses.tags = function(_) {
50690         if (!arguments.length) return tags;
50691         tags = _;
50692         return tagClasses;
50693     };
50694
50695     return tagClasses;
50696 }
50697
50698 function svgTurns(projection) {
50699
50700     return function drawTurns(selection, graph, turns) {
50701
50702         function key(turn) {
50703             return [turn.from.node + turn.via.node + turn.to.node].join('-');
50704         }
50705
50706         function icon(turn) {
50707             var u = turn.u ? '-u' : '';
50708             if (!turn.restriction)
50709                 return '#turn-yes' + u;
50710             var restriction = graph.entity(turn.restriction).tags.restriction;
50711             return '#turn-' +
50712                 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
50713         }
50714
50715         var groups = selection.selectAll('.layer-hit').selectAll('g.turn')
50716             .data(turns, key);
50717
50718         groups.exit()
50719             .remove();
50720
50721
50722         var enter = groups.enter()
50723             .append('g')
50724             .attr('class', 'turn');
50725
50726         var nEnter = enter
50727             .filter(function (turn) { return !turn.u; });
50728
50729         nEnter.append('rect')
50730             .attr('transform', 'translate(-22, -12)')
50731             .attr('width', '44')
50732             .attr('height', '24');
50733
50734         nEnter.append('use')
50735             .attr('transform', 'translate(-22, -12)')
50736             .attr('width', '44')
50737             .attr('height', '24');
50738
50739
50740         var uEnter = enter
50741             .filter(function (turn) { return turn.u; });
50742
50743         uEnter.append('circle')
50744             .attr('r', '16');
50745
50746         uEnter.append('use')
50747             .attr('transform', 'translate(-16, -16)')
50748             .attr('width', '32')
50749             .attr('height', '32');
50750
50751
50752         groups = groups
50753             .merge(enter);
50754
50755         groups
50756             .attr('transform', function (turn) {
50757                 var v = graph.entity(turn.via.node),
50758                     t = graph.entity(turn.to.node),
50759                     a = geoAngle(v, t, projection),
50760                     p = projection(v.loc),
50761                     r = turn.u ? 0 : 60;
50762
50763                 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
50764                     'rotate(' + a * 180 / Math.PI + ')';
50765             });
50766
50767         groups.select('use')
50768             .attr('xlink:href', icon);
50769
50770         groups.select('rect');
50771         groups.select('circle');
50772
50773         return this;
50774     };
50775 }
50776
50777 function svgVertices$$1(projection$$1, context) {
50778     var radiuses = {
50779         //       z16-, z17, z18+, tagged
50780         shadow: [6,    7.5,   7.5,  11.5],
50781         stroke: [2.5,  3.5,   3.5,  7],
50782         fill:   [1,    1.5,   1.5,  1.5]
50783     };
50784
50785     var hover;
50786
50787
50788     function siblingAndChildVertices(ids, graph, extent$$1) {
50789         var vertices = {};
50790
50791         function addChildVertices(entity) {
50792             if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
50793                 var i;
50794                 if (entity.type === 'way') {
50795                     for (i = 0; i < entity.nodes.length; i++) {
50796                         addChildVertices(graph.entity(entity.nodes[i]));
50797                     }
50798                 } else if (entity.type === 'relation') {
50799                     for (i = 0; i < entity.members.length; i++) {
50800                         var member = context.hasEntity(entity.members[i].id);
50801                         if (member) {
50802                             addChildVertices(member);
50803                         }
50804                     }
50805                 } else if (entity.intersects(extent$$1, graph)) {
50806                     vertices[entity.id] = entity;
50807                 }
50808             }
50809         }
50810
50811         ids.forEach(function(id) {
50812             var entity = context.hasEntity(id);
50813             if (entity && entity.type === 'node') {
50814                 vertices[entity.id] = entity;
50815                 context.graph().parentWays(entity).forEach(function(entity) {
50816                     addChildVertices(entity);
50817                 });
50818             } else if (entity) {
50819                 addChildVertices(entity);
50820             }
50821         });
50822
50823         return vertices;
50824     }
50825
50826
50827     function draw(selection$$1, vertices, klass, graph, zoom$$1, siblings$$1) {
50828
50829         function icon(entity) {
50830             if (entity.id in icons) return icons[entity.id];
50831             icons[entity.id] =
50832                 entity.hasInterestingTags() &&
50833                 context.presets().match(entity, graph).icon;
50834             return icons[entity.id];
50835         }
50836
50837         function setClass(klass) {
50838             return function(entity) {
50839                 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
50840             };
50841         }
50842
50843         function setAttributes(selection$$1) {
50844             ['shadow','stroke','fill'].forEach(function(klass) {
50845                 var rads = radiuses[klass];
50846                 selection$$1.selectAll('.' + klass)
50847                     .each(function(entity) {
50848                         var i = z && icon(entity),
50849                             c = i ? 0.5 : 0,
50850                             r = rads[i ? 3 : z];
50851
50852                         // slightly increase the size of unconnected endpoints #3775
50853                         if (entity.isEndpoint(graph) && !entity.isConnected(graph)) {
50854                             r += 1.5;
50855                         }
50856
50857                         this.setAttribute('cx', c);
50858                         this.setAttribute('cy', -c);
50859                         this.setAttribute('r', r);
50860                         if (i && klass === 'fill') {
50861                             this.setAttribute('visibility', 'hidden');
50862                         } else {
50863                             this.removeAttribute('visibility');
50864                         }
50865                     });
50866             });
50867
50868             selection$$1.selectAll('use')
50869                 .each(function() {
50870                     if (z) {
50871                         this.removeAttribute('visibility');
50872                     } else {
50873                         this.setAttribute('visibility', 'hidden');
50874                     }
50875                 });
50876         }
50877
50878
50879         siblings$$1 = siblings$$1 || {};
50880
50881         var icons = {},
50882             z = (zoom$$1 < 17 ? 0 : zoom$$1 < 18 ? 1 : 2);
50883
50884         var groups = selection$$1
50885             .data(vertices, osmEntity$$1.key);
50886
50887         groups.exit()
50888             .remove();
50889
50890         var enter = groups.enter()
50891             .append('g')
50892             .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
50893
50894         enter.append('circle')
50895             .each(setClass('shadow'));
50896
50897         enter.append('circle')
50898             .each(setClass('stroke'));
50899
50900         // Vertices with icons get a `use`.
50901         enter.filter(function(d) { return icon(d); })
50902             .append('use')
50903             .attr('transform', 'translate(-5, -6)')
50904             .attr('xlink:href', function(d) {
50905                 var picon = icon(d),
50906                     isMaki = dataFeatureIcons.indexOf(picon) !== -1;
50907                 return '#' + picon + (isMaki ? '-11' : '');
50908             })
50909             .attr('width', '11px')
50910             .attr('height', '11px')
50911             .each(setClass('icon'));
50912
50913         // Vertices with tags get a fill.
50914         enter.filter(function(d) { return d.hasInterestingTags(); })
50915             .append('circle')
50916             .each(setClass('fill'));
50917
50918         groups
50919             .merge(enter)
50920             .attr('transform', svgPointTransform(projection$$1))
50921             .classed('sibling', function(entity) { return entity.id in siblings$$1; })
50922             .classed('shared', function(entity) { return graph.isShared(entity); })
50923             .classed('endpoint', function(entity) { return entity.isEndpoint(graph); })
50924             .call(setAttributes);
50925     }
50926
50927
50928     function drawVertices(selection$$1, graph, entities, filter, extent$$1, zoom$$1) {
50929         var siblings$$1 = siblingAndChildVertices(context.selectedIDs(), graph, extent$$1),
50930             wireframe = context.surface().classed('fill-wireframe'),
50931             vertices = [];
50932
50933         for (var i = 0; i < entities.length; i++) {
50934             var entity = entities[i],
50935                 geometry = entity.geometry(graph);
50936
50937             if (wireframe && geometry === 'point') {
50938                 vertices.push(entity);
50939                 continue;
50940             }
50941
50942             if (geometry !== 'vertex')
50943                 continue;
50944
50945             if (entity.id in siblings$$1 ||
50946                 entity.hasInterestingTags() ||
50947                 entity.isEndpoint(graph) ||
50948                 entity.isConnected(graph)) {
50949                 vertices.push(entity);
50950             }
50951         }
50952
50953         var layer = selection$$1.selectAll('.layer-hit');
50954         layer.selectAll('g.vertex.vertex-persistent')
50955             .filter(filter)
50956             .call(draw, vertices, 'vertex-persistent', graph, zoom$$1, siblings$$1);
50957
50958         drawHover(selection$$1, graph, extent$$1, zoom$$1);
50959     }
50960
50961
50962     function drawHover(selection$$1, graph, extent$$1, zoom$$1) {
50963         var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent$$1) : {};
50964         var layer = selection$$1.selectAll('.layer-hit');
50965
50966         layer.selectAll('g.vertex.vertex-hover')
50967             .call(draw, values(hovered), 'vertex-hover', graph, zoom$$1);
50968     }
50969
50970
50971     drawVertices.drawHover = function(selection$$1, graph, target, extent$$1, zoom$$1) {
50972         if (target === hover) return;
50973         hover = target;
50974         drawHover(selection$$1, graph, extent$$1, zoom$$1);
50975     };
50976
50977     return drawVertices;
50978 }
50979
50980 function behaviorEdit(context) {
50981
50982     function edit() {
50983         context.map()
50984             .minzoom(context.minEditableZoom());
50985     }
50986
50987
50988     edit.off = function() {
50989         context.map()
50990             .minzoom(0);
50991     };
50992
50993
50994     return edit;
50995 }
50996
50997 /*
50998    The hover behavior adds the `.hover` class on mouseover to all elements to which
50999    the identical datum is bound, and removes it on mouseout.
51000
51001    The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
51002    representation may consist of several elements scattered throughout the DOM hierarchy.
51003    Only one of these elements can have the :hover pseudo-class, but all of them will
51004    have the .hover class.
51005  */
51006 function behaviorHover(context) {
51007     var dispatch$$1 = dispatch('hover'),
51008         _selection = select(null),
51009         newId = null,
51010         buttonDown,
51011         altDisables,
51012         target;
51013
51014
51015     function keydown() {
51016         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
51017             _selection.selectAll('.hover')
51018                 .classed('hover-suppressed', true)
51019                 .classed('hover', false);
51020
51021             _selection
51022                 .classed('hover-disabled', true);
51023
51024             dispatch$$1.call('hover', this, null);
51025         }
51026     }
51027
51028
51029     function keyup() {
51030         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
51031             _selection.selectAll('.hover-suppressed')
51032                 .classed('hover-suppressed', false)
51033                 .classed('hover', true);
51034
51035             _selection
51036                 .classed('hover-disabled', false);
51037
51038             dispatch$$1.call('hover', this, target ? target.id : null);
51039         }
51040     }
51041
51042
51043     var hover = function(selection$$1) {
51044         _selection = selection$$1;
51045         newId = null;
51046
51047         _selection
51048             .on('mouseover.hover', mouseover)
51049             .on('mouseout.hover', mouseout)
51050             .on('mousedown.hover', mousedown);
51051
51052         select(window)
51053             .on('keydown.hover', keydown)
51054             .on('keyup.hover', keyup);
51055
51056
51057         function mouseover() {
51058             if (buttonDown) return;
51059             var target = event.target;
51060             enter(target ? target.__data__ : null);
51061         }
51062
51063
51064         function mouseout() {
51065             if (buttonDown) return;
51066             var target = event.relatedTarget;
51067             enter(target ? target.__data__ : null);
51068         }
51069
51070
51071         function mousedown() {
51072             buttonDown = true;
51073             select(window)
51074                 .on('mouseup.hover', mouseup, true);
51075         }
51076
51077
51078         function mouseup() {
51079             buttonDown = false;
51080             select(window)
51081                 .on('mouseup.hover', null, true);
51082         }
51083
51084
51085         function enter(d) {
51086             if (d === target) return;
51087             target = d;
51088
51089             _selection.selectAll('.hover')
51090                 .classed('hover', false);
51091             _selection.selectAll('.hover-suppressed')
51092                 .classed('hover-suppressed', false);
51093
51094             if (target instanceof osmEntity$$1 && target.id !== newId) {
51095
51096                 // If drawing a way, don't hover on a node that was just placed. #3974
51097                 var mode = context.mode() && context.mode().id;
51098                 if ((mode === 'draw-line' || mode === 'draw-area') && !newId && target.type === 'node') {
51099                     newId = target.id;
51100                     return;
51101                 }
51102
51103                 var selector$$1 = '.' + target.id;
51104
51105                 if (target.type === 'relation') {
51106                     target.members.forEach(function(member) {
51107                         selector$$1 += ', .' + member.id;
51108                     });
51109                 }
51110
51111                 var suppressed = altDisables && event && event.altKey;
51112
51113                 _selection.selectAll(selector$$1)
51114                     .classed(suppressed ? 'hover-suppressed' : 'hover', true);
51115
51116                 dispatch$$1.call('hover', this, !suppressed && target.id);
51117
51118             } else {
51119                 dispatch$$1.call('hover', this, null);
51120             }
51121         }
51122
51123     };
51124
51125
51126     hover.off = function(selection$$1) {
51127         selection$$1.selectAll('.hover')
51128             .classed('hover', false);
51129         selection$$1.selectAll('.hover-suppressed')
51130             .classed('hover-suppressed', false);
51131         selection$$1
51132             .classed('hover-disabled', false);
51133
51134
51135         selection$$1
51136             .on('mouseover.hover', null)
51137             .on('mouseout.hover', null)
51138             .on('mousedown.hover', null);
51139
51140         select(window)
51141             .on('keydown.hover', null)
51142             .on('keyup.hover', null);
51143     };
51144
51145
51146     hover.altDisables = function(_) {
51147         if (!arguments.length) return altDisables;
51148         altDisables = _;
51149         return hover;
51150     };
51151
51152
51153     return utilRebind(hover, dispatch$$1, 'on');
51154 }
51155
51156 function behaviorTail() {
51157     var text$$1,
51158         container,
51159         xmargin = 25,
51160         tooltipSize = [0, 0],
51161         selectionSize = [0, 0];
51162
51163
51164     function tail(selection$$1) {
51165         if (!text$$1) return;
51166
51167         select(window)
51168             .on('resize.tail', function() { selectionSize = utilGetDimensions(selection$$1); });
51169
51170         container = select(document.body)
51171             .append('div')
51172             .style('display', 'none')
51173             .attr('class', 'tail tooltip-inner');
51174
51175         container.append('div')
51176             .text(text$$1);
51177
51178         selection$$1
51179             .on('mousemove.tail', mousemove)
51180             .on('mouseenter.tail', mouseenter)
51181             .on('mouseleave.tail', mouseleave);
51182
51183         container
51184             .on('mousemove.tail', mousemove);
51185
51186         tooltipSize = utilGetDimensions(container);
51187         selectionSize = utilGetDimensions(selection$$1);
51188
51189
51190         function show() {
51191             container.style('display', 'block');
51192             tooltipSize = utilGetDimensions(container);
51193         }
51194
51195
51196         function mousemove() {
51197             if (container.style('display') === 'none') show();
51198             var xoffset = ((event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
51199                 -tooltipSize[0] - xmargin : xmargin;
51200             container.classed('left', xoffset > 0);
51201             utilSetTransform(container, event.clientX + xoffset, event.clientY);
51202         }
51203
51204
51205         function mouseleave() {
51206             if (event.relatedTarget !== container.node()) {
51207                 container.style('display', 'none');
51208             }
51209         }
51210
51211
51212         function mouseenter() {
51213             if (event.relatedTarget !== container.node()) {
51214                 show();
51215             }
51216         }
51217     }
51218
51219
51220     tail.off = function(selection$$1) {
51221         if (!text$$1) return;
51222
51223         container
51224             .on('mousemove.tail', null)
51225             .remove();
51226
51227         selection$$1
51228             .on('mousemove.tail', null)
51229             .on('mouseenter.tail', null)
51230             .on('mouseleave.tail', null);
51231
51232         select(window)
51233             .on('resize.tail', null);
51234     };
51235
51236
51237     tail.text = function(_) {
51238         if (!arguments.length) return text$$1;
51239         text$$1 = _;
51240         return tail;
51241     };
51242
51243
51244     return tail;
51245 }
51246
51247 var usedTails = {};
51248 var disableSpace = false;
51249 var lastSpace = null;
51250
51251
51252 function behaviorDraw(context) {
51253     var dispatch$$1 = dispatch('move', 'click', 'clickWay',
51254             'clickNode', 'undo', 'cancel', 'finish'),
51255         keybinding = d3keybinding('draw'),
51256         hover = behaviorHover(context)
51257             .altDisables(true)
51258             .on('hover', context.ui().sidebar.hover),
51259         tail = behaviorTail(),
51260         edit = behaviorEdit(context),
51261         closeTolerance = 4,
51262         tolerance = 12,
51263         mouseLeave = false,
51264         lastMouse = null;
51265
51266
51267     function datum() {
51268         if (event.altKey) return {};
51269
51270         if (event.type === 'keydown') {
51271             return (lastMouse && lastMouse.target.__data__) || {};
51272         } else {
51273             return event.target.__data__ || {};
51274         }
51275     }
51276
51277
51278     function mousedown() {
51279
51280         function point() {
51281             var p = context.container().node();
51282             return touchId !== null ? touches(p).filter(function(p) {
51283                 return p.identifier === touchId;
51284             })[0] : mouse(p);
51285         }
51286
51287         var element = select(this),
51288             touchId = event.touches ? event.changedTouches[0].identifier : null,
51289             t1 = +new Date(),
51290             p1 = point();
51291
51292         element.on('mousemove.draw', null);
51293
51294         select(window).on('mouseup.draw', function() {
51295             var t2 = +new Date(),
51296                 p2 = point(),
51297                 dist = geoEuclideanDistance(p1, p2);
51298
51299             element.on('mousemove.draw', mousemove);
51300             select(window).on('mouseup.draw', null);
51301
51302             if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
51303                 // Prevent a quick second click
51304                 select(window).on('click.draw-block', function() {
51305                     event.stopPropagation();
51306                 }, true);
51307
51308                 context.map().dblclickEnable(false);
51309
51310                 window.setTimeout(function() {
51311                     context.map().dblclickEnable(true);
51312                     select(window).on('click.draw-block', null);
51313                 }, 500);
51314
51315                 click();
51316             }
51317         }, true);
51318     }
51319
51320
51321     function mousemove() {
51322         lastMouse = event;
51323         dispatch$$1.call('move', this, datum());
51324     }
51325
51326
51327     function mouseenter() {
51328         mouseLeave = false;
51329     }
51330
51331
51332     function mouseleave() {
51333         mouseLeave = true;
51334     }
51335
51336
51337     function click() {
51338         var d = datum();
51339         if (d.type === 'way') {
51340             var dims = context.map().dimensions(),
51341                 mouse$$1 = context.mouse(),
51342                 pad = 5,
51343                 trySnap = mouse$$1[0] > pad && mouse$$1[0] < dims[0] - pad &&
51344                     mouse$$1[1] > pad && mouse$$1[1] < dims[1] - pad;
51345
51346             if (trySnap) {
51347                 var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection),
51348                     edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
51349                 dispatch$$1.call('clickWay', this, choice.loc, edge);
51350             } else {
51351                 dispatch$$1.call('click', this, context.map().mouseCoordinates());
51352             }
51353
51354         } else if (d.type === 'node') {
51355             dispatch$$1.call('clickNode', this, d);
51356
51357         } else {
51358             dispatch$$1.call('click', this, context.map().mouseCoordinates());
51359         }
51360     }
51361
51362
51363     function space() {
51364         event.preventDefault();
51365         event.stopPropagation();
51366
51367         var currSpace = context.mouse();
51368         if (disableSpace && lastSpace) {
51369             var dist = geoEuclideanDistance(lastSpace, currSpace);
51370             if (dist > tolerance) {
51371                 disableSpace = false;
51372             }
51373         }
51374
51375         if (disableSpace || mouseLeave || !lastMouse) return;
51376
51377         // user must move mouse or release space bar to allow another click
51378         lastSpace = currSpace;
51379         disableSpace = true;
51380
51381         select(window).on('keyup.space-block', function() {
51382             event.preventDefault();
51383             event.stopPropagation();
51384             disableSpace = false;
51385             select(window).on('keyup.space-block', null);
51386         });
51387
51388         click();
51389     }
51390
51391
51392     function backspace() {
51393         event.preventDefault();
51394         dispatch$$1.call('undo');
51395     }
51396
51397
51398     function del() {
51399         event.preventDefault();
51400         dispatch$$1.call('cancel');
51401     }
51402
51403
51404     function ret() {
51405         event.preventDefault();
51406         dispatch$$1.call('finish');
51407     }
51408
51409
51410     function draw(selection$$1) {
51411         context.install(hover);
51412         context.install(edit);
51413
51414         if (!context.inIntro() && !usedTails[tail.text()]) {
51415             context.install(tail);
51416         }
51417
51418         keybinding
51419             .on('⌫', backspace)
51420             .on('⌦', del)
51421             .on('⎋', ret)
51422             .on('↩', ret)
51423             .on('space', space)
51424             .on('⌥space', space);
51425
51426         selection$$1
51427             .on('mouseenter.draw', mouseenter)
51428             .on('mouseleave.draw', mouseleave)
51429             .on('mousedown.draw', mousedown)
51430             .on('mousemove.draw', mousemove);
51431
51432         select(document)
51433             .call(keybinding);
51434
51435         return draw;
51436     }
51437
51438
51439     draw.off = function(selection$$1) {
51440         context.ui().sidebar.hover.cancel();
51441         context.uninstall(hover);
51442         context.uninstall(edit);
51443
51444         if (!context.inIntro() && !usedTails[tail.text()]) {
51445             context.uninstall(tail);
51446             usedTails[tail.text()] = true;
51447         }
51448
51449         selection$$1
51450             .on('mouseenter.draw', null)
51451             .on('mouseleave.draw', null)
51452             .on('mousedown.draw', null)
51453             .on('mousemove.draw', null);
51454
51455         select(window)
51456             .on('mouseup.draw', null);
51457             // note: keyup.space-block, click.draw-block should remain
51458
51459         select(document)
51460             .call(keybinding.off);
51461     };
51462
51463
51464     draw.tail = function(_) {
51465         tail.text(_);
51466         return draw;
51467     };
51468
51469
51470     return utilRebind(draw, dispatch$$1, 'on');
51471 }
51472
51473 function behaviorAddWay(context) {
51474     var dispatch$$1 = dispatch('start', 'startFromWay', 'startFromNode'),
51475         draw = behaviorDraw(context);
51476
51477     var addWay = function(surface) {
51478         draw.on('click', function() { dispatch$$1.apply('start', this, arguments); })
51479             .on('clickWay', function() { dispatch$$1.apply('startFromWay', this, arguments); })
51480             .on('clickNode', function() { dispatch$$1.apply('startFromNode', this, arguments); })
51481             .on('cancel', addWay.cancel)
51482             .on('finish', addWay.cancel);
51483
51484         context.map()
51485             .dblclickEnable(false);
51486
51487         surface.call(draw);
51488     };
51489
51490
51491     addWay.off = function(surface) {
51492         surface.call(draw.off);
51493     };
51494
51495
51496     addWay.cancel = function() {
51497         window.setTimeout(function() {
51498             context.map().dblclickEnable(true);
51499         }, 1000);
51500
51501         context.enter(modeBrowse(context));
51502     };
51503
51504
51505     addWay.tail = function(text$$1) {
51506         draw.tail(text$$1);
51507         return addWay;
51508     };
51509
51510
51511     return utilRebind(addWay, dispatch$$1, 'on');
51512 }
51513
51514 function behaviorBreathe() {
51515     var duration = 800,
51516         steps = 4,
51517         selector$$1 = '.selected.shadow, .selected .shadow',
51518         selected = select(null),
51519         classed = '',
51520         params = {},
51521         done = false,
51522         timer$$1;
51523
51524
51525     function ratchetyInterpolator(a, b, steps, units) {
51526         a = parseFloat(a);
51527         b = parseFloat(b);
51528         var sample = quantize$1()
51529             .domain([0, 1])
51530             .range(quantize(reinterpolate(a, b), steps));
51531
51532         return function(t) {
51533             return String(sample(t)) + (units || '');
51534         };
51535     }
51536
51537
51538     function reset(selection$$1) {
51539         selection$$1
51540             .style('stroke-opacity', null)
51541             .style('stroke-width', null)
51542             .style('fill-opacity', null)
51543             .style('r', null);
51544     }
51545
51546
51547     function setAnimationParams(transition$$1, fromTo) {
51548         var toFrom = (fromTo === 'from' ? 'to' : 'from');
51549
51550         transition$$1
51551             .styleTween('stroke-opacity', function(d) {
51552                 return ratchetyInterpolator(
51553                     params[d.id][toFrom].opacity,
51554                     params[d.id][fromTo].opacity,
51555                     steps
51556                 );
51557             })
51558             .styleTween('stroke-width', function(d) {
51559                 return ratchetyInterpolator(
51560                     params[d.id][toFrom].width,
51561                     params[d.id][fromTo].width,
51562                     steps,
51563                     'px'
51564                 );
51565             })
51566             .styleTween('fill-opacity', function(d) {
51567                 return ratchetyInterpolator(
51568                     params[d.id][toFrom].opacity,
51569                     params[d.id][fromTo].opacity,
51570                     steps
51571                 );
51572             })
51573             .styleTween('r', function(d) {
51574                 return ratchetyInterpolator(
51575                     params[d.id][toFrom].width,
51576                     params[d.id][fromTo].width,
51577                     steps,
51578                     'px'
51579                 );
51580             });
51581     }
51582
51583
51584     function calcAnimationParams(selection$$1) {
51585         selection$$1
51586             .call(reset)
51587             .each(function(d) {
51588                 var s = select(this),
51589                     tag = s.node().tagName,
51590                     p = {'from': {}, 'to': {}},
51591                     opacity, width;
51592
51593                 // determine base opacity and width
51594                 if (tag === 'circle') {
51595                     opacity = parseFloat(s.style('fill-opacity') || 0.5);
51596                     width = parseFloat(s.style('r') || 15.5);
51597                 } else {
51598                     opacity = parseFloat(s.style('stroke-opacity') || 0.7);
51599                     width = parseFloat(s.style('stroke-width') || 10);
51600                 }
51601
51602                 // calculate from/to interpolation params..
51603                 p.tag = tag;
51604                 p.from.opacity = opacity * 0.6;
51605                 p.to.opacity = opacity * 1.25;
51606                 p.from.width = width * 0.7;
51607                 p.to.width = width * (tag === 'circle' ? 1.5 : 1);
51608                 params[d.id] = p;
51609             });
51610     }
51611
51612
51613     function run(surface, fromTo) {
51614         var toFrom = (fromTo === 'from' ? 'to' : 'from'),
51615             currSelected = surface.selectAll(selector$$1),
51616             currClassed = surface.attr('class');
51617
51618         if (done || currSelected.empty()) {
51619             selected.call(reset);
51620             return;
51621         }
51622
51623         if (!lodash.isEqual(currSelected.data(), selected.data()) || currClassed !== classed) {
51624             selected.call(reset);
51625             classed = currClassed;
51626             selected = currSelected.call(calcAnimationParams);
51627         }
51628
51629         selected
51630             .transition()
51631             .duration(duration)
51632             .call(setAnimationParams, fromTo)
51633             .on('end', function() {
51634                 surface.call(run, toFrom);
51635             });
51636     }
51637
51638
51639     var breathe = function(surface) {
51640         done = false;
51641         timer$$1 = timer(function() {
51642             // wait for elements to actually become selected
51643             if (surface.selectAll(selector$$1).empty()) {
51644                 return false;
51645             }
51646
51647             surface.call(run, 'from');
51648             timer$$1.stop();
51649             return true;
51650         }, 20);
51651     };
51652
51653
51654     breathe.off = function() {
51655         done = true;
51656         if (timer$$1) {
51657             timer$$1.stop();
51658         }
51659         selected
51660             .interrupt()
51661             .call(reset);
51662     };
51663
51664
51665     return breathe;
51666 }
51667
51668 function behaviorCopy(context) {
51669     var keybinding = d3keybinding('copy');
51670
51671
51672     function groupEntities(ids, graph) {
51673         var entities = ids.map(function (id) { return graph.entity(id); });
51674         return lodash.extend({relation: [], way: [], node: []},
51675             lodash.groupBy(entities, function(entity) { return entity.type; }));
51676     }
51677
51678
51679     function getDescendants(id, graph, descendants) {
51680         var entity = graph.entity(id),
51681             i, children;
51682
51683         descendants = descendants || {};
51684
51685         if (entity.type === 'relation') {
51686             children = lodash.map(entity.members, 'id');
51687         } else if (entity.type === 'way') {
51688             children = entity.nodes;
51689         } else {
51690             children = [];
51691         }
51692
51693         for (i = 0; i < children.length; i++) {
51694             if (!descendants[children[i]]) {
51695                 descendants[children[i]] = true;
51696                 descendants = getDescendants(children[i], graph, descendants);
51697             }
51698         }
51699
51700         return descendants;
51701     }
51702
51703
51704     function doCopy() {
51705         event.preventDefault();
51706
51707         var graph = context.graph(),
51708             selected = groupEntities(context.selectedIDs(), graph),
51709             canCopy = [],
51710             skip = {},
51711             i, entity;
51712
51713         for (i = 0; i < selected.relation.length; i++) {
51714             entity = selected.relation[i];
51715             if (!skip[entity.id] && entity.isComplete(graph)) {
51716                 canCopy.push(entity.id);
51717                 skip = getDescendants(entity.id, graph, skip);
51718             }
51719         }
51720         for (i = 0; i < selected.way.length; i++) {
51721             entity = selected.way[i];
51722             if (!skip[entity.id]) {
51723                 canCopy.push(entity.id);
51724                 skip = getDescendants(entity.id, graph, skip);
51725             }
51726         }
51727         for (i = 0; i < selected.node.length; i++) {
51728             entity = selected.node[i];
51729             if (!skip[entity.id]) {
51730                 canCopy.push(entity.id);
51731             }
51732         }
51733
51734         context.copyIDs(canCopy);
51735     }
51736
51737
51738     function copy() {
51739         keybinding.on(uiCmd('⌘C'), doCopy);
51740         select(document).call(keybinding);
51741         return copy;
51742     }
51743
51744
51745     copy.off = function() {
51746         select(document).call(keybinding.off);
51747     };
51748
51749
51750     return copy;
51751 }
51752
51753 /*
51754     `behaviorDrag` is like `d3.behavior.drag`, with the following differences:
51755
51756     * The `origin` function is expected to return an [x, y] tuple rather than an
51757       {x, y} object.
51758     * The events are `start`, `move`, and `end`.
51759       (https://github.com/mbostock/d3/issues/563)
51760     * The `start` event is not dispatched until the first cursor movement occurs.
51761       (https://github.com/mbostock/d3/pull/368)
51762     * The `move` event has a `point` and `delta` [x, y] tuple properties rather
51763       than `x`, `y`, `dx`, and `dy` properties.
51764     * The `end` event is not dispatched if no movement occurs.
51765     * An `off` function is available that unbinds the drag's internal event handlers.
51766  */
51767
51768 function behaviorDrag() {
51769     var event$$1 = dispatch('start', 'move', 'end'),
51770         origin = null,
51771         selector$$1 = '',
51772         filter = null,
51773         event_, target, surface;
51774
51775
51776     var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect'),
51777         d3_event_userSelectSuppress = function() {
51778             var selection$$1 = selection(),
51779                 select$$1 = selection$$1.style(d3_event_userSelectProperty);
51780             selection$$1.style(d3_event_userSelectProperty, 'none');
51781             return function() {
51782                 selection$$1.style(d3_event_userSelectProperty, select$$1);
51783             };
51784         };
51785
51786
51787     function d3_eventCancel() {
51788         event.stopPropagation();
51789         event.preventDefault();
51790     }
51791
51792
51793     function eventOf(thiz, argumentz) {
51794         return function(e1) {
51795             e1.target = drag$$1;
51796             customEvent(e1, event$$1.apply, event$$1, [e1.type, thiz, argumentz]);
51797         };
51798     }
51799
51800
51801     function dragstart() {
51802         target = this;
51803         event_ = eventOf(target, arguments);
51804
51805         var eventTarget = event.target,
51806             touchId = event.touches ? event.changedTouches[0].identifier : null,
51807             offset,
51808             origin_ = point(),
51809             started = false,
51810             selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
51811
51812         select(window)
51813             .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
51814             .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
51815
51816         if (origin) {
51817             offset = origin.apply(target, arguments);
51818             offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
51819         } else {
51820             offset = [0, 0];
51821         }
51822
51823         if (touchId === null) {
51824             event.stopPropagation();
51825         }
51826
51827
51828         function point() {
51829             var p = surface || target.parentNode;
51830             return touchId !== null ? touches(p).filter(function(p) {
51831                 return p.identifier === touchId;
51832             })[0] : mouse(p);
51833         }
51834
51835
51836         function dragmove() {
51837             var p = point(),
51838                 dx = p[0] - origin_[0],
51839                 dy = p[1] - origin_[1];
51840
51841             if (dx === 0 && dy === 0)
51842                 return;
51843
51844             if (!started) {
51845                 started = true;
51846                 event_({ type: 'start' });
51847             }
51848
51849             origin_ = p;
51850             d3_eventCancel();
51851
51852             event_({
51853                 type: 'move',
51854                 point: [p[0] + offset[0],  p[1] + offset[1]],
51855                 delta: [dx, dy]
51856             });
51857         }
51858
51859
51860         function dragend() {
51861             if (started) {
51862                 event_({ type: 'end' });
51863
51864                 d3_eventCancel();
51865                 if (event.target === eventTarget) {
51866                     select(window)
51867                         .on('click.drag', click, true);
51868                 }
51869             }
51870
51871             select(window)
51872                 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
51873                 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
51874
51875             selectEnable();
51876         }
51877
51878
51879         function click() {
51880             d3_eventCancel();
51881             select(window)
51882                 .on('click.drag', null);
51883         }
51884     }
51885
51886
51887     function drag$$1(selection$$1) {
51888         var matchesSelector = utilPrefixDOMProperty('matchesSelector'),
51889             delegate = dragstart;
51890
51891         if (selector$$1) {
51892             delegate = function() {
51893                 var root = this,
51894                     target = event.target;
51895                 for (; target && target !== root; target = target.parentNode) {
51896                     if (target[matchesSelector](selector$$1) &&
51897                             (!filter || filter(target.__data__))) {
51898                         return dragstart.call(target, target.__data__);
51899                     }
51900                 }
51901             };
51902         }
51903
51904         selection$$1
51905             .on('mousedown.drag' + selector$$1, delegate)
51906             .on('touchstart.drag' + selector$$1, delegate);
51907     }
51908
51909
51910     drag$$1.off = function(selection$$1) {
51911         selection$$1
51912             .on('mousedown.drag' + selector$$1, null)
51913             .on('touchstart.drag' + selector$$1, null);
51914     };
51915
51916
51917     drag$$1.selector = function(_) {
51918         if (!arguments.length) return selector$$1;
51919         selector$$1 = _;
51920         return drag$$1;
51921     };
51922
51923
51924     drag$$1.filter = function(_) {
51925         if (!arguments.length) return origin;
51926         filter = _;
51927         return drag$$1;
51928     };
51929
51930
51931     drag$$1.origin = function (_) {
51932         if (!arguments.length) return origin;
51933         origin = _;
51934         return drag$$1;
51935     };
51936
51937
51938     drag$$1.cancel = function() {
51939         select(window)
51940             .on('mousemove.drag', null)
51941             .on('mouseup.drag', null);
51942         return drag$$1;
51943     };
51944
51945
51946     drag$$1.target = function() {
51947         if (!arguments.length) return target;
51948         target = arguments[0];
51949         event_ = eventOf(target, Array.prototype.slice.call(arguments, 1));
51950         return drag$$1;
51951     };
51952
51953
51954     drag$$1.surface = function() {
51955         if (!arguments.length) return surface;
51956         surface = arguments[0];
51957         return drag$$1;
51958     };
51959
51960
51961     return utilRebind(drag$$1, event$$1, 'on');
51962 }
51963
51964 function behaviorDrawWay(context, wayId, index, mode, startGraph) {
51965
51966     var origWay = context.entity(wayId),
51967         isArea = context.geometry(wayId) === 'area',
51968         tempEdits = 0,
51969         annotation = t((origWay.isDegenerate() ?
51970             'operations.start.annotation.' :
51971             'operations.continue.annotation.') + context.geometry(wayId)),
51972         draw = behaviorDraw(context),
51973         startIndex,
51974         start,
51975         end,
51976         segment;
51977
51978
51979     // initialize the temporary drawing entities
51980     if (!isArea) {
51981         startIndex = typeof index === 'undefined' ? origWay.nodes.length - 1 : 0;
51982         start = osmNode({ id: 'nStart', loc: context.entity(origWay.nodes[startIndex]).loc });
51983         end = osmNode({ id: 'nEnd', loc: context.map().mouseCoordinates() });
51984         segment = osmWay({ id: 'wTemp',
51985             nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
51986             tags: lodash.clone(origWay.tags)
51987         });
51988     } else {
51989         end = osmNode({ loc: context.map().mouseCoordinates() });
51990     }
51991
51992     // Push an annotated state for undo to return back to.
51993     // We must make sure to remove this edit later.
51994     context.perform(actionNoop(), annotation);
51995     tempEdits++;
51996
51997     // Add the temporary drawing entities to the graph.
51998     // We must make sure to remove this edit later.
51999     context.perform(AddDrawEntities());
52000     tempEdits++;
52001
52002
52003     function move(datum) {
52004         var loc;
52005
52006         if (datum.type === 'node' && datum.id !== end.id) {
52007             loc = datum.loc;
52008
52009         } else if (datum.type === 'way') {
52010             var dims = context.map().dimensions(),
52011                 mouse = context.mouse(),
52012                 pad = 5,
52013                 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
52014                     mouse[1] > pad && mouse[1] < dims[1] - pad;
52015
52016             if (trySnap) {
52017                 loc = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
52018             }
52019         }
52020
52021         if (!loc) {
52022             loc = context.map().mouseCoordinates();
52023         }
52024
52025         context.replace(actionMoveNode(end.id, loc));
52026         end = context.entity(end.id);
52027     }
52028
52029
52030     function undone() {
52031         // Undo popped the history back to the initial annotated no-op edit.
52032         // Remove initial no-op edit and whatever edit happened immediately before it.
52033         context.pop(2);
52034         tempEdits = 0;
52035
52036         if (context.hasEntity(wayId)) {
52037             context.enter(mode);
52038         } else {
52039             context.enter(modeBrowse(context));
52040         }
52041     }
52042
52043
52044     function setActiveElements() {
52045         var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
52046         context.surface().selectAll(utilEntitySelector(active))
52047             .classed('active', true);
52048     }
52049
52050
52051     var drawWay = function(surface) {
52052         draw.on('move', move)
52053             .on('click', drawWay.add)
52054             .on('clickWay', drawWay.addWay)
52055             .on('clickNode', drawWay.addNode)
52056             .on('undo', context.undo)
52057             .on('cancel', drawWay.cancel)
52058             .on('finish', drawWay.finish);
52059
52060         context.map()
52061             .dblclickEnable(false)
52062             .on('drawn.draw', setActiveElements);
52063
52064         setActiveElements();
52065
52066         surface.call(draw);
52067
52068         context.history()
52069             .on('undone.draw', undone);
52070     };
52071
52072
52073     drawWay.off = function(surface) {
52074         // Drawing was interrupted unexpectedly.
52075         // This can happen if the user changes modes,
52076         // clicks geolocate button, a hashchange event occurs, etc.
52077         if (tempEdits) {
52078             context.pop(tempEdits);
52079             while (context.graph() !== startGraph) {
52080                 context.pop();
52081             }
52082         }
52083
52084         context.map()
52085             .on('drawn.draw', null);
52086
52087         surface.call(draw.off)
52088             .selectAll('.active')
52089             .classed('active', false);
52090
52091         context.history()
52092             .on('undone.draw', null);
52093     };
52094
52095
52096     function AddDrawEntities() {
52097         return function(graph) {
52098             if (isArea) {
52099                 // For area drawing, there is no need for a temporary node.
52100                 // `end` gets inserted into the way as the penultimate node.
52101                 return graph
52102                     .replace(end)
52103                     .replace(origWay.addNode(end.id));
52104             } else {
52105                 // For line drawing, add a temporary start, end, and segment to the graph.
52106                 // This allows us to class the new segment as `active`, but still
52107                 // connect it back to parts of the way that have already been drawn.
52108                 return graph
52109                     .replace(start)
52110                     .replace(end)
52111                     .replace(segment);
52112             }
52113         };
52114     }
52115
52116
52117     function ReplaceDrawEntities(newNode) {
52118         return function(graph) {
52119             if (isArea) {
52120                 // For area drawing, we didn't create a temporary node.
52121                 // `newNode` gets inserted into the _original_ way as the penultimate node.
52122                 return graph
52123                     .replace(origWay.addNode(newNode.id))
52124                     .remove(end);
52125             } else {
52126                 // For line drawing, add the `newNode` to the way at specified index,
52127                 // and remove the temporary start, end, and segment.
52128                 return graph
52129                     .replace(origWay.addNode(newNode.id, index))
52130                     .remove(end)
52131                     .remove(segment)
52132                     .remove(start);
52133             }
52134         };
52135     }
52136
52137
52138     // Accept the current position of the temporary node and continue drawing.
52139     drawWay.add = function(loc) {
52140         // prevent duplicate nodes
52141         var last = context.hasEntity(origWay.nodes[origWay.nodes.length - (isArea ? 2 : 1)]);
52142         if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
52143
52144         context.pop(tempEdits);
52145
52146         if (isArea) {
52147             context.perform(
52148                 AddDrawEntities(),
52149                 annotation
52150             );
52151         } else {
52152             var newNode = osmNode({loc: loc});
52153             context.perform(
52154                 actionAddEntity(newNode),
52155                 ReplaceDrawEntities(newNode),
52156                 annotation
52157             );
52158         }
52159
52160         tempEdits = 0;
52161         context.enter(mode);
52162     };
52163
52164
52165     // Connect the way to an existing way.
52166     drawWay.addWay = function(loc, edge) {
52167         if (isArea) {
52168             context.pop(tempEdits);
52169
52170             context.perform(
52171                 AddDrawEntities(),
52172                 actionAddMidpoint({ loc: loc, edge: edge}, end),
52173                 annotation
52174             );
52175         } else {
52176             var previousEdge = startIndex ?
52177                 [origWay.nodes[startIndex], origWay.nodes[startIndex - 1]] :
52178                 [origWay.nodes[0], origWay.nodes[1]];
52179
52180             // Avoid creating duplicate segments
52181             if (geoEdgeEqual(edge, previousEdge))
52182                 return;
52183
52184             context.pop(tempEdits);
52185
52186             var newNode = osmNode({ loc: loc });
52187             context.perform(
52188                 actionAddMidpoint({ loc: loc, edge: edge}, newNode),
52189                 ReplaceDrawEntities(newNode),
52190                 annotation
52191             );
52192         }
52193
52194         tempEdits = 0;
52195         context.enter(mode);
52196     };
52197
52198
52199     // Connect the way to an existing node and continue drawing.
52200     drawWay.addNode = function(node) {
52201         // Avoid creating duplicate segments
52202         if (origWay.areAdjacent(node.id, origWay.nodes[origWay.nodes.length - 1])) return;
52203
52204         // Clicks should not occur on the drawing node, however a space keypress can
52205         // sometimes grab that node's datum (before it gets classed as `active`?)  #4016
52206         if (node.id === end.id) {
52207             drawWay.add(node.loc);
52208             return;
52209         }
52210
52211         context.pop(tempEdits);
52212
52213         context.perform(
52214             ReplaceDrawEntities(node),
52215             annotation
52216         );
52217
52218         tempEdits = 0;
52219         context.enter(mode);
52220     };
52221
52222
52223     // Finish the draw operation, removing the temporary edits.
52224     // If the way has enough nodes to be valid, it's selected.
52225     // Otherwise, delete everything and return to browse mode.
52226     drawWay.finish = function() {
52227         context.pop(tempEdits);
52228         tempEdits = 0;
52229
52230         var way = context.hasEntity(wayId);
52231         if (!way || way.isDegenerate()) {
52232             drawWay.cancel();
52233             return;
52234         }
52235
52236         window.setTimeout(function() {
52237             context.map().dblclickEnable(true);
52238         }, 1000);
52239
52240         context.enter(modeSelect(context, [wayId]).newFeature(true));
52241     };
52242
52243
52244     // Cancel the draw operation, delete everything, and return to browse mode.
52245     drawWay.cancel = function() {
52246         context.pop(tempEdits);
52247         tempEdits = 0;
52248
52249         while (context.graph() !== startGraph) {
52250             context.pop();
52251         }
52252
52253         window.setTimeout(function() {
52254             context.map().dblclickEnable(true);
52255         }, 1000);
52256
52257         context.enter(modeBrowse(context));
52258     };
52259
52260
52261     drawWay.tail = function(text) {
52262         draw.tail(text);
52263         return drawWay;
52264     };
52265
52266
52267     return drawWay;
52268 }
52269
52270 function behaviorHash(context) {
52271     var s0 = null, // cached window.location.hash
52272         lat = 90 - 1e-8; // allowable latitude range
52273
52274
52275     var parser = function(map, s) {
52276         var q = utilStringQs(s);
52277         var args = (q.map || '').split('/').map(Number);
52278
52279         if (args.length < 3 || args.some(isNaN)) {
52280             return true; // replace bogus hash
52281
52282         } else if (s !== formatter(map).slice(1)) {   // hash has changed
52283             var mode = context.mode(),
52284                 dist = geoSphericalDistance(map.center(), [args[2], args[1]]),
52285                 maxdist = 500;
52286
52287             // Don't allow the hash location to change too much while drawing
52288             // This can happen if the user accidently hit the back button.  #3996
52289             if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
52290                 context.enter(modeBrowse(context));
52291             }
52292
52293             map.centerZoom([args[2], Math.min(lat, Math.max(-lat, args[1]))], args[0]);
52294         }
52295     };
52296
52297
52298     var formatter = function(map) {
52299         var center = map.center(),
52300             zoom$$1 = map.zoom(),
52301             precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2)),
52302             q = lodash.omit(utilStringQs(window.location.hash.substring(1)), ['comment', 'walkthrough']),
52303             newParams = {};
52304
52305         delete q.id;
52306         var selected = context.selectedIDs().filter(function(id) {
52307             return !context.entity(id).isNew();
52308         });
52309         if (selected.length) {
52310             newParams.id = selected.join(',');
52311         }
52312
52313         newParams.map = zoom$$1.toFixed(2) +
52314             '/' + center[1].toFixed(precision) +
52315             '/' + center[0].toFixed(precision);
52316
52317         return '#' + utilQsString(lodash.assign(q, newParams), true);
52318     };
52319
52320
52321     function update() {
52322         if (context.inIntro()) return;
52323         var s1 = formatter(context.map());
52324         if (s0 !== s1) {
52325             window.location.replace(s0 = s1);  // don't recenter the map!
52326         }
52327     }
52328
52329
52330     var throttledUpdate = lodash.throttle(update, 500);
52331
52332
52333     function hashchange() {
52334         if (window.location.hash === s0) return;  // ignore spurious hashchange events
52335         if (parser(context.map(), (s0 = window.location.hash).substring(1))) {
52336             update(); // replace bogus hash
52337         }
52338     }
52339
52340
52341     function hash() {
52342         context.map()
52343             .on('move.hash', throttledUpdate);
52344
52345         context
52346             .on('enter.hash', throttledUpdate);
52347
52348         select(window)
52349             .on('hashchange.hash', hashchange);
52350
52351         if (window.location.hash) {
52352
52353             var q = utilStringQs(window.location.hash.substring(1));
52354
52355             if (q.id) {
52356                 context.zoomToEntity(q.id.split(',')[0], !q.map);
52357             }
52358
52359             if (q.comment) {
52360                 context.storage('comment', q.comment);
52361                 context.storage('commentDate', Date.now());
52362             }
52363
52364             if (q.walkthrough) {
52365                 hash.startWalkthrough = true;
52366             }
52367
52368             hashchange();
52369
52370             if (q.map) {
52371                 hash.hadHash = true;
52372             }
52373         }
52374     }
52375
52376
52377     hash.off = function() {
52378         throttledUpdate.cancel();
52379
52380         context.map()
52381             .on('move.hash', null);
52382
52383         context
52384             .on('enter.hash', null);
52385
52386         select(window)
52387             .on('hashchange.hash', null);
52388
52389         window.location.hash = '';
52390     };
52391
52392
52393     return hash;
52394 }
52395
52396 function behaviorLasso(context) {
52397
52398     var behavior = function(selection$$1) {
52399         var lasso;
52400
52401
52402         function mousedown() {
52403             var button = 0;  // left
52404             if (event.button === button && event.shiftKey === true) {
52405                 lasso = null;
52406
52407                 select(window)
52408                     .on('mousemove.lasso', mousemove)
52409                     .on('mouseup.lasso', mouseup);
52410
52411                 event.stopPropagation();
52412             }
52413         }
52414
52415
52416         function mousemove() {
52417             if (!lasso) {
52418                 lasso = uiLasso(context);
52419                 context.surface().call(lasso);
52420             }
52421
52422             lasso.p(context.mouse());
52423         }
52424
52425
52426         function normalize(a, b) {
52427             return [
52428                 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
52429                 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
52430         }
52431
52432
52433         function lassoed() {
52434             if (!lasso) return [];
52435
52436             var graph = context.graph(),
52437                 bounds$$1 = lasso.extent().map(context.projection.invert),
52438                 extent$$1 = geoExtent$$1(normalize(bounds$$1[0], bounds$$1[1]));
52439
52440             return lodash.map(context.intersects(extent$$1).filter(function(entity) {
52441                 return entity.type === 'node' &&
52442                     geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
52443                     !context.features().isHidden(entity, graph, entity.geometry(graph));
52444             }), 'id');
52445         }
52446
52447
52448         function mouseup() {
52449             select(window)
52450                 .on('mousemove.lasso', null)
52451                 .on('mouseup.lasso', null);
52452
52453             if (!lasso) return;
52454
52455             var ids = lassoed();
52456             lasso.close();
52457
52458             if (ids.length) {
52459                 context.enter(modeSelect(context, ids));
52460             }
52461         }
52462
52463         selection$$1
52464             .on('mousedown.lasso', mousedown);
52465     };
52466
52467
52468     behavior.off = function(selection$$1) {
52469         selection$$1.on('mousedown.lasso', null);
52470     };
52471
52472
52473     return behavior;
52474 }
52475
52476 /* Creates a keybinding behavior for an operation */
52477 function behaviorOperation() {
52478     var which, keybinding;
52479
52480
52481     function drawIcon(selection$$1) {
52482         var button = selection$$1
52483             .append('svg')
52484             .attr('class', 'operation-icon')
52485             .append('g')
52486             .attr('class', 'radial-menu-item radial-menu-item-' + which.id)
52487             .attr('transform', 'translate(10,10)')
52488             .classed('disabled', which.disabled());
52489
52490         button
52491             .append('circle')
52492             .attr('r', 9);
52493
52494         button
52495             .append('use')
52496             .attr('transform', 'translate(-7,-7)')
52497             .attr('width', '14')
52498             .attr('height', '14')
52499             .attr('xlink:href', '#operation-' + which.id);
52500
52501         return selection$$1;
52502     }
52503
52504
52505     var behavior = function () {
52506         if (which && which.available()) {
52507             keybinding = d3keybinding('behavior.key.' + which.id);
52508             keybinding.on(which.keys, function() {
52509                 event.preventDefault();
52510                 var disabled = which.disabled();
52511
52512                 if (disabled) {
52513                     uiFlash(3000)
52514                         .html('')
52515                         .call(drawIcon)
52516                         .append('div')
52517                         .attr('class', 'operation-tip')
52518                         .text(which.tooltip);
52519
52520                 } else {
52521                     uiFlash(1500)
52522                         .html('')
52523                         .call(drawIcon)
52524                         .append('div')
52525                         .attr('class', 'operation-tip')
52526                         .text(which.annotation() || which.title);
52527
52528                     which();
52529                 }
52530             });
52531             select(document).call(keybinding);
52532         }
52533         return behavior;
52534     };
52535
52536
52537     behavior.off = function() {
52538         if (keybinding) {
52539             select(document).call(keybinding.off);
52540         }
52541     };
52542
52543
52544     behavior.which = function (_) {
52545         if (!arguments.length) return which;
52546         which = _;
52547         return behavior;
52548     };
52549
52550
52551     return behavior;
52552 }
52553
52554 function behaviorPaste(context) {
52555     var keybinding = d3keybinding('paste');
52556
52557
52558     function doPaste() {
52559         event.preventDefault();
52560
52561         var baseGraph = context.graph(),
52562             mouse$$1 = context.mouse(),
52563             projection$$1 = context.projection,
52564             viewport = geoExtent$$1(projection$$1.clipExtent()).polygon();
52565
52566         if (!geoPointInPolygon(mouse$$1, viewport)) return;
52567
52568         var extent$$1 = geoExtent$$1(),
52569             oldIDs = context.copyIDs(),
52570             oldGraph = context.copyGraph(),
52571             newIDs = [];
52572
52573         if (!oldIDs.length) return;
52574
52575         var action = actionCopyEntities(oldIDs, oldGraph);
52576         context.perform(action);
52577
52578         var copies = action.copies();
52579         var originals = lodash.invert(lodash.mapValues(copies, 'id'));
52580         for (var id in copies) {
52581             var oldEntity = oldGraph.entity(id),
52582                 newEntity = copies[id];
52583
52584             extent$$1._extend(oldEntity.extent(oldGraph));
52585
52586             // Exclude child nodes from newIDs if their parent way was also copied.
52587             var parents = context.graph().parentWays(newEntity),
52588                 parentCopied = false;
52589             for (var i = 0; i < parents.length; i++) {
52590                 if (originals[parents[i].id]) {
52591                     parentCopied = true;
52592                     break;
52593                 }
52594             }
52595
52596             if (!parentCopied) {
52597                 newIDs.push(newEntity.id);
52598             }
52599         }
52600
52601         // Put pasted objects where mouse pointer is..
52602         var center = projection$$1(extent$$1.center()),
52603             delta = [ mouse$$1[0] - center[0], mouse$$1[1] - center[1] ];
52604
52605         context.perform(actionMove(newIDs, delta, projection$$1));
52606         context.enter(modeMove$$1(context, newIDs, baseGraph));
52607     }
52608
52609
52610     function paste() {
52611         keybinding.on(uiCmd('⌘V'), doPaste);
52612         select(document).call(keybinding);
52613         return paste;
52614     }
52615
52616
52617     paste.off = function() {
52618         select(document).call(keybinding.off);
52619     };
52620
52621
52622     return paste;
52623 }
52624
52625 function behaviorSelect(context) {
52626     var lastMouse = null,
52627         suppressMenu = true,
52628         tolerance = 4,
52629         p1 = null;
52630
52631
52632     function point() {
52633         return mouse(context.container().node());
52634     }
52635
52636
52637     function keydown() {
52638         var e = event;
52639         if (e && e.shiftKey) {
52640             context.surface()
52641                 .classed('behavior-multiselect', true);
52642         }
52643
52644         if (e && e.keyCode === 93) {  // context menu
52645             e.preventDefault();
52646             e.stopPropagation();
52647         }
52648     }
52649
52650
52651     function keyup() {
52652         var e = event;
52653         if (!e || !e.shiftKey) {
52654             context.surface()
52655                 .classed('behavior-multiselect', false);
52656         }
52657
52658
52659         if (e && e.keyCode === 93) {  // context menu
52660             e.preventDefault();
52661             e.stopPropagation();
52662             contextmenu();
52663         }
52664     }
52665
52666
52667     function mousedown() {
52668         if (!p1) p1 = point();
52669         select(window)
52670             .on('mouseup.select', mouseup, true);
52671
52672         var isShowAlways = +context.storage('edit-menu-show-always') === 1;
52673         suppressMenu = !isShowAlways;
52674     }
52675
52676
52677     function mousemove() {
52678         if (event) lastMouse = event;
52679     }
52680
52681
52682     function mouseup() {
52683         click();
52684     }
52685
52686
52687     function contextmenu() {
52688         var e = event;
52689         e.preventDefault();
52690         e.stopPropagation();
52691
52692         if (!+e.clientX && !+e.clientY) {
52693             if (lastMouse) {
52694                 e.sourceEvent = lastMouse;
52695             } else {
52696                 return;
52697             }
52698         }
52699
52700         if (!p1) p1 = point();
52701         suppressMenu = false;
52702         click();
52703     }
52704
52705
52706     function click() {
52707         select(window)
52708             .on('mouseup.select', null, true);
52709
52710         if (!p1) return;
52711         var p2 = point(),
52712             dist = geoEuclideanDistance(p1, p2);
52713
52714         p1 = null;
52715         if (dist > tolerance) {
52716             return;
52717         }
52718
52719         var isMultiselect = event.shiftKey || select('#surface .lasso').node(),
52720             isShowAlways = +context.storage('edit-menu-show-always') === 1,
52721             datum = event.target.__data__ || (lastMouse && lastMouse.target.__data__),
52722             mode = context.mode();
52723
52724
52725         if (datum && datum.type === 'midpoint') {
52726             datum = datum.parents[0];
52727         }
52728
52729         if (!(datum instanceof osmEntity$$1)) {
52730             // clicked nothing..
52731             if (!isMultiselect && mode.id !== 'browse') {
52732                 context.enter(modeBrowse(context));
52733             }
52734
52735         } else {
52736             // clicked an entity..
52737             var selectedIDs = context.selectedIDs();
52738
52739             if (!isMultiselect) {
52740                 if (selectedIDs.length > 1 && (!suppressMenu && !isShowAlways)) {
52741                     // multiple things already selected, just show the menu...
52742                     mode.suppressMenu(false).reselect();
52743                 } else {
52744                     // select a single thing..
52745                     context.enter(modeSelect(context, [datum.id]).suppressMenu(suppressMenu));
52746                 }
52747
52748             } else {
52749                 if (selectedIDs.indexOf(datum.id) !== -1) {
52750                     // clicked entity is already in the selectedIDs list..
52751                     if (!suppressMenu && !isShowAlways) {
52752                         // don't deselect clicked entity, just show the menu.
52753                         mode.suppressMenu(false).reselect();
52754                     } else {
52755                         // deselect clicked entity, then reenter select mode or return to browse mode..
52756                         selectedIDs = lodash.without(selectedIDs, datum.id);
52757                         context.enter(selectedIDs.length ? modeSelect(context, selectedIDs) : modeBrowse(context));
52758                     }
52759                 } else {
52760                     // clicked entity is not in the selected list, add it..
52761                     selectedIDs = selectedIDs.concat([datum.id]);
52762                     context.enter(modeSelect(context, selectedIDs).suppressMenu(suppressMenu));
52763                 }
52764             }
52765         }
52766
52767         // reset for next time..
52768         suppressMenu = true;
52769     }
52770
52771
52772     var behavior = function(selection$$1) {
52773         lastMouse = null;
52774         suppressMenu = true;
52775         p1 = null;
52776
52777         select(window)
52778             .on('keydown.select', keydown)
52779             .on('keyup.select', keyup)
52780             .on('contextmenu.select-window', function() {
52781                 // Edge and IE really like to show the contextmenu on the
52782                 // menubar when user presses a keyboard menu button
52783                 // even after we've already preventdefaulted the key event.
52784                 var e = event;
52785                 if (+e.clientX === 0 && +e.clientY === 0) {
52786                     event.preventDefault();
52787                     event.stopPropagation();
52788                 }
52789             });
52790
52791         selection$$1
52792             .on('mousedown.select', mousedown)
52793             .on('mousemove.select', mousemove)
52794             .on('contextmenu.select', contextmenu);
52795
52796         if (event && event.shiftKey) {
52797             context.surface()
52798                 .classed('behavior-multiselect', true);
52799         }
52800     };
52801
52802
52803     behavior.off = function(selection$$1) {
52804         select(window)
52805             .on('keydown.select', null)
52806             .on('keyup.select', null)
52807             .on('contextmenu.select-window', null)
52808             .on('mouseup.select', null, true);
52809
52810         selection$$1
52811             .on('mousedown.select', null)
52812             .on('mousemove.select', null)
52813             .on('contextmenu.select', null);
52814
52815         context.surface()
52816             .classed('behavior-multiselect', false);
52817     };
52818
52819
52820     return behavior;
52821 }
52822
52823 function modeAddArea$$1(context) {
52824     var mode = {
52825         id: 'add-area',
52826         button: 'area',
52827         title: t('modes.add_area.title'),
52828         description: t('modes.add_area.description'),
52829         key: '3'
52830     };
52831
52832     var behavior = behaviorAddWay(context)
52833             .tail(t('modes.add_area.tail'))
52834             .on('start', start)
52835             .on('startFromWay', startFromWay)
52836             .on('startFromNode', startFromNode),
52837         defaultTags = { area: 'yes' };
52838
52839
52840     function actionClose(wayId) {
52841         return function (graph) {
52842             return graph.replace(graph.entity(wayId).close());
52843         };
52844     }
52845
52846
52847     function start(loc) {
52848         var startGraph = context.graph(),
52849             node = osmNode({ loc: loc }),
52850             way = osmWay({ tags: defaultTags });
52851
52852         context.perform(
52853             actionAddEntity(node),
52854             actionAddEntity(way),
52855             actionAddVertex(way.id, node.id),
52856             actionClose(way.id)
52857         );
52858
52859         context.enter(modeDrawArea(context, way.id, startGraph));
52860     }
52861
52862
52863     function startFromWay(loc, edge) {
52864         var startGraph = context.graph(),
52865             node = osmNode({ loc: loc }),
52866             way = osmWay({ tags: defaultTags });
52867
52868         context.perform(
52869             actionAddEntity(node),
52870             actionAddEntity(way),
52871             actionAddVertex(way.id, node.id),
52872             actionClose(way.id),
52873             actionAddMidpoint({ loc: loc, edge: edge }, node)
52874         );
52875
52876         context.enter(modeDrawArea(context, way.id, startGraph));
52877     }
52878
52879
52880     function startFromNode(node) {
52881         var startGraph = context.graph(),
52882             way = osmWay({ tags: defaultTags });
52883
52884         context.perform(
52885             actionAddEntity(way),
52886             actionAddVertex(way.id, node.id),
52887             actionClose(way.id)
52888         );
52889
52890         context.enter(modeDrawArea(context, way.id, startGraph));
52891     }
52892
52893
52894     mode.enter = function() {
52895         context.install(behavior);
52896     };
52897
52898
52899     mode.exit = function() {
52900         context.uninstall(behavior);
52901     };
52902
52903
52904     return mode;
52905 }
52906
52907 function modeAddLine$$1(context) {
52908     var mode = {
52909         id: 'add-line',
52910         button: 'line',
52911         title: t('modes.add_line.title'),
52912         description: t('modes.add_line.description'),
52913         key: '2'
52914     };
52915
52916     var behavior = behaviorAddWay(context)
52917         .tail(t('modes.add_line.tail'))
52918         .on('start', start)
52919         .on('startFromWay', startFromWay)
52920         .on('startFromNode', startFromNode);
52921
52922
52923     function start(loc) {
52924         var startGraph = context.graph(),
52925             node = osmNode({ loc: loc }),
52926             way = osmWay();
52927
52928         context.perform(
52929             actionAddEntity(node),
52930             actionAddEntity(way),
52931             actionAddVertex(way.id, node.id)
52932         );
52933
52934         context.enter(modeDrawLine(context, way.id, startGraph));
52935     }
52936
52937
52938     function startFromWay(loc, edge) {
52939         var startGraph = context.graph(),
52940             node = osmNode({ loc: loc }),
52941             way = osmWay();
52942
52943         context.perform(
52944             actionAddEntity(node),
52945             actionAddEntity(way),
52946             actionAddVertex(way.id, node.id),
52947             actionAddMidpoint({ loc: loc, edge: edge }, node)
52948         );
52949
52950         context.enter(modeDrawLine(context, way.id, startGraph));
52951     }
52952
52953
52954     function startFromNode(node) {
52955         var startGraph = context.graph(),
52956             way = osmWay();
52957
52958         context.perform(
52959             actionAddEntity(way),
52960             actionAddVertex(way.id, node.id)
52961         );
52962
52963         context.enter(modeDrawLine(context, way.id, startGraph));
52964     }
52965
52966
52967     mode.enter = function() {
52968         context.install(behavior);
52969     };
52970
52971
52972     mode.exit = function() {
52973         context.uninstall(behavior);
52974     };
52975
52976     return mode;
52977 }
52978
52979 function modeAddPoint$$1(context) {
52980     var mode = {
52981         id: 'add-point',
52982         button: 'point',
52983         title: t('modes.add_point.title'),
52984         description: t('modes.add_point.description'),
52985         key: '1'
52986     };
52987
52988     var behavior = behaviorDraw(context)
52989         .tail(t('modes.add_point.tail'))
52990         .on('click', add)
52991         .on('clickWay', addWay)
52992         .on('clickNode', addNode)
52993         .on('cancel', cancel)
52994         .on('finish', cancel);
52995
52996
52997     function add(loc) {
52998         var node = osmNode({ loc: loc });
52999
53000         context.perform(
53001             actionAddEntity(node),
53002             t('operations.add.annotation.point')
53003         );
53004
53005         context.enter(
53006             modeSelect(context, [node.id]).newFeature(true)
53007         );
53008     }
53009
53010
53011     function addWay(loc) {
53012         add(loc);
53013     }
53014
53015
53016     function addNode(node) {
53017         add(node.loc);
53018     }
53019
53020
53021     function cancel() {
53022         context.enter(modeBrowse(context));
53023     }
53024
53025
53026     mode.enter = function() {
53027         context.install(behavior);
53028     };
53029
53030
53031     mode.exit = function() {
53032         context.uninstall(behavior);
53033     };
53034
53035
53036     return mode;
53037 }
53038
53039 function modeDragNode$$1(context) {
53040     var mode = {
53041         id: 'drag-node',
53042         button: 'browse'
53043     };
53044
53045     var nudgeInterval,
53046         activeIDs,
53047         wasMidpoint,
53048         isCancelled,
53049         lastLoc,
53050         selectedIDs = [],
53051         hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover),
53052         edit = behaviorEdit(context);
53053
53054
53055     function vecSub(a, b) {
53056         return [a[0] - b[0], a[1] - b[1]];
53057     }
53058
53059     function edge(point, size) {
53060         var pad = [80, 20, 50, 20],   // top, right, bottom, left
53061             x = 0,
53062             y = 0;
53063
53064         if (point[0] > size[0] - pad[1])
53065             x = -10;
53066         if (point[0] < pad[3])
53067             x = 10;
53068         if (point[1] > size[1] - pad[2])
53069             y = -10;
53070         if (point[1] < pad[0])
53071             y = 10;
53072
53073         if (x || y) {
53074             return [x, y];
53075         } else {
53076             return null;
53077         }
53078     }
53079
53080
53081     function startNudge(entity, nudge) {
53082         if (nudgeInterval) window.clearInterval(nudgeInterval);
53083         nudgeInterval = window.setInterval(function() {
53084             context.pan(nudge);
53085             doMove(entity, nudge);
53086         }, 50);
53087     }
53088
53089
53090     function stopNudge() {
53091         if (nudgeInterval) {
53092             window.clearInterval(nudgeInterval);
53093             nudgeInterval = null;
53094         }
53095     }
53096
53097
53098     function moveAnnotation(entity) {
53099         return t('operations.move.annotation.' + entity.geometry(context.graph()));
53100     }
53101
53102
53103     function connectAnnotation(entity) {
53104         return t('operations.connect.annotation.' + entity.geometry(context.graph()));
53105     }
53106
53107
53108     function origin(entity) {
53109         return context.projection(entity.loc);
53110     }
53111
53112
53113     function start(entity) {
53114         wasMidpoint = entity.type === 'midpoint';
53115
53116         isCancelled = event.sourceEvent.shiftKey ||
53117             context.features().hasHiddenConnections(entity, context.graph());
53118
53119         if (isCancelled) {
53120             return behavior.cancel();
53121         }
53122
53123         if (wasMidpoint) {
53124             var midpoint = entity;
53125             entity = osmNode();
53126             context.perform(actionAddMidpoint(midpoint, entity));
53127
53128             var vertex = context.surface().selectAll('.' + entity.id);
53129             behavior.target(vertex.node(), entity);
53130
53131         } else {
53132             context.perform(actionNoop());
53133         }
53134
53135         // activeIDs generate no pointer events.  This prevents the node or vertex
53136         // being dragged from trying to connect to itself or its parent element.
53137         activeIDs = lodash.map(context.graph().parentWays(entity), 'id');
53138         activeIDs.push(entity.id);
53139         setActiveElements();
53140
53141         context.enter(mode);
53142     }
53143
53144
53145     function datum() {
53146         var event$$1 = event && event.sourceEvent;
53147         if (!event$$1 || event$$1.altKey) {
53148             return {};
53149         } else {
53150             return event$$1.target.__data__ || {};
53151         }
53152     }
53153
53154
53155     function doMove(entity, nudge) {
53156         nudge = nudge || [0, 0];
53157
53158         var currPoint = (event && event.point) || context.projection(lastLoc),
53159             currMouse = vecSub(currPoint, nudge),
53160             loc = context.projection.invert(currMouse),
53161             d = datum();
53162
53163         if (!nudgeInterval) {
53164             if (d.type === 'node' && d.id !== entity.id) {
53165                 loc = d.loc;
53166             } else if (d.type === 'way' && !select(event.sourceEvent.target).classed('fill')) {
53167                 loc = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
53168             }
53169         }
53170
53171         context.replace(
53172             actionMoveNode(entity.id, loc),
53173             moveAnnotation(entity)
53174         );
53175
53176         lastLoc = loc;
53177     }
53178
53179
53180     function move(entity) {
53181         if (isCancelled) return;
53182         event.sourceEvent.stopPropagation();
53183         lastLoc = context.projection.invert(event.point);
53184
53185         doMove(entity);
53186         var nudge = edge(event.point, context.map().dimensions());
53187         if (nudge) {
53188             startNudge(entity, nudge);
53189         } else {
53190             stopNudge();
53191         }
53192     }
53193
53194
53195     function end(entity) {
53196         if (isCancelled) return;
53197
53198         var d = datum();
53199
53200         if (d.type === 'way') {
53201             var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection);
53202             context.replace(
53203                 actionAddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
53204                 connectAnnotation(d)
53205             );
53206
53207         } else if (d.type === 'node' && d.id !== entity.id) {
53208             context.replace(
53209                 actionConnect([d.id, entity.id]),
53210                 connectAnnotation(d)
53211             );
53212
53213         } else if (wasMidpoint) {
53214             context.replace(
53215                 actionNoop(),
53216                 t('operations.add.annotation.vertex')
53217             );
53218
53219         } else {
53220             context.replace(
53221                 actionNoop(),
53222                 moveAnnotation(entity)
53223             );
53224         }
53225
53226         var reselection = selectedIDs.filter(function(id) {
53227             return context.graph().hasEntity(id);
53228         });
53229
53230         if (reselection.length) {
53231             context.enter(modeSelect(context, reselection));
53232         } else {
53233             context.enter(modeBrowse(context));
53234         }
53235     }
53236
53237
53238     function cancel() {
53239         behavior.cancel();
53240         context.enter(modeBrowse(context));
53241     }
53242
53243
53244     function setActiveElements() {
53245         context.surface().selectAll(utilEntitySelector(activeIDs))
53246             .classed('active', true);
53247     }
53248
53249
53250     var behavior = behaviorDrag()
53251         .selector('g.node, g.point, g.midpoint')
53252         .surface(select('#map').node())
53253         .origin(origin)
53254         .on('start', start)
53255         .on('move', move)
53256         .on('end', end);
53257
53258
53259     mode.enter = function() {
53260         context.install(hover);
53261         context.install(edit);
53262
53263         context.history()
53264             .on('undone.drag-node', cancel);
53265
53266         context.map()
53267             .on('drawn.drag-node', setActiveElements);
53268
53269         setActiveElements();
53270     };
53271
53272
53273     mode.exit = function() {
53274         context.ui().sidebar.hover.cancel();
53275         context.uninstall(hover);
53276         context.uninstall(edit);
53277
53278         context.history()
53279             .on('undone.drag-node', null);
53280
53281         context.map()
53282             .on('drawn.drag-node', null);
53283
53284         context.surface()
53285             .selectAll('.active')
53286             .classed('active', false);
53287
53288         stopNudge();
53289     };
53290
53291
53292     mode.selectedIDs = function(_) {
53293         if (!arguments.length) return selectedIDs;
53294         selectedIDs = _;
53295         return mode;
53296     };
53297
53298
53299     mode.behavior = behavior;
53300
53301
53302     return mode;
53303 }
53304
53305 function modeBrowse(context) {
53306     var mode = {
53307         button: 'browse',
53308         id: 'browse',
53309         title: t('modes.browse.title'),
53310         description: t('modes.browse.description')
53311     }, sidebar;
53312
53313     var behaviors = [
53314         behaviorPaste(context),
53315         behaviorHover(context).on('hover', context.ui().sidebar.hover),
53316         behaviorSelect(context),
53317         behaviorLasso(context),
53318         modeDragNode$$1(context).behavior
53319     ];
53320
53321
53322     mode.enter = function() {
53323         behaviors.forEach(function(behavior) {
53324             context.install(behavior);
53325         });
53326
53327         // Get focus on the body.
53328         if (document.activeElement && document.activeElement.blur) {
53329             document.activeElement.blur();
53330         }
53331
53332         if (sidebar) {
53333             context.ui().sidebar.show(sidebar);
53334         } else {
53335             context.ui().sidebar.select(null);
53336         }
53337     };
53338
53339
53340     mode.exit = function() {
53341         context.ui().sidebar.hover.cancel();
53342         behaviors.forEach(function(behavior) {
53343             context.uninstall(behavior);
53344         });
53345
53346         if (sidebar) {
53347             context.ui().sidebar.hide();
53348         }
53349     };
53350
53351
53352     mode.sidebar = function(_) {
53353         if (!arguments.length) return sidebar;
53354         sidebar = _;
53355         return mode;
53356     };
53357
53358
53359     return mode;
53360 }
53361
53362 function modeDrawArea(context, wayId, startGraph) {
53363     var mode = {
53364         button: 'area',
53365         id: 'draw-area'
53366     };
53367
53368     var behavior;
53369
53370
53371     mode.enter = function() {
53372         var way = context.entity(wayId);
53373
53374         behavior = behaviorDrawWay(context, wayId, undefined, mode, startGraph)
53375             .tail(t('modes.draw_area.tail'));
53376
53377         var addNode = behavior.addNode;
53378
53379         behavior.addNode = function(node) {
53380             var length = way.nodes.length,
53381                 penultimate = length > 2 ? way.nodes[length - 2] : null;
53382
53383             if (node.id === way.first() || node.id === penultimate) {
53384                 behavior.finish();
53385             } else {
53386                 addNode(node);
53387             }
53388         };
53389
53390         context.install(behavior);
53391     };
53392
53393
53394     mode.exit = function() {
53395         context.uninstall(behavior);
53396     };
53397
53398
53399     mode.selectedIDs = function() {
53400         return [wayId];
53401     };
53402
53403
53404     return mode;
53405 }
53406
53407 function modeDrawLine(context, wayId, startGraph, affix) {
53408     var mode = {
53409         button: 'line',
53410         id: 'draw-line'
53411     };
53412
53413     var behavior;
53414
53415
53416     mode.enter = function() {
53417         var way = context.entity(wayId),
53418             index = (affix === 'prefix') ? 0 : undefined,
53419             headId = (affix === 'prefix') ? way.first() : way.last();
53420
53421         behavior = behaviorDrawWay(context, wayId, index, mode, startGraph)
53422             .tail(t('modes.draw_line.tail'));
53423
53424         var addNode = behavior.addNode;
53425
53426         behavior.addNode = function(node) {
53427             if (node.id === headId) {
53428                 behavior.finish();
53429             } else {
53430                 addNode(node);
53431             }
53432         };
53433
53434         context.install(behavior);
53435     };
53436
53437
53438     mode.exit = function() {
53439         context.uninstall(behavior);
53440     };
53441
53442
53443     mode.selectedIDs = function() {
53444         return [wayId];
53445     };
53446
53447
53448     return mode;
53449 }
53450
53451 function operationCircularize(selectedIDs, context) {
53452     var entityId = selectedIDs[0],
53453         entity = context.entity(entityId),
53454         extent = entity.extent(context.graph()),
53455         geometry = context.geometry(entityId),
53456         action = actionCircularize(entityId, context.projection);
53457
53458
53459     var operation = function() {
53460         context.perform(action, operation.annotation());
53461     };
53462
53463
53464     operation.available = function() {
53465         return selectedIDs.length === 1 &&
53466             entity.type === 'way' &&
53467             lodash.uniq(entity.nodes).length > 1;
53468     };
53469
53470
53471     operation.disabled = function() {
53472         var reason;
53473         if (extent.percentContainedIn(context.extent()) < 0.8) {
53474             reason = 'too_large';
53475         } else if (context.hasHiddenConnections(entityId)) {
53476             reason = 'connected_to_hidden';
53477         }
53478         return action.disabled(context.graph()) || reason;
53479     };
53480
53481
53482     operation.tooltip = function() {
53483         var disable = operation.disabled();
53484         return disable ?
53485             t('operations.circularize.' + disable) :
53486             t('operations.circularize.description.' + geometry);
53487     };
53488
53489
53490     operation.annotation = function() {
53491         return t('operations.circularize.annotation.' + geometry);
53492     };
53493
53494
53495     operation.id = 'circularize';
53496     operation.keys = [t('operations.circularize.key')];
53497     operation.title = t('operations.circularize.title');
53498     operation.behavior = behaviorOperation(context).which(operation);
53499
53500     return operation;
53501 }
53502
53503 function operationContinue(selectedIDs, context) {
53504     var graph = context.graph(),
53505         entities = selectedIDs.map(function(id) { return graph.entity(id); }),
53506         geometries = lodash.extend({ line: [], vertex: [] },
53507             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); })),
53508         vertex = geometries.vertex[0];
53509
53510
53511     function candidateWays() {
53512         return graph.parentWays(vertex).filter(function(parent) {
53513             return parent.geometry(graph) === 'line' &&
53514                 !parent.isClosed() &&
53515                 parent.affix(vertex.id) &&
53516                 (geometries.line.length === 0 || geometries.line[0] === parent);
53517         });
53518     }
53519
53520
53521     var operation = function() {
53522         var candidate = candidateWays()[0];
53523         context.enter(
53524             modeDrawLine(context, candidate.id, context.graph(), candidate.affix(vertex.id))
53525         );
53526     };
53527
53528
53529     operation.available = function() {
53530         return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
53531             !context.features().hasHiddenConnections(vertex, context.graph());
53532     };
53533
53534
53535     operation.disabled = function() {
53536         var candidates = candidateWays();
53537         if (candidates.length === 0)
53538             return 'not_eligible';
53539         if (candidates.length > 1)
53540             return 'multiple';
53541     };
53542
53543
53544     operation.tooltip = function() {
53545         var disable = operation.disabled();
53546         return disable ?
53547             t('operations.continue.' + disable) :
53548             t('operations.continue.description');
53549     };
53550
53551
53552     operation.annotation = function() {
53553         return t('operations.continue.annotation.line');
53554     };
53555
53556
53557     operation.id = 'continue';
53558     operation.keys = [t('operations.continue.key')];
53559     operation.title = t('operations.continue.title');
53560     operation.behavior = behaviorOperation(context).which(operation);
53561
53562     return operation;
53563 }
53564
53565 function operationDelete(selectedIDs, context) {
53566     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
53567         action = actionDeleteMultiple(selectedIDs),
53568         extent = selectedIDs.reduce(function(extent, id) {
53569                 return extent.extend(context.entity(id).extent(context.graph()));
53570             }, geoExtent$$1());
53571
53572
53573     var operation = function() {
53574         var nextSelectedID;
53575
53576         if (selectedIDs.length === 1) {
53577             var id = selectedIDs[0],
53578                 entity = context.entity(id),
53579                 geometry = context.geometry(id),
53580                 parents = context.graph().parentWays(entity),
53581                 parent = parents[0];
53582
53583             // Select the next closest node in the way.
53584             if (geometry === 'vertex' && parent.nodes.length > 2) {
53585                 var nodes = parent.nodes,
53586                     i = nodes.indexOf(id);
53587
53588                 if (i === 0) {
53589                     i++;
53590                 } else if (i === nodes.length - 1) {
53591                     i--;
53592                 } else {
53593                     var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
53594                         b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
53595                     i = a < b ? i - 1 : i + 1;
53596                 }
53597
53598                 nextSelectedID = nodes[i];
53599             }
53600         }
53601
53602         context.perform(action, operation.annotation());
53603
53604         if (nextSelectedID && context.hasEntity(nextSelectedID)) {
53605             context.enter(modeSelect(context, [nextSelectedID]).follow(true));
53606         } else {
53607             context.enter(modeBrowse(context));
53608         }
53609
53610     };
53611
53612
53613     operation.available = function() {
53614         return true;
53615     };
53616
53617
53618     operation.disabled = function() {
53619         var reason;
53620         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
53621             reason = 'too_large';
53622         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53623             reason = 'connected_to_hidden';
53624         } else if (lodash.some(selectedIDs, protectedMember)) {
53625             reason = 'part_of_relation';
53626         } else if (lodash.some(selectedIDs, incompleteRelation)) {
53627             reason = 'incomplete_relation';
53628         }
53629         return reason;
53630
53631         function incompleteRelation(id) {
53632             var entity = context.entity(id);
53633             return entity.type === 'relation' && !entity.isComplete(context.graph());
53634         }
53635
53636         function protectedMember(id) {
53637             var entity = context.entity(id);
53638             if (entity.type !== 'way') return false;
53639
53640             var parents = context.graph().parentRelations(entity);
53641             for (var i = 0; i < parents.length; i++) {
53642                 var parent = parents[i],
53643                     type = parent.tags.type,
53644                     role = parent.memberById(id).role || 'outer';
53645                 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
53646                     return true;
53647                 }
53648             }
53649             return false;
53650         }
53651
53652     };
53653
53654
53655     operation.tooltip = function() {
53656         var disable = operation.disabled();
53657         return disable ?
53658             t('operations.delete.' + disable + '.' + multi) :
53659             t('operations.delete.description' + '.' + multi);
53660     };
53661
53662
53663     operation.annotation = function() {
53664         return selectedIDs.length === 1 ?
53665             t('operations.delete.annotation.' + context.geometry(selectedIDs[0])) :
53666             t('operations.delete.annotation.multiple', { n: selectedIDs.length });
53667     };
53668
53669
53670     operation.id = 'delete';
53671     operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
53672     operation.title = t('operations.delete.title');
53673     operation.behavior = behaviorOperation(context).which(operation);
53674
53675     return operation;
53676 }
53677
53678 function operationDisconnect(selectedIDs, context) {
53679     var vertices = lodash.filter(selectedIDs, function(entityId) {
53680         return context.geometry(entityId) === 'vertex';
53681     });
53682
53683     var entityId = vertices[0],
53684         action = actionDisconnect(entityId);
53685
53686     if (selectedIDs.length > 1) {
53687         action.limitWays(lodash.without(selectedIDs, entityId));
53688     }
53689
53690
53691     var operation = function() {
53692         context.perform(action, operation.annotation());
53693     };
53694
53695
53696     operation.available = function() {
53697         return vertices.length === 1;
53698     };
53699
53700
53701     operation.disabled = function() {
53702         var reason;
53703         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53704             reason = 'connected_to_hidden';
53705         }
53706         return action.disabled(context.graph()) || reason;
53707     };
53708
53709
53710     operation.tooltip = function() {
53711         var disable = operation.disabled();
53712         return disable ?
53713             t('operations.disconnect.' + disable) :
53714             t('operations.disconnect.description');
53715     };
53716
53717
53718     operation.annotation = function() {
53719         return t('operations.disconnect.annotation');
53720     };
53721
53722
53723     operation.id = 'disconnect';
53724     operation.keys = [t('operations.disconnect.key')];
53725     operation.title = t('operations.disconnect.title');
53726     operation.behavior = behaviorOperation(context).which(operation);
53727
53728     return operation;
53729 }
53730
53731 function operationMerge(selectedIDs, context) {
53732
53733     function updatePresetTags(newGraph, ids) {
53734         var id = ids[0],
53735             newEntity = newGraph.hasEntity(id);
53736
53737         if (!newEntity) return;
53738
53739         var newPreset = context.presets().match(newEntity, newGraph);
53740
53741         context.replace(actionChangePreset(id, null, newPreset), operation.annotation());
53742     }
53743
53744
53745     var join = actionJoin(selectedIDs),
53746         merge = actionMerge(selectedIDs),
53747         mergePolygon = actionMergePolygon(selectedIDs);
53748
53749
53750     var operation = function() {
53751         var origGraph = context.graph(),
53752             action;
53753
53754         if (!join.disabled(origGraph)) {
53755             action = join;
53756         } else if (!merge.disabled(origGraph)) {
53757             action = merge;
53758         } else {
53759             action = mergePolygon;
53760         }
53761
53762         context.perform(action, operation.annotation());
53763
53764         var ids = selectedIDs.filter(function(id) {
53765             var entity = context.hasEntity(id);
53766             return entity && entity.type !== 'node';
53767         });
53768
53769         // if we merged tags, rematch preset to update tags if necessary (#3851)
53770         if (action === merge) {
53771             updatePresetTags(context.graph(), ids);
53772         }
53773
53774         context.enter(modeSelect(context, ids));
53775     };
53776
53777
53778     operation.available = function() {
53779         return selectedIDs.length >= 2;
53780     };
53781
53782
53783     operation.disabled = function() {
53784         return join.disabled(context.graph()) &&
53785             merge.disabled(context.graph()) &&
53786             mergePolygon.disabled(context.graph());
53787     };
53788
53789
53790     operation.tooltip = function() {
53791         var j = join.disabled(context.graph()),
53792             m = merge.disabled(context.graph()),
53793             p = mergePolygon.disabled(context.graph());
53794
53795         if (j === 'restriction' && m && p) {
53796             return t('operations.merge.restriction',
53797                 { relation: context.presets().item('type/restriction').name() });
53798         }
53799
53800         if (p === 'incomplete_relation' && j && m) {
53801             return t('operations.merge.incomplete_relation');
53802         }
53803
53804         if (j && m && p) {
53805             return t('operations.merge.' + j);
53806         }
53807
53808         return t('operations.merge.description');
53809     };
53810
53811
53812     operation.annotation = function() {
53813         return t('operations.merge.annotation', { n: selectedIDs.length });
53814     };
53815
53816
53817     operation.id = 'merge';
53818     operation.keys = [t('operations.merge.key')];
53819     operation.title = t('operations.merge.title');
53820     operation.behavior = behaviorOperation(context).which(operation);
53821
53822     return operation;
53823 }
53824
53825 function operationMove(selectedIDs, context) {
53826     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
53827         extent = selectedIDs.reduce(function(extent, id) {
53828             return extent.extend(context.entity(id).extent(context.graph()));
53829         }, geoExtent$$1());
53830
53831
53832     var operation = function() {
53833         context.enter(modeMove$$1(context, selectedIDs));
53834     };
53835
53836
53837     operation.available = function() {
53838         return selectedIDs.length > 1 ||
53839             context.entity(selectedIDs[0]).type !== 'node';
53840     };
53841
53842
53843     operation.disabled = function() {
53844         var reason;
53845         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
53846             reason = 'too_large';
53847         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53848             reason = 'connected_to_hidden';
53849         } else if (lodash.some(selectedIDs, incompleteRelation)) {
53850             reason = 'incomplete_relation';
53851         }
53852         return reason;
53853
53854         function incompleteRelation(id) {
53855             var entity = context.entity(id);
53856             return entity.type === 'relation' && !entity.isComplete(context.graph());
53857         }
53858     };
53859
53860
53861     operation.tooltip = function() {
53862         var disable = operation.disabled();
53863         return disable ?
53864             t('operations.move.' + disable + '.' + multi) :
53865             t('operations.move.description.' + multi);
53866     };
53867
53868
53869     operation.annotation = function() {
53870         return selectedIDs.length === 1 ?
53871             t('operations.move.annotation.' + context.geometry(selectedIDs[0])) :
53872             t('operations.move.annotation.multiple');
53873     };
53874
53875
53876     operation.id = 'move';
53877     operation.keys = [t('operations.move.key')];
53878     operation.title = t('operations.move.title');
53879     operation.behavior = behaviorOperation(context).which(operation);
53880
53881     return operation;
53882 }
53883
53884 function operationOrthogonalize(selectedIDs, context) {
53885     var entityId = selectedIDs[0],
53886         entity = context.entity(entityId),
53887         extent = entity.extent(context.graph()),
53888         geometry = context.geometry(entityId),
53889         action = actionOrthogonalize(entityId, context.projection);
53890
53891
53892     var operation = function() {
53893         context.perform(action, operation.annotation());
53894     };
53895
53896
53897     operation.available = function() {
53898         return selectedIDs.length === 1 &&
53899             entity.type === 'way' &&
53900             entity.isClosed() &&
53901             lodash.uniq(entity.nodes).length > 2;
53902     };
53903
53904
53905     operation.disabled = function() {
53906         var reason;
53907         if (extent.percentContainedIn(context.extent()) < 0.8) {
53908             reason = 'too_large';
53909         } else if (context.hasHiddenConnections(entityId)) {
53910             reason = 'connected_to_hidden';
53911         }
53912         return action.disabled(context.graph()) || reason;
53913     };
53914
53915
53916     operation.tooltip = function() {
53917         var disable = operation.disabled();
53918         return disable ?
53919             t('operations.orthogonalize.' + disable) :
53920             t('operations.orthogonalize.description.' + geometry);
53921     };
53922
53923
53924     operation.annotation = function() {
53925         return t('operations.orthogonalize.annotation.' + geometry);
53926     };
53927
53928
53929     operation.id = 'orthogonalize';
53930     operation.keys = [t('operations.orthogonalize.key')];
53931     operation.title = t('operations.orthogonalize.title');
53932     operation.behavior = behaviorOperation(context).which(operation);
53933
53934     return operation;
53935 }
53936
53937 function operationReflectShort(selectedIDs, context) {
53938     return operationReflect(selectedIDs, context, 'short');
53939 }
53940
53941
53942 function operationReflectLong(selectedIDs, context) {
53943     return operationReflect(selectedIDs, context, 'long');
53944 }
53945
53946
53947 function operationReflect(selectedIDs, context, axis) {
53948     axis = axis || 'long';
53949     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
53950         extent = selectedIDs.reduce(function(extent, id) {
53951             return extent.extend(context.entity(id).extent(context.graph()));
53952         }, geoExtent$$1());
53953
53954
53955     var operation = function() {
53956         var action = actionReflect(selectedIDs, context.projection)
53957             .useLongAxis(Boolean(axis === 'long'));
53958         context.perform(action, operation.annotation());
53959     };
53960
53961
53962     operation.available = function() {
53963         return lodash.some(selectedIDs, hasArea);
53964
53965         function hasArea(id) {
53966             var entity = context.entity(id);
53967             return (entity.type === 'way' && entity.isClosed()) ||
53968                 (entity.type ==='relation' && entity.isMultipolygon());
53969         }
53970     };
53971
53972
53973     operation.disabled = function() {
53974         var reason;
53975         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
53976             reason = 'too_large';
53977         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
53978             reason = 'connected_to_hidden';
53979         } else if (lodash.some(selectedIDs, incompleteRelation)) {
53980             reason = 'incomplete_relation';
53981         }
53982         return reason;
53983
53984         function incompleteRelation(id) {
53985             var entity = context.entity(id);
53986             return entity.type === 'relation' && !entity.isComplete(context.graph());
53987         }
53988     };
53989
53990
53991     operation.tooltip = function() {
53992         var disable = operation.disabled();
53993         return disable ?
53994             t('operations.reflect.' + disable + '.' + multi) :
53995             t('operations.reflect.description.' + axis + '.' + multi);
53996     };
53997
53998
53999     operation.annotation = function() {
54000         return t('operations.reflect.annotation.' + axis + '.' + multi);
54001     };
54002
54003
54004     operation.id = 'reflect-' + axis;
54005     operation.keys = [t('operations.reflect.key.' + axis)];
54006     operation.title = t('operations.reflect.title.' + axis);
54007     operation.behavior = behaviorOperation(context).which(operation);
54008
54009     return operation;
54010 }
54011
54012 function operationReverse(selectedIDs, context) {
54013     var entityId = selectedIDs[0];
54014
54015     var operation = function() {
54016         context.perform(actionReverse(entityId), operation.annotation());
54017     };
54018
54019
54020     operation.available = function() {
54021         return selectedIDs.length === 1 && context.geometry(entityId) === 'line';
54022     };
54023
54024
54025     operation.disabled = function() {
54026         return false;
54027     };
54028
54029
54030     operation.tooltip = function() {
54031         return t('operations.reverse.description');
54032     };
54033
54034
54035     operation.annotation = function() {
54036         return t('operations.reverse.annotation');
54037     };
54038
54039
54040     operation.id = 'reverse';
54041     operation.keys = [t('operations.reverse.key')];
54042     operation.title = t('operations.reverse.title');
54043     operation.behavior = behaviorOperation(context).which(operation);
54044
54045     return operation;
54046 }
54047
54048 function operationRotate(selectedIDs, context) {
54049     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
54050         extent = selectedIDs.reduce(function(extent, id) {
54051             return extent.extend(context.entity(id).extent(context.graph()));
54052         }, geoExtent$$1());
54053
54054
54055     var operation = function() {
54056         context.enter(modeRotate$$1(context, selectedIDs));
54057     };
54058
54059
54060     operation.available = function() {
54061         return lodash.some(selectedIDs, hasArea);
54062
54063         function hasArea(id) {
54064             var entity = context.entity(id);
54065             return (entity.type === 'way' && entity.isClosed()) ||
54066                 (entity.type ==='relation' && entity.isMultipolygon());
54067         }
54068     };
54069
54070
54071     operation.disabled = function() {
54072         var reason;
54073         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
54074             reason = 'too_large';
54075         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
54076             reason = 'connected_to_hidden';
54077         } else if (lodash.some(selectedIDs, incompleteRelation)) {
54078             reason = 'incomplete_relation';
54079         }
54080         return reason;
54081
54082         function incompleteRelation(id) {
54083             var entity = context.entity(id);
54084             return entity.type === 'relation' && !entity.isComplete(context.graph());
54085         }
54086     };
54087
54088
54089     operation.tooltip = function() {
54090         var disable = operation.disabled();
54091         return disable ?
54092             t('operations.rotate.' + disable + '.' + multi) :
54093             t('operations.rotate.description.' + multi);
54094     };
54095
54096
54097     operation.annotation = function() {
54098         return selectedIDs.length === 1 ?
54099             t('operations.rotate.annotation.' + context.geometry(selectedIDs[0])) :
54100             t('operations.rotate.annotation.multiple');
54101     };
54102
54103
54104     operation.id = 'rotate';
54105     operation.keys = [t('operations.rotate.key')];
54106     operation.title = t('operations.rotate.title');
54107     operation.behavior = behaviorOperation(context).which(operation);
54108
54109     return operation;
54110 }
54111
54112 function operationSplit(selectedIDs, context) {
54113     var vertices = lodash.filter(selectedIDs, function(entityId) {
54114         return context.geometry(entityId) === 'vertex';
54115     });
54116
54117     var entityId = vertices[0],
54118         action = actionSplit(entityId),
54119         ways = [];
54120
54121     if (vertices.length === 1) {
54122         if (selectedIDs.length > 1) {
54123             action.limitWays(lodash.without(selectedIDs, entityId));
54124         }
54125         ways = action.ways(context.graph());
54126     }
54127
54128
54129     var operation = function() {
54130         var difference = context.perform(action, operation.annotation());
54131         context.enter(modeSelect(context, difference.extantIDs()));
54132     };
54133
54134
54135     operation.available = function() {
54136         return vertices.length === 1;
54137     };
54138
54139
54140     operation.disabled = function() {
54141         var reason;
54142         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
54143             reason = 'connected_to_hidden';
54144         }
54145         return action.disabled(context.graph()) || reason;
54146     };
54147
54148
54149     operation.tooltip = function() {
54150         var disable = operation.disabled();
54151         if (disable) {
54152             return t('operations.split.' + disable);
54153         }
54154         if (ways.length === 1) {
54155             return t('operations.split.description.' + context.geometry(ways[0].id));
54156         } else {
54157             return t('operations.split.description.multiple');
54158         }
54159     };
54160
54161
54162     operation.annotation = function() {
54163         return ways.length === 1 ?
54164             t('operations.split.annotation.' + context.geometry(ways[0].id)) :
54165             t('operations.split.annotation.multiple', { n: ways.length });
54166     };
54167
54168
54169     operation.id = 'split';
54170     operation.keys = [t('operations.split.key')];
54171     operation.title = t('operations.split.title');
54172     operation.behavior = behaviorOperation(context).which(operation);
54173
54174     return operation;
54175 }
54176
54177 function operationStraighten(selectedIDs, context) {
54178     var entityId = selectedIDs[0],
54179         action = actionStraighten(entityId, context.projection);
54180
54181
54182     function operation() {
54183         context.perform(action, operation.annotation());
54184     }
54185
54186
54187     operation.available = function() {
54188         var entity = context.entity(entityId);
54189         return selectedIDs.length === 1 &&
54190             entity.type === 'way' &&
54191             !entity.isClosed() &&
54192             lodash.uniq(entity.nodes).length > 2;
54193     };
54194
54195
54196     operation.disabled = function() {
54197         var reason;
54198         if (context.hasHiddenConnections(entityId)) {
54199             reason = 'connected_to_hidden';
54200         }
54201         return action.disabled(context.graph()) || reason;
54202     };
54203
54204
54205     operation.tooltip = function() {
54206         var disable = operation.disabled();
54207         return disable ?
54208             t('operations.straighten.' + disable) :
54209             t('operations.straighten.description');
54210     };
54211
54212
54213     operation.annotation = function() {
54214         return t('operations.straighten.annotation');
54215     };
54216
54217
54218     operation.id = 'straighten';
54219     operation.keys = [t('operations.straighten.key')];
54220     operation.title = t('operations.straighten.title');
54221     operation.behavior = behaviorOperation(context).which(operation);
54222
54223     return operation;
54224 }
54225
54226
54227
54228 var Operations = Object.freeze({
54229         operationCircularize: operationCircularize,
54230         operationContinue: operationContinue,
54231         operationDelete: operationDelete,
54232         operationDisconnect: operationDisconnect,
54233         operationMerge: operationMerge,
54234         operationMove: operationMove,
54235         operationOrthogonalize: operationOrthogonalize,
54236         operationReflectShort: operationReflectShort,
54237         operationReflectLong: operationReflectLong,
54238         operationReverse: operationReverse,
54239         operationRotate: operationRotate,
54240         operationSplit: operationSplit,
54241         operationStraighten: operationStraighten
54242 });
54243
54244 function modeMove$$1(context, entityIDs, baseGraph) {
54245     var mode = {
54246         id: 'move',
54247         button: 'browse'
54248     };
54249
54250     var keybinding = d3keybinding('move'),
54251         behaviors = [
54252             behaviorEdit(context),
54253             operationCircularize(entityIDs, context).behavior,
54254             operationDelete(entityIDs, context).behavior,
54255             operationOrthogonalize(entityIDs, context).behavior,
54256             operationReflectLong(entityIDs, context).behavior,
54257             operationReflectShort(entityIDs, context).behavior,
54258             operationRotate(entityIDs, context).behavior
54259         ],
54260         annotation = entityIDs.length === 1 ?
54261             t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
54262             t('operations.move.annotation.multiple'),
54263         prevGraph,
54264         cache,
54265         origin,
54266         nudgeInterval;
54267
54268
54269     function vecSub(a, b) {
54270         return [a[0] - b[0], a[1] - b[1]];
54271     }
54272
54273
54274     function edge(point, size) {
54275         var pad = [80, 20, 50, 20],   // top, right, bottom, left
54276             x = 0,
54277             y = 0;
54278
54279         if (point[0] > size[0] - pad[1])
54280             x = -10;
54281         if (point[0] < pad[3])
54282             x = 10;
54283         if (point[1] > size[1] - pad[2])
54284             y = -10;
54285         if (point[1] < pad[0])
54286             y = 10;
54287
54288         if (x || y) {
54289             return [x, y];
54290         } else {
54291             return null;
54292         }
54293     }
54294
54295
54296     function doMove(nudge) {
54297         nudge = nudge || [0, 0];
54298
54299         var fn;
54300         if (prevGraph !== context.graph()) {
54301             cache = {};
54302             origin = context.map().mouseCoordinates();
54303             fn = context.perform;
54304         } else {
54305             fn = context.overwrite;
54306         }
54307
54308         var currMouse = context.mouse(),
54309             origMouse = context.projection(origin),
54310             delta = vecSub(vecSub(currMouse, origMouse), nudge);
54311
54312         fn(actionMove(entityIDs, delta, context.projection, cache), annotation);
54313         prevGraph = context.graph();
54314     }
54315
54316
54317     function startNudge(nudge) {
54318         if (nudgeInterval) window.clearInterval(nudgeInterval);
54319         nudgeInterval = window.setInterval(function() {
54320             context.pan(nudge);
54321             doMove(nudge);
54322         }, 50);
54323     }
54324
54325
54326     function stopNudge() {
54327         if (nudgeInterval) {
54328             window.clearInterval(nudgeInterval);
54329             nudgeInterval = null;
54330         }
54331     }
54332
54333
54334     function move() {
54335         doMove();
54336         var nudge = edge(context.mouse(), context.map().dimensions());
54337         if (nudge) {
54338             startNudge(nudge);
54339         } else {
54340             stopNudge();
54341         }
54342     }
54343
54344
54345     function finish() {
54346         event.stopPropagation();
54347         context.enter(modeSelect(context, entityIDs));
54348         stopNudge();
54349     }
54350
54351
54352     function cancel() {
54353         if (baseGraph) {
54354             while (context.graph() !== baseGraph) context.pop();
54355             context.enter(modeBrowse(context));
54356         } else {
54357             context.pop();
54358             context.enter(modeSelect(context, entityIDs));
54359         }
54360         stopNudge();
54361     }
54362
54363
54364     function undone() {
54365         context.enter(modeBrowse(context));
54366     }
54367
54368
54369     mode.enter = function() {
54370         origin = context.map().mouseCoordinates();
54371         prevGraph = null;
54372         cache = {};
54373
54374         behaviors.forEach(function(behavior) {
54375             context.install(behavior);
54376         });
54377
54378         context.surface()
54379             .on('mousemove.move', move)
54380             .on('click.move', finish);
54381
54382         context.history()
54383             .on('undone.move', undone);
54384
54385         keybinding
54386             .on('⎋', cancel)
54387             .on('↩', finish);
54388
54389         select(document)
54390             .call(keybinding);
54391     };
54392
54393
54394     mode.exit = function() {
54395         stopNudge();
54396
54397         behaviors.forEach(function(behavior) {
54398             context.uninstall(behavior);
54399         });
54400
54401         context.surface()
54402             .on('mousemove.move', null)
54403             .on('click.move', null);
54404
54405         context.history()
54406             .on('undone.move', null);
54407
54408         keybinding.off();
54409     };
54410
54411
54412     return mode;
54413 }
54414
54415 function modeRotate$$1(context, entityIDs) {
54416     var mode = {
54417         id: 'rotate',
54418         button: 'browse'
54419     };
54420
54421     var keybinding = d3keybinding('rotate'),
54422         behaviors = [
54423             behaviorEdit(context),
54424             operationCircularize(entityIDs, context).behavior,
54425             operationDelete(entityIDs, context).behavior,
54426             operationMove(entityIDs, context).behavior,
54427             operationOrthogonalize(entityIDs, context).behavior,
54428             operationReflectLong(entityIDs, context).behavior,
54429             operationReflectShort(entityIDs, context).behavior
54430         ],
54431         annotation = entityIDs.length === 1 ?
54432             t('operations.rotate.annotation.' + context.geometry(entityIDs[0])) :
54433             t('operations.rotate.annotation.multiple'),
54434         prevGraph,
54435         prevAngle,
54436         prevTransform,
54437         pivot;
54438
54439
54440     function doRotate() {
54441         var fn;
54442         if (context.graph() !== prevGraph) {
54443             fn = context.perform;
54444         } else {
54445             fn = context.replace;
54446         }
54447
54448         // projection changed, recalculate pivot
54449         var projection$$1 = context.projection;
54450         var currTransform = projection$$1.transform();
54451         if (!prevTransform ||
54452             currTransform.k !== prevTransform.k ||
54453             currTransform.x !== prevTransform.x ||
54454             currTransform.y !== prevTransform.y) {
54455
54456             var nodes = utilGetAllNodes(entityIDs, context.graph()),
54457                 points = nodes.map(function(n) { return projection$$1(n.loc); });
54458
54459             pivot = d3polygonCentroid(d3polygonHull(points));
54460             prevAngle = undefined;
54461         }
54462
54463
54464         var currMouse = context.mouse(),
54465             currAngle = Math.atan2(currMouse[1] - pivot[1], currMouse[0] - pivot[0]);
54466
54467         if (typeof prevAngle === 'undefined') prevAngle = currAngle;
54468         var delta = currAngle - prevAngle;
54469
54470         fn(actionRotate(entityIDs, pivot, delta, projection$$1), annotation);
54471
54472         prevTransform = currTransform;
54473         prevAngle = currAngle;
54474         prevGraph = context.graph();
54475     }
54476
54477
54478     function finish() {
54479         event.stopPropagation();
54480         context.enter(modeSelect(context, entityIDs));
54481     }
54482
54483
54484     function cancel() {
54485         context.pop();
54486         context.enter(modeSelect(context, entityIDs));
54487     }
54488
54489
54490     function undone() {
54491         context.enter(modeBrowse(context));
54492     }
54493
54494
54495     mode.enter = function() {
54496         behaviors.forEach(function(behavior) {
54497             context.install(behavior);
54498         });
54499
54500         context.surface()
54501             .on('mousemove.rotate', doRotate)
54502             .on('click.rotate', finish);
54503
54504         context.history()
54505             .on('undone.rotate', undone);
54506
54507         keybinding
54508             .on('⎋', cancel)
54509             .on('↩', finish);
54510
54511         select(document)
54512             .call(keybinding);
54513     };
54514
54515
54516     mode.exit = function() {
54517         behaviors.forEach(function(behavior) {
54518             context.uninstall(behavior);
54519         });
54520
54521         context.surface()
54522             .on('mousemove.rotate', null)
54523             .on('click.rotate', null);
54524
54525         context.history()
54526             .on('undone.rotate', null);
54527
54528         keybinding.off();
54529     };
54530
54531
54532     return mode;
54533 }
54534
54535 function modeSave$$1(context) {
54536     var mode = {
54537         id: 'save'
54538     };
54539
54540     var commit = uiCommit(context)
54541             .on('cancel', cancel)
54542             .on('save', save);
54543
54544
54545     function cancel() {
54546         context.enter(modeBrowse(context));
54547     }
54548
54549
54550     function save(changeset, tryAgain) {
54551
54552         var loading = uiLoading(context).message(t('save.uploading')).blocking(true),
54553             history = context.history(),
54554             origChanges = history.changes(actionDiscardTags(history.difference())),
54555             localGraph = context.graph(),
54556             remoteGraph = coreGraph$$1(history.base(), true),
54557             modified = lodash.filter(history.difference().summary(), {changeType: 'modified'}),
54558             toCheck = lodash.map(lodash.map(modified, 'entity'), 'id'),
54559             toLoad = withChildNodes(toCheck, localGraph),
54560             conflicts = [],
54561             errors = [];
54562
54563         if (!tryAgain) {
54564             history.perform(actionNoop());  // checkpoint
54565         }
54566
54567         context.container().call(loading);
54568
54569         if (toCheck.length) {
54570             context.connection().loadMultiple(toLoad, loaded);
54571         } else {
54572             upload();
54573         }
54574
54575
54576         function withChildNodes(ids, graph) {
54577             return lodash.uniq(lodash.reduce(ids, function(result, id) {
54578                 var entity = graph.entity(id);
54579                 if (entity.type === 'way') {
54580                     try {
54581                         var cn = graph.childNodes(entity);
54582                         result.push.apply(result, lodash.map(lodash.filter(cn, 'version'), 'id'));
54583                     } catch (err) {
54584                         /* eslint-disable no-console */
54585                         if (typeof console !== 'undefined') console.error(err);
54586                         /* eslint-enable no-console */
54587                     }
54588                 }
54589                 return result;
54590             }, lodash.clone(ids)));
54591         }
54592
54593
54594         // Reload modified entities into an alternate graph and check for conflicts..
54595         function loaded(err, result) {
54596             if (errors.length) return;
54597
54598             if (err) {
54599                 errors.push({
54600                     msg: err.responseText,
54601                     details: [ t('save.status_code', { code: err.status }) ]
54602                 });
54603                 showErrors();
54604
54605             } else {
54606                 var loadMore = [];
54607                 lodash.each(result.data, function(entity) {
54608                     remoteGraph.replace(entity);
54609                     toLoad = lodash.without(toLoad, entity.id);
54610
54611                     // Because loadMultiple doesn't download /full like loadEntity,
54612                     // need to also load children that aren't already being checked..
54613                     if (!entity.visible) return;
54614                     if (entity.type === 'way') {
54615                         loadMore.push.apply(loadMore,
54616                             lodash.difference(entity.nodes, toCheck, toLoad, loadMore));
54617                     } else if (entity.type === 'relation' && entity.isMultipolygon()) {
54618                         loadMore.push.apply(loadMore,
54619                             lodash.difference(lodash.map(entity.members, 'id'), toCheck, toLoad, loadMore));
54620                     }
54621                 });
54622
54623                 if (loadMore.length) {
54624                     toLoad.push.apply(toLoad, loadMore);
54625                     context.connection().loadMultiple(loadMore, loaded);
54626                 }
54627
54628                 if (!toLoad.length) {
54629                     checkConflicts();
54630                 }
54631             }
54632         }
54633
54634
54635         function checkConflicts() {
54636             function choice(id, text$$1, action) {
54637                 return { id: id, text: text$$1, action: function() { history.replace(action); } };
54638             }
54639             function formatUser(d) {
54640                 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
54641             }
54642             function entityName(entity) {
54643                 return utilDisplayName(entity) || (utilDisplayType(entity.id) + ' ' + entity.id);
54644             }
54645
54646             function compareVersions(local, remote) {
54647                 if (local.version !== remote.version) return false;
54648
54649                 if (local.type === 'way') {
54650                     var children = lodash.union(local.nodes, remote.nodes);
54651
54652                     for (var i = 0; i < children.length; i++) {
54653                         var a = localGraph.hasEntity(children[i]),
54654                             b = remoteGraph.hasEntity(children[i]);
54655
54656                         if (a && b && a.version !== b.version) return false;
54657                     }
54658                 }
54659
54660                 return true;
54661             }
54662
54663             lodash.each(toCheck, function(id) {
54664                 var local = localGraph.entity(id),
54665                     remote = remoteGraph.entity(id);
54666
54667                 if (compareVersions(local, remote)) return;
54668
54669                 var action = actionMergeRemoteChanges,
54670                     merge$$1 = action(id, localGraph, remoteGraph, formatUser);
54671
54672                 history.replace(merge$$1);
54673
54674                 var mergeConflicts = merge$$1.conflicts();
54675                 if (!mergeConflicts.length) return;  // merged safely
54676
54677                 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
54678                     forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
54679                     keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
54680                     keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
54681
54682                 conflicts.push({
54683                     id: id,
54684                     name: entityName(local),
54685                     details: mergeConflicts,
54686                     chosen: 1,
54687                     choices: [
54688                         choice(id, keepMine, forceLocal),
54689                         choice(id, keepTheirs, forceRemote)
54690                     ]
54691                 });
54692             });
54693
54694             upload();
54695         }
54696
54697
54698         function upload() {
54699             if (conflicts.length) {
54700                 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
54701                 showConflicts();
54702             } else if (errors.length) {
54703                 showErrors();
54704             } else {
54705                 var changes = history.changes(actionDiscardTags(history.difference()));
54706                 if (changes.modified.length || changes.created.length || changes.deleted.length) {
54707                     context.connection().putChangeset(changeset, changes, uploadCallback);
54708                 } else {        // changes were insignificant or reverted by user
54709                     select('.inspector-wrap *').remove();
54710                     loading.close();
54711                     context.flush();
54712                     cancel();
54713                 }
54714             }
54715         }
54716
54717
54718         function uploadCallback(err, changeset) {
54719             if (err) {
54720                 errors.push({
54721                     msg: err.responseText,
54722                     details: [ t('save.status_code', { code: err.status }) ]
54723                 });
54724                 showErrors();
54725             } else {
54726                 history.clearSaved();
54727                 success(changeset);
54728                 // Add delay to allow for postgres replication #1646 #2678
54729                 window.setTimeout(function() {
54730                     select('.inspector-wrap *').remove();
54731                     loading.close();
54732                     context.flush();
54733                 }, 2500);
54734             }
54735         }
54736
54737
54738         function showConflicts() {
54739             var selection$$1 = context.container()
54740                 .select('#sidebar')
54741                 .append('div')
54742                 .attr('class','sidebar-component');
54743
54744             loading.close();
54745
54746             selection$$1.call(uiConflicts(context)
54747                 .list(conflicts)
54748                 .on('download', function() {
54749                     var data = JXON.stringify(changeset.update({ id: 'CHANGEME' }).osmChangeJXON(origChanges)),
54750                         win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
54751                     win.focus();
54752                 })
54753                 .on('cancel', function() {
54754                     history.pop();
54755                     selection$$1.remove();
54756                 })
54757                 .on('save', function() {
54758                     for (var i = 0; i < conflicts.length; i++) {
54759                         if (conflicts[i].chosen === 1) {  // user chose "keep theirs"
54760                             var entity = context.hasEntity(conflicts[i].id);
54761                             if (entity && entity.type === 'way') {
54762                                 var children = lodash.uniq(entity.nodes);
54763                                 for (var j = 0; j < children.length; j++) {
54764                                     history.replace(actionRevert(children[j]));
54765                                 }
54766                             }
54767                             history.replace(actionRevert(conflicts[i].id));
54768                         }
54769                     }
54770
54771                     selection$$1.remove();
54772                     save(changeset, true);
54773                 })
54774             );
54775         }
54776
54777
54778         function showErrors() {
54779             var selection$$1 = uiConfirm(context.container());
54780
54781             history.pop();
54782             loading.close();
54783
54784             selection$$1
54785                 .select('.modal-section.header')
54786                 .append('h3')
54787                 .text(t('save.error'));
54788
54789             addErrors(selection$$1, errors);
54790             selection$$1.okButton();
54791         }
54792
54793
54794         function addErrors(selection$$1, data) {
54795             var message = selection$$1
54796                 .select('.modal-section.message-text');
54797
54798             var items = message
54799                 .selectAll('.error-container')
54800                 .data(data);
54801
54802             var enter = items.enter()
54803                 .append('div')
54804                 .attr('class', 'error-container');
54805
54806             enter
54807                 .append('a')
54808                 .attr('class', 'error-description')
54809                 .attr('href', '#')
54810                 .classed('hide-toggle', true)
54811                 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
54812                 .on('click', function() {
54813                     var error = select(this),
54814                         detail = select(this.nextElementSibling),
54815                         exp = error.classed('expanded');
54816
54817                     detail.style('display', exp ? 'none' : 'block');
54818                     error.classed('expanded', !exp);
54819
54820                     event.preventDefault();
54821                 });
54822
54823             var details = enter
54824                 .append('div')
54825                 .attr('class', 'error-detail-container')
54826                 .style('display', 'none');
54827
54828             details
54829                 .append('ul')
54830                 .attr('class', 'error-detail-list')
54831                 .selectAll('li')
54832                 .data(function(d) { return d.details || []; })
54833                 .enter()
54834                 .append('li')
54835                 .attr('class', 'error-detail-item')
54836                 .text(function(d) { return d; });
54837
54838             items.exit()
54839                 .remove();
54840         }
54841
54842     }
54843
54844
54845     function success(changeset) {
54846         commit.reset();
54847         context.enter(modeBrowse(context)
54848             .sidebar(uiSuccess(context)
54849                 .changeset(changeset)
54850                 .on('cancel', function() {
54851                     context.ui().sidebar.hide();
54852                 })
54853             )
54854         );
54855     }
54856
54857
54858     mode.enter = function() {
54859         function done() {
54860             context.ui().sidebar.show(commit);
54861         }
54862
54863         context.container().selectAll('#content')
54864             .attr('class', 'inactive');
54865
54866         if (context.connection().authenticated()) {
54867             done();
54868         } else {
54869             context.connection().authenticate(function(err) {
54870                 if (err) {
54871                     cancel();
54872                 } else {
54873                     done();
54874                 }
54875             });
54876         }
54877     };
54878
54879
54880     mode.exit = function() {
54881         context.container().selectAll('#content')
54882             .attr('class', 'active');
54883
54884         context.ui().sidebar.hide();
54885     };
54886
54887     return mode;
54888 }
54889
54890 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
54891 // For example, ⌘Z -> Ctrl+Z
54892 var uiCmd = function (code) {
54893     var detected = utilDetect();
54894
54895     if (detected.os === 'mac') {
54896         return code;
54897     }
54898
54899     if (detected.os === 'win') {
54900         if (code === '⌘⇧Z') return 'Ctrl+Y';
54901     }
54902
54903     var result = '',
54904         replacements = {
54905             '⌘': 'Ctrl',
54906             '⇧': 'Shift',
54907             '⌥': 'Alt',
54908             '⌫': 'Backspace',
54909             '⌦': 'Delete'
54910         };
54911
54912     for (var i = 0; i < code.length; i++) {
54913         if (code[i] in replacements) {
54914             result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
54915         } else {
54916             result += code[i];
54917         }
54918     }
54919
54920     return result;
54921 };
54922
54923
54924 // return a display-focused string for a given keyboard code
54925 uiCmd.display = function(code) {
54926     if (code.length !== 1) return code;
54927
54928     var detected = utilDetect();
54929     var mac = (detected.os === 'mac');
54930     var replacements = {
54931         '⌘': mac ? '⌘ ' + t('shortcuts.key.cmd')    : t('shortcuts.key.ctrl'),
54932         '⇧': mac ? '⇧ ' + t('shortcuts.key.shift')  : t('shortcuts.key.shift'),
54933         '⌥': mac ? '⌥ ' + t('shortcuts.key.option') : t('shortcuts.key.alt'),
54934         '⌃': mac ? '⌃ ' + t('shortcuts.key.ctrl')   : t('shortcuts.key.ctrl'),
54935         '⌫': mac ? '⌫ ' + t('shortcuts.key.delete') : t('shortcuts.key.backspace'),
54936         '⌦': mac ? '⌦ ' + t('shortcuts.key.del')    : t('shortcuts.key.del'),
54937         '↖': mac ? '↖ ' + t('shortcuts.key.pgup')   : t('shortcuts.key.pgup'),
54938         '↘': mac ? '↘ ' + t('shortcuts.key.pgdn')   : t('shortcuts.key.pgdn'),
54939         '⇞': mac ? '⇞ ' + t('shortcuts.key.home')   : t('shortcuts.key.home'),
54940         '⇟': mac ? '⇟ ' + t('shortcuts.key.end')    : t('shortcuts.key.end'),
54941         '↵': mac ? '↵ ' + t('shortcuts.key.return') : t('shortcuts.key.enter'),
54942         '⎋': mac ? '⎋ ' + t('shortcuts.key.esc')    : t('shortcuts.key.esc'),
54943     };
54944
54945     return replacements[code] || code;
54946 };
54947
54948 // deprecation warning - Radial Menu to be removed in iD v3
54949 var relatedParent;
54950
54951
54952 function modeSelect(context, selectedIDs) {
54953     var mode = {
54954         id: 'select',
54955         button: 'browse'
54956     };
54957
54958     var keybinding = d3keybinding('select'),
54959         timeout = null,
54960         behaviors = [
54961             behaviorCopy(context),
54962             behaviorPaste(context),
54963             behaviorBreathe(context),
54964             behaviorHover(context),
54965             behaviorSelect(context),
54966             behaviorLasso(context),
54967             modeDragNode$$1(context).selectedIDs(selectedIDs).behavior
54968         ],
54969         inspector,
54970         editMenu,
54971         newFeature = false,
54972         suppressMenu = true,
54973         follow = false;
54974
54975
54976     var wrap = context.container()
54977         .select('.inspector-wrap');
54978
54979
54980     function singular() {
54981         if (selectedIDs.length === 1) {
54982             return context.hasEntity(selectedIDs[0]);
54983         }
54984     }
54985
54986
54987     function checkSelectedIDs() {
54988         var ids = [];
54989         if (Array.isArray(selectedIDs)) {
54990             ids = selectedIDs.filter(function(id) {
54991                 return context.hasEntity(id);
54992             });
54993         }
54994
54995         if (ids.length) {
54996             selectedIDs = ids;
54997         } else {
54998             context.enter(modeBrowse(context));
54999         }
55000         return !!ids.length;
55001     }
55002
55003
55004     // find the common parent ways for nextVertex, previousVertex
55005     function commonParents() {
55006         var graph = context.graph(),
55007             commonParents = [];
55008
55009         for (var i = 0; i < selectedIDs.length; i++) {
55010             var entity = context.hasEntity(selectedIDs[i]);
55011             if (!entity || entity.geometry(graph) !== 'vertex') {
55012                 return [];  // selection includes some not vertexes
55013             }
55014
55015             var currParents = lodash.map(graph.parentWays(entity), 'id');
55016             if (!commonParents.length) {
55017                 commonParents = currParents;
55018                 continue;
55019             }
55020
55021             commonParents = lodash.intersection(commonParents, currParents);
55022             if (!commonParents.length) {
55023                 return [];
55024             }
55025         }
55026
55027         return commonParents;
55028     }
55029
55030
55031     function singularParent() {
55032         var parents = commonParents();
55033         if (!parents || parents.length === 0) {
55034             relatedParent = null;
55035             return null;
55036         }
55037
55038         // relatedParent is used when we visit a vertex with multiple
55039         // parents, and we want to remember which parent line we started on.
55040
55041         if (parents.length === 1) {
55042             relatedParent = parents[0];  // remember this parent for later
55043             return relatedParent;
55044         }
55045
55046         if (parents.indexOf(relatedParent) !== -1) {
55047             return relatedParent;   // prefer the previously seen parent
55048         }
55049
55050         return parents[0];
55051     }
55052
55053
55054     function closeMenu() {
55055         if (editMenu) {
55056             context.surface().call(editMenu.close);
55057         }
55058     }
55059
55060
55061     function positionMenu() {
55062         if (!editMenu) { return; }
55063
55064         var entity = singular();
55065         if (entity && context.geometry(entity.id) === 'relation') {
55066             suppressMenu = true;
55067         } else {
55068             var point = context.mouse(),
55069                 viewport = geoExtent$$1(context.projection.clipExtent()).polygon();
55070
55071             if (point && geoPointInPolygon(point, viewport)) {
55072                 editMenu.center(point);
55073             } else {
55074                 suppressMenu = true;
55075             }
55076         }
55077     }
55078
55079
55080     function showMenu() {
55081         closeMenu();
55082         if (editMenu) {
55083             context.surface().call(editMenu);
55084         }
55085     }
55086
55087
55088     function toggleMenu() {
55089         // deprecation warning - Radial Menu to be removed in iD v3
55090         if (select('.edit-menu, .radial-menu').empty()) {
55091             positionMenu();
55092             showMenu();
55093         } else {
55094             closeMenu();
55095         }
55096     }
55097
55098
55099     mode.selectedIDs = function() {
55100         return selectedIDs;
55101     };
55102
55103
55104     mode.reselect = function() {
55105         if (!checkSelectedIDs()) return;
55106
55107         var surfaceNode = context.surface().node();
55108         if (surfaceNode.focus) {   // FF doesn't support it
55109             surfaceNode.focus();
55110         }
55111
55112         positionMenu();
55113         if (!suppressMenu) {
55114             showMenu();
55115         }
55116     };
55117
55118
55119     mode.newFeature = function(_) {
55120         if (!arguments.length) return newFeature;
55121         newFeature = _;
55122         return mode;
55123     };
55124
55125
55126     mode.suppressMenu = function(_) {
55127         if (!arguments.length) return suppressMenu;
55128         suppressMenu = _;
55129         return mode;
55130     };
55131
55132
55133     mode.follow = function(_) {
55134         if (!arguments.length) return follow;
55135         follow = _;
55136         return mode;
55137     };
55138
55139
55140     mode.enter = function() {
55141
55142         function update() {
55143             closeMenu();
55144             checkSelectedIDs();
55145         }
55146
55147
55148         function dblclick() {
55149             var target = select(event.target),
55150                 datum = target.datum();
55151
55152             if (datum instanceof osmWay && !target.classed('fill')) {
55153                 var choice = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection),
55154                     prev = datum.nodes[choice.index - 1],
55155                     next = datum.nodes[choice.index];
55156
55157                 context.perform(
55158                     actionAddMidpoint({loc: choice.loc, edge: [prev, next]}, osmNode()),
55159                     t('operations.add.annotation.vertex')
55160                 );
55161
55162                 event.preventDefault();
55163                 event.stopPropagation();
55164
55165             } else if (datum.type === 'midpoint') {
55166                 context.perform(
55167                     actionAddMidpoint({loc: datum.loc, edge: datum.edge}, osmNode()),
55168                     t('operations.add.annotation.vertex'));
55169
55170                 event.preventDefault();
55171                 event.stopPropagation();
55172             }
55173         }
55174
55175
55176         function selectElements(drawn) {
55177             if (!checkSelectedIDs()) return;
55178
55179             var surface = context.surface(),
55180                 entity = singular();
55181
55182             if (entity && context.geometry(entity.id) === 'relation') {
55183                 suppressMenu = true;
55184                 return;
55185             }
55186
55187             surface.selectAll('.related')
55188                 .classed('related', false);
55189
55190             singularParent();
55191             if (relatedParent) {
55192                 surface.selectAll(utilEntitySelector([relatedParent]))
55193                     .classed('related', true);
55194             }
55195
55196             var selection$$1 = context.surface()
55197                 .selectAll(utilEntityOrMemberSelector(selectedIDs, context.graph()));
55198
55199             if (selection$$1.empty()) {
55200                 // Return to browse mode if selected DOM elements have
55201                 // disappeared because the user moved them out of view..
55202                 var source = event && event.type === 'zoom' && event.sourceEvent;
55203                 if (drawn && source && (source.type === 'mousemove' || source.type === 'touchmove')) {
55204                     context.enter(modeBrowse(context));
55205                 }
55206             } else {
55207                 selection$$1
55208                     .classed('selected', true);
55209             }
55210         }
55211
55212
55213         function esc() {
55214             context.enter(modeBrowse(context));
55215         }
55216
55217
55218         function firstVertex() {
55219             event.preventDefault();
55220             var parent = singularParent();
55221             if (parent) {
55222                 var way = context.entity(parent);
55223                 context.enter(
55224                     modeSelect(context, [way.first()]).follow(true)
55225                 );
55226             }
55227         }
55228
55229
55230         function lastVertex() {
55231             event.preventDefault();
55232             var parent = singularParent();
55233             if (parent) {
55234                 var way = context.entity(parent);
55235                 context.enter(
55236                     modeSelect(context, [way.last()]).follow(true)
55237                 );
55238             }
55239         }
55240
55241
55242         function previousVertex() {
55243             event.preventDefault();
55244             var parent = singularParent();
55245             if (!parent) return;
55246
55247             var way = context.entity(parent),
55248                 length = way.nodes.length,
55249                 curr = way.nodes.indexOf(selectedIDs[0]),
55250                 index = -1;
55251
55252             if (curr > 0) {
55253                 index = curr - 1;
55254             } else if (way.isClosed()) {
55255                 index = length - 2;
55256             }
55257
55258             if (index !== -1) {
55259                 context.enter(
55260                     modeSelect(context, [way.nodes[index]]).follow(true)
55261                 );
55262             }
55263         }
55264
55265
55266         function nextVertex() {
55267             event.preventDefault();
55268             var parent = singularParent();
55269             if (!parent) return;
55270
55271             var way = context.entity(parent),
55272                 length = way.nodes.length,
55273                 curr = way.nodes.indexOf(selectedIDs[0]),
55274                 index = -1;
55275
55276             if (curr < length - 1) {
55277                 index = curr + 1;
55278             } else if (way.isClosed()) {
55279                 index = 0;
55280             }
55281
55282             if (index !== -1) {
55283                 context.enter(
55284                     modeSelect(context, [way.nodes[index]]).follow(true)
55285                 );
55286             }
55287         }
55288
55289
55290         function nextParent() {
55291             event.preventDefault();
55292             var parents = lodash.uniq(commonParents());
55293             if (!parents || parents.length < 2) return;
55294
55295             var index = parents.indexOf(relatedParent);
55296             if (index < 0 || index > parents.length - 2) {
55297                 relatedParent = parents[0];
55298             } else {
55299                 relatedParent = parents[index + 1];
55300             }
55301
55302             var surface = context.surface();
55303             surface.selectAll('.related')
55304                 .classed('related', false);
55305
55306             if (relatedParent) {
55307                 surface.selectAll(utilEntitySelector([relatedParent]))
55308                     .classed('related', true);
55309             }
55310         }
55311
55312
55313         if (!checkSelectedIDs()) return;
55314
55315         var operations = lodash.without(values(Operations), operationDelete)
55316                 .map(function(o) { return o(selectedIDs, context); })
55317                 .filter(function(o) { return o.available(); });
55318
55319         // deprecation warning - Radial Menu to be removed in iD v3
55320         var isRadialMenu = context.storage('edit-menu-style') === 'radial';
55321         if (isRadialMenu) {
55322             operations = operations.slice(0,7);
55323             operations.unshift(operationDelete(selectedIDs, context));
55324         } else {
55325             operations.push(operationDelete(selectedIDs, context));
55326         }
55327
55328         operations.forEach(function(operation) {
55329             if (operation.behavior) {
55330                 behaviors.push(operation.behavior);
55331             }
55332         });
55333
55334         behaviors.forEach(function(behavior) {
55335             context.install(behavior);
55336         });
55337
55338         keybinding
55339             .on(['[', 'pgup'], previousVertex)
55340             .on([']', 'pgdown'], nextVertex)
55341             .on(['{', uiCmd('⌘['), 'home'], firstVertex)
55342             .on(['}', uiCmd('⌘]'), 'end'], lastVertex)
55343             .on(['\\', 'pause'], nextParent)
55344             .on('⎋', esc, true)
55345             .on('space', toggleMenu);
55346
55347         select(document)
55348             .call(keybinding);
55349
55350
55351         // deprecation warning - Radial Menu to be removed in iD v3
55352         editMenu = isRadialMenu
55353             ? uiRadialMenu(context, operations)
55354             : uiEditMenu(context, operations);
55355
55356         context.ui().sidebar
55357             .select(singular() ? singular().id : null, newFeature);
55358
55359         context.history()
55360             .on('undone.select', update)
55361             .on('redone.select', update);
55362
55363         context.map()
55364             .on('move.select', closeMenu)
55365             .on('drawn.select', selectElements);
55366
55367         context.surface()
55368             .on('dblclick.select', dblclick);
55369
55370
55371         selectElements();
55372
55373         if (selectedIDs.length > 1) {
55374             var entities = uiSelectionList(context, selectedIDs);
55375             context.ui().sidebar.show(entities);
55376         }
55377
55378         if (follow) {
55379             var extent$$1 = geoExtent$$1(),
55380                 graph = context.graph();
55381             selectedIDs.forEach(function(id) {
55382                 var entity = context.entity(id);
55383                 extent$$1._extend(entity.extent(graph));
55384             });
55385
55386             var loc = extent$$1.center();
55387             context.map().centerEase(loc);
55388         } else if (singular() && singular().type === 'way') {
55389             context.map().pan([0,0]);  // full redraw, to adjust z-sorting #2914
55390         }
55391
55392         timeout = window.setTimeout(function() {
55393             positionMenu();
55394             if (!suppressMenu) {
55395                 showMenu();
55396             }
55397         }, 270);  /* after any centerEase completes */
55398
55399     };
55400
55401
55402     mode.exit = function() {
55403         if (timeout) window.clearTimeout(timeout);
55404
55405         if (inspector) wrap.call(inspector.close);
55406
55407         behaviors.forEach(function(behavior) {
55408             context.uninstall(behavior);
55409         });
55410
55411         keybinding.off();
55412         closeMenu();
55413         editMenu = undefined;
55414
55415         context.history()
55416             .on('undone.select', null)
55417             .on('redone.select', null);
55418
55419         var surface = context.surface();
55420
55421         surface
55422             .on('dblclick.select', null);
55423
55424         surface
55425             .selectAll('.selected')
55426             .classed('selected', false);
55427
55428         surface
55429             .selectAll('.related')
55430             .classed('related', false);
55431
55432         context.map().on('drawn.select', null);
55433         context.ui().sidebar.hide();
55434     };
55435
55436
55437     return mode;
55438 }
55439
55440 function uiAccount(context) {
55441     var connection = context.connection();
55442
55443
55444     function update(selection$$1) {
55445         if (!connection.authenticated()) {
55446             selection$$1.selectAll('#userLink, #logoutLink')
55447                 .classed('hide', true);
55448             return;
55449         }
55450
55451         connection.userDetails(function(err, details) {
55452             var userLink = selection$$1.select('#userLink'),
55453                 logoutLink = selection$$1.select('#logoutLink');
55454
55455             userLink.html('');
55456             logoutLink.html('');
55457
55458             if (err) return;
55459
55460             selection$$1.selectAll('#userLink, #logoutLink')
55461                 .classed('hide', false);
55462
55463             // Link
55464             userLink.append('a')
55465                 .attr('href', connection.userURL(details.display_name))
55466                 .attr('target', '_blank');
55467
55468             // Add thumbnail or dont
55469             if (details.image_url) {
55470                 userLink.append('img')
55471                     .attr('class', 'icon pre-text user-icon')
55472                     .attr('src', details.image_url);
55473             } else {
55474                 userLink
55475                     .call(svgIcon('#icon-avatar', 'pre-text light'));
55476             }
55477
55478             // Add user name
55479             userLink.append('span')
55480                 .attr('class', 'label')
55481                 .text(details.display_name);
55482
55483             logoutLink.append('a')
55484                 .attr('class', 'logout')
55485                 .attr('href', '#')
55486                 .text(t('logout'))
55487                 .on('click.logout', function() {
55488                     event.preventDefault();
55489                     connection.logout();
55490                 });
55491         });
55492     }
55493
55494
55495     return function(selection$$1) {
55496         selection$$1.append('li')
55497             .attr('id', 'logoutLink')
55498             .classed('hide', true);
55499
55500         selection$$1.append('li')
55501             .attr('id', 'userLink')
55502             .classed('hide', true);
55503
55504         connection
55505             .on('change.account', function() { update(selection$$1); });
55506
55507         update(selection$$1);
55508     };
55509 }
55510
55511 function uiAttribution(context) {
55512     var selection$$1;
55513
55514
55515     function attribution(data, klass) {
55516         var div = selection$$1.selectAll('.' + klass)
55517             .data([0]);
55518
55519         div = div.enter()
55520             .append('div')
55521             .attr('class', klass)
55522             .merge(div);
55523
55524
55525         var background = div.selectAll('.attribution')
55526             .data(data, function(d) { return d.name(); });
55527
55528         background.exit()
55529             .remove();
55530
55531         background = background.enter()
55532             .append('span')
55533             .attr('class', 'attribution')
55534             .each(function(d) {
55535                 if (d.terms_html) {
55536                     select(this)
55537                         .html(d.terms_html);
55538                     return;
55539                 }
55540
55541                 var selection$$1;
55542                 if (d.terms_url) {
55543                     selection$$1 = select(this)
55544                         .append('a')
55545                         .attr('href', d.terms_url)
55546                         .attr('target', '_blank');
55547                 } else {
55548                     selection$$1 = select(this);
55549                 }
55550
55551
55552                 var id_safe = d.id.replace('.', '<TX_DOT>');
55553                 var terms_text = t('imagery.' + id_safe + '.attribution.text',
55554                     { default: d.terms_text || d.id || d.name() }
55555                 );
55556
55557                 if (d.icon && !d.overlay) {
55558                     selection$$1
55559                         .append('img')
55560                         .attr('class', 'source-image')
55561                         .attr('src', d.icon);
55562                 }
55563
55564                 selection$$1
55565                     .append('span')
55566                     .attr('class', 'attribution-text')
55567                     .text(terms_text);
55568             })
55569             .merge(background);
55570
55571
55572         var copyright = background.selectAll('.copyright-notice')
55573             .data(function(d) {
55574                 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
55575                 return notice ? [notice] : [];
55576             });
55577
55578         copyright.exit()
55579             .remove();
55580
55581         copyright = copyright.enter()
55582             .append('span')
55583             .attr('class', 'copyright-notice')
55584             .merge(copyright);
55585
55586         copyright
55587             .text(String);
55588     }
55589
55590
55591     function update() {
55592         attribution([context.background().baseLayerSource()], 'base-layer-attribution');
55593         attribution(context.background().overlayLayerSources().filter(function (s) {
55594             return s.validZoom(context.map().zoom());
55595         }), 'overlay-layer-attribution');
55596     }
55597
55598
55599     return function(select$$1) {
55600         selection$$1 = select$$1;
55601
55602         context.background()
55603             .on('change.attribution', update);
55604
55605         context.map()
55606             .on('move.attribution', lodash.throttle(update, 400, {leading: false}));
55607
55608         update();
55609     };
55610 }
55611
55612 function localeDateString(s) {
55613     if (!s) return null;
55614     var d = new Date(s);
55615     if (isNaN(d.getTime())) return null;
55616     return d.toLocaleDateString();
55617 }
55618
55619 function vintageRange(vintage) {
55620     var s;
55621     if (vintage.start || vintage.end) {
55622         s = (vintage.start || '?');
55623         if (vintage.start !== vintage.end) {
55624             s += ' - ' + (vintage.end || '?');
55625         }
55626     }
55627     return s;
55628 }
55629
55630
55631 function rendererBackgroundSource(data) {
55632     var source = lodash.clone(data),
55633         offset = [0, 0],
55634         name = source.name,
55635         description = source.description,
55636         best = !!source.best,
55637         template = source.template;
55638
55639     source.scaleExtent = data.scaleExtent || [0, 20];
55640     source.overzoom = data.overzoom !== false;
55641
55642
55643     source.offset = function(_) {
55644         if (!arguments.length) return offset;
55645         offset = _;
55646         return source;
55647     };
55648
55649
55650     source.nudge = function(_, zoomlevel) {
55651         offset[0] += _[0] / Math.pow(2, zoomlevel);
55652         offset[1] += _[1] / Math.pow(2, zoomlevel);
55653         return source;
55654     };
55655
55656
55657     source.name = function() {
55658         var id_safe = source.id.replace('.', '<TX_DOT>');
55659         return t('imagery.' + id_safe + '.name', { default: name });
55660     };
55661
55662
55663     source.description = function() {
55664         var id_safe = source.id.replace('.', '<TX_DOT>');
55665         return t('imagery.' + id_safe + '.description', { default: description });
55666     };
55667
55668
55669     source.best = function() {
55670         return best;
55671     };
55672
55673
55674     source.area = function() {
55675         if (!data.polygon) return Number.MAX_VALUE;  // worldwide
55676         var area$$1 = area({ type: 'MultiPolygon', coordinates: [ data.polygon ] });
55677         return isNaN(area$$1) ? 0 : area$$1;
55678     };
55679
55680
55681     source.imageryUsed = function() {
55682         return name || source.id;
55683     };
55684
55685
55686     source.template = function(_) {
55687         if (!arguments.length) return template;
55688         if (source.id === 'custom') template = _;
55689         return source;
55690     };
55691
55692
55693     source.url = function(coord) {
55694         return template
55695             .replace('{x}', coord[0])
55696             .replace('{y}', coord[1])
55697             // TMS-flipped y coordinate
55698             .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
55699             .replace(/\{z(oom)?\}/, coord[2])
55700             .replace(/\{switch:([^}]+)\}/, function(s, r) {
55701                 var subdomains = r.split(',');
55702                 return subdomains[(coord[0] + coord[1]) % subdomains.length];
55703             })
55704             .replace('{u}', function() {
55705                 var u = '';
55706                 for (var zoom$$1 = coord[2]; zoom$$1 > 0; zoom$$1--) {
55707                     var b = 0;
55708                     var mask = 1 << (zoom$$1 - 1);
55709                     if ((coord[0] & mask) !== 0) b++;
55710                     if ((coord[1] & mask) !== 0) b += 2;
55711                     u += b.toString();
55712                 }
55713                 return u;
55714             });
55715     };
55716
55717
55718     source.intersects = function(extent$$1) {
55719         extent$$1 = extent$$1.polygon();
55720         return !data.polygon || data.polygon.some(function(polygon) {
55721             return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
55722         });
55723     };
55724
55725
55726     source.validZoom = function(z) {
55727         return source.scaleExtent[0] <= z &&
55728             (source.overzoom || source.scaleExtent[1] > z);
55729     };
55730
55731
55732     source.isLocatorOverlay = function() {
55733         return source.id === 'mapbox_locator_overlay';
55734     };
55735
55736
55737     source.copyrightNotices = function() {};
55738
55739
55740     source.getVintage = function(center, tileCoord, callback) {
55741         var vintage = {
55742             start: localeDateString(source.startDate),
55743             end: localeDateString(source.endDate)
55744         };
55745         vintage.range = vintageRange(vintage);
55746         callback(null, vintage);
55747     };
55748
55749
55750     return source;
55751 }
55752
55753
55754 rendererBackgroundSource.Bing = function(data, dispatch$$1) {
55755     // http://msdn.microsoft.com/en-us/library/ff701716.aspx
55756     // http://msdn.microsoft.com/en-us/library/ff701701.aspx
55757
55758     data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
55759
55760     var bing = rendererBackgroundSource(data),
55761         key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
55762         url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
55763             key + '&jsonp={callback}',
55764         cache = {},
55765         providers = [];
55766
55767     jsonpRequest(url, function(json$$1) {
55768         providers = json$$1.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
55769             return {
55770                 attribution: provider.attribution,
55771                 areas: provider.coverageAreas.map(function(area$$1) {
55772                     return {
55773                         zoom: [area$$1.zoomMin, area$$1.zoomMax],
55774                         extent: geoExtent$$1([area$$1.bbox[1], area$$1.bbox[0]], [area$$1.bbox[3], area$$1.bbox[2]])
55775                     };
55776                 })
55777             };
55778         });
55779         dispatch$$1.call('change');
55780     });
55781
55782
55783     bing.copyrightNotices = function(zoom$$1, extent$$1) {
55784         zoom$$1 = Math.min(zoom$$1, 21);
55785         return providers.filter(function(provider) {
55786             return lodash.some(provider.areas, function(area$$1) {
55787                 return extent$$1.intersects(area$$1.extent) &&
55788                     area$$1.zoom[0] <= zoom$$1 &&
55789                     area$$1.zoom[1] >= zoom$$1;
55790             });
55791         }).map(function(provider) {
55792             return provider.attribution;
55793         }).join(', ');
55794     };
55795
55796
55797     bing.getVintage = function(center, tileCoord, callback) {
55798         var tileId = tileCoord.slice(0, 3).join('/'),
55799             zoom$$1 = Math.min(tileCoord[2], 21),
55800             centerPoint = center[1] + ',' + center[0],  // lat,lng
55801             url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint +
55802                 '?zl=' + zoom$$1 + '&key=' + key + '&jsonp={callback}';
55803
55804         if (!cache[tileId]) {
55805             cache[tileId] = {};
55806         }
55807         if (cache[tileId] && cache[tileId].vintage) {
55808             return callback(null, cache[tileId].vintage);
55809         }
55810
55811         jsonpRequest(url, function(result) {
55812             var err = (!result && 'Unknown Error') || result.errorDetails;
55813             if (err) {
55814                 return callback(err);
55815             } else {
55816                 var vintage = {
55817                     start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
55818                     end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
55819                 };
55820                 vintage.range = vintageRange(vintage);
55821                 cache[tileId].vintage = vintage;
55822                 return callback(null, vintage);
55823             }
55824         });
55825     };
55826
55827
55828     bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
55829
55830
55831     return bing;
55832 };
55833
55834
55835 rendererBackgroundSource.None = function() {
55836     var source = rendererBackgroundSource({ id: 'none', template: '' });
55837
55838
55839     source.name = function() {
55840         return t('background.none');
55841     };
55842
55843
55844     source.imageryUsed = function() {
55845         return 'None';
55846     };
55847
55848
55849     source.area = function() {
55850         return -1;  // sources in background pane are sorted by area
55851     };
55852
55853
55854     return source;
55855 };
55856
55857
55858 rendererBackgroundSource.Custom = function(template) {
55859     var source = rendererBackgroundSource({ id: 'custom', template: template });
55860
55861
55862     source.name = function() {
55863         return t('background.custom');
55864     };
55865
55866
55867     source.imageryUsed = function() {
55868         return 'Custom (' + source.template() + ')';
55869     };
55870
55871
55872     source.area = function() {
55873         return -2;  // sources in background pane are sorted by area
55874     };
55875
55876
55877     return source;
55878 };
55879
55880 function rendererTileLayer(context) {
55881     var tileSize = 256,
55882         tile = d3geoTile(),
55883         projection$$1,
55884         cache = {},
55885         tileOrigin,
55886         z,
55887         transformProp = utilPrefixCSSProperty('Transform'),
55888         source;
55889
55890
55891     // blacklist overlay tiles around Null Island..
55892     function nearNullIsland(x, y, z) {
55893         if (z >= 7) {
55894             var center = Math.pow(2, z - 1),
55895                 width = Math.pow(2, z - 6),
55896                 min$$1 = center - (width / 2),
55897                 max$$1 = center + (width / 2) - 1;
55898             return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
55899         }
55900         return false;
55901     }
55902
55903
55904     function tileSizeAtZoom(d, z) {
55905         var epsilon = 0.002;
55906         return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
55907     }
55908
55909
55910     function atZoom(t$$1, distance$$1) {
55911         var power = Math.pow(2, distance$$1);
55912         return [
55913             Math.floor(t$$1[0] * power),
55914             Math.floor(t$$1[1] * power),
55915             t$$1[2] + distance$$1];
55916     }
55917
55918
55919     function lookUp(d) {
55920         for (var up = -1; up > -d[2]; up--) {
55921             var tile = atZoom(d, up);
55922             if (cache[source.url(tile)] !== false) {
55923                 return tile;
55924             }
55925         }
55926     }
55927
55928
55929     function uniqueBy(a, n) {
55930         var o = [], seen = {};
55931         for (var i = 0; i < a.length; i++) {
55932             if (seen[a[i][n]] === undefined) {
55933                 o.push(a[i]);
55934                 seen[a[i][n]] = true;
55935             }
55936         }
55937         return o;
55938     }
55939
55940
55941     function addSource(d) {
55942         d.push(source.url(d));
55943         return d;
55944     }
55945
55946
55947     // Update tiles based on current state of `projection`.
55948     function background(selection$$1) {
55949         tile.scale(projection$$1.scale() * 2 * Math.PI)
55950             .translate(projection$$1.translate());
55951
55952         tileOrigin = [
55953             projection$$1.scale() * Math.PI - projection$$1.translate()[0],
55954             projection$$1.scale() * Math.PI - projection$$1.translate()[1]];
55955
55956         z = Math.max(Math.log(projection$$1.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
55957
55958         render(selection$$1);
55959     }
55960
55961
55962     // Derive the tiles onscreen, remove those offscreen and position them.
55963     // Important that this part not depend on `projection` because it's
55964     // rentered when tiles load/error (see #644).
55965     function render(selection$$1) {
55966         if (!source) return;
55967         var requests = [];
55968         var showDebug = context.getDebug('tile') && !source.overlay;
55969
55970         if (source.validZoom(z)) {
55971             tile().forEach(function(d) {
55972                 addSource(d);
55973                 if (d[3] === '') return;
55974                 if (typeof d[3] !== 'string') return; // Workaround for #2295
55975                 requests.push(d);
55976                 if (cache[d[3]] === false && lookUp(d)) {
55977                     requests.push(addSource(lookUp(d)));
55978                 }
55979             });
55980
55981             requests = uniqueBy(requests, 3).filter(function(r) {
55982                 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
55983                     return false;
55984                 }
55985                 // don't re-request tiles which have failed in the past
55986                 return cache[r[3]] !== false;
55987             });
55988         }
55989
55990         var pixelOffset = [
55991             source.offset()[0] * Math.pow(2, z),
55992             source.offset()[1] * Math.pow(2, z)
55993         ];
55994
55995
55996         function load(d) {
55997             cache[d[3]] = true;
55998             select(this)
55999                 .on('error', null)
56000                 .on('load', null)
56001                 .classed('tile-loaded', true);
56002             render(selection$$1);
56003         }
56004
56005         function error(d) {
56006             cache[d[3]] = false;
56007             select(this)
56008                 .on('error', null)
56009                 .on('load', null)
56010                 .remove();
56011             render(selection$$1);
56012         }
56013
56014         function imageTransform(d) {
56015             var _ts = tileSize * Math.pow(2, z - d[2]);
56016             var scale = tileSizeAtZoom(d, z);
56017             return 'translate(' +
56018                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
56019                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
56020                 'scale(' + scale + ',' + scale + ')';
56021         }
56022
56023         function tileCenter(d) {
56024             var _ts = tileSize * Math.pow(2, z - d[2]);
56025             return [
56026                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + (_ts / 2)),
56027                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + (_ts / 2))
56028             ];
56029         }
56030
56031         function debugTransform(d) {
56032             var coord = tileCenter(d);
56033             return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
56034         }
56035
56036
56037         // Pick a representative tile near the center of the viewport
56038         // (This is useful for sampling the imagery vintage)
56039         var dims = tile.size(),
56040             mapCenter = [dims[0] / 2, dims[1] / 2],
56041             minDist = Math.max(dims[0], dims[1]),
56042             nearCenter;
56043
56044         requests.forEach(function(d) {
56045             var c = tileCenter(d);
56046             var dist = geoEuclideanDistance(c, mapCenter);
56047             if (dist < minDist) {
56048                 minDist = dist;
56049                 nearCenter = d;
56050             }
56051         });
56052
56053
56054         var image = selection$$1.selectAll('img')
56055             .data(requests, function(d) { return d[3]; });
56056
56057         image.exit()
56058             .style(transformProp, imageTransform)
56059             .classed('tile-removing', true)
56060             .classed('tile-center', false)
56061             .each(function() {
56062                 var tile = select(this);
56063                 window.setTimeout(function() {
56064                     if (tile.classed('tile-removing')) {
56065                         tile.remove();
56066                     }
56067                 }, 300);
56068             });
56069
56070         image.enter()
56071           .append('img')
56072             .attr('class', 'tile')
56073             .attr('src', function(d) { return d[3]; })
56074             .on('error', error)
56075             .on('load', load)
56076           .merge(image)
56077             .style(transformProp, imageTransform)
56078             .classed('tile-debug', showDebug)
56079             .classed('tile-removing', false)
56080             .classed('tile-center', function(d) { return d === nearCenter; });
56081
56082
56083
56084         var debug = selection$$1.selectAll('.tile-label-debug')
56085             .data(showDebug ? requests : [], function(d) { return d[3]; });
56086
56087         debug.exit()
56088             .remove();
56089
56090         if (showDebug) {
56091             var debugEnter = debug.enter()
56092                 .append('div')
56093                 .attr('class', 'tile-label-debug');
56094
56095             debugEnter
56096                 .append('div')
56097                 .attr('class', 'tile-label-debug-coord');
56098
56099             debugEnter
56100                 .append('div')
56101                 .attr('class', 'tile-label-debug-vintage');
56102
56103             debug = debug.merge(debugEnter);
56104
56105             debug
56106                 .style(transformProp, debugTransform);
56107
56108             debug
56109                 .selectAll('.tile-label-debug-coord')
56110                 .text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; });
56111
56112             debug
56113                 .selectAll('.tile-label-debug-vintage')
56114                 .each(function(d) {
56115                     var span = select(this);
56116                     var center = context.projection.invert(tileCenter(d));
56117                     source.getVintage(center, d, function(err, result) {
56118                         span.text((result && result.range) ||
56119                             t('info_panels.background.vintage') + ': ' + t('info_panels.background.unknown')
56120                         );
56121                     });
56122                 });
56123         }
56124
56125     }
56126
56127
56128     background.projection = function(_) {
56129         if (!arguments.length) return projection$$1;
56130         projection$$1 = _;
56131         return background;
56132     };
56133
56134
56135     background.dimensions = function(_) {
56136         if (!arguments.length) return tile.size();
56137         tile.size(_);
56138         return background;
56139     };
56140
56141
56142     background.source = function(_) {
56143         if (!arguments.length) return source;
56144         source = _;
56145         cache = {};
56146         tile.scaleExtent(source.scaleExtent);
56147         return background;
56148     };
56149
56150
56151     return background;
56152 }
56153
56154 function rendererBackground(context) {
56155     var dispatch$$1 = dispatch('change'),
56156         baseLayer = rendererTileLayer(context).projection(context.projection),
56157         overlayLayers = [],
56158         backgroundSources;
56159
56160
56161     function background(selection$$1) {
56162         var base = selection$$1.selectAll('.layer-background')
56163             .data([0]);
56164
56165         base.enter()
56166             .insert('div', '.layer-data')
56167             .attr('class', 'layer layer-background')
56168             .merge(base)
56169             .call(baseLayer);
56170
56171         var overlays = selection$$1.selectAll('.layer-overlay')
56172             .data(overlayLayers, function(d) { return d.source().name(); });
56173
56174         overlays.exit()
56175             .remove();
56176
56177         overlays.enter()
56178             .insert('div', '.layer-data')
56179             .attr('class', 'layer layer-overlay')
56180             .merge(overlays)
56181             .each(function(layer) { select(this).call(layer); });
56182     }
56183
56184
56185     background.updateImagery = function() {
56186         if (context.inIntro()) return;
56187
56188         var b = background.baseLayerSource(),
56189             o = overlayLayers
56190                 .filter(function (d) { return !d.source().isLocatorOverlay(); })
56191                 .map(function (d) { return d.source().id; })
56192                 .join(','),
56193             meters = geoOffsetToMeters(b.offset()),
56194             epsilon = 0.01,
56195             x = +meters[0].toFixed(2),
56196             y = +meters[1].toFixed(2),
56197             q = utilStringQs(window.location.hash.substring(1));
56198
56199         var id = b.id;
56200         if (id === 'custom') {
56201             id = 'custom:' + b.template();
56202         }
56203
56204         if (id) {
56205             q.background = id;
56206         } else {
56207             delete q.background;
56208         }
56209
56210         if (o) {
56211             q.overlays = o;
56212         } else {
56213             delete q.overlays;
56214         }
56215
56216         if (Math.abs(x) > epsilon || Math.abs(y) > epsilon) {
56217             q.offset = x + ',' + y;
56218         } else {
56219             delete q.offset;
56220         }
56221
56222         window.location.replace('#' + utilQsString(q, true));
56223
56224         var imageryUsed = [b.imageryUsed()];
56225
56226         overlayLayers
56227             .filter(function (d) { return !d.source().isLocatorOverlay(); })
56228             .forEach(function (d) { imageryUsed.push(d.source().imageryUsed()); });
56229
56230         var gpx = context.layers().layer('gpx');
56231         if (gpx && gpx.enabled() && gpx.hasGpx()) {
56232             imageryUsed.push('Local GPX');
56233         }
56234
56235         var mapillary_images = context.layers().layer('mapillary-images');
56236         if (mapillary_images && mapillary_images.enabled()) {
56237             imageryUsed.push('Mapillary Images');
56238         }
56239
56240         var mapillary_signs = context.layers().layer('mapillary-signs');
56241         if (mapillary_signs && mapillary_signs.enabled()) {
56242             imageryUsed.push('Mapillary Signs');
56243         }
56244
56245         context.history().imageryUsed(imageryUsed);
56246     };
56247
56248
56249     background.sources = function(extent$$1) {
56250         return backgroundSources.filter(function(source) {
56251             return source.intersects(extent$$1);
56252         });
56253     };
56254
56255
56256     background.dimensions = function(_) {
56257         if (!_) return;
56258         baseLayer.dimensions(_);
56259
56260         overlayLayers.forEach(function(layer) {
56261             layer.dimensions(_);
56262         });
56263     };
56264
56265
56266     background.baseLayerSource = function(d) {
56267         if (!arguments.length) return baseLayer.source();
56268
56269         // test source against OSM imagery blacklists..
56270         var blacklists = context.connection().imageryBlacklists();
56271
56272         var template = d.template(),
56273             fail = false,
56274             tested = 0,
56275             regex, i;
56276
56277         for (i = 0; i < blacklists.length; i++) {
56278             try {
56279                 regex = new RegExp(blacklists[i]);
56280                 fail = regex.test(template);
56281                 tested++;
56282                 if (fail) break;
56283             } catch (e) {
56284                 /* noop */
56285             }
56286         }
56287
56288         // ensure at least one test was run.
56289         if (!tested) {
56290             regex = new RegExp('.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*');
56291             fail = regex.test(template);
56292         }
56293
56294         baseLayer.source(!fail ? d : background.findSource('none'));
56295         dispatch$$1.call('change');
56296         background.updateImagery();
56297         return background;
56298     };
56299
56300
56301     background.findSource = function(id) {
56302         return lodash.find(backgroundSources, function(d) {
56303             return d.id && d.id === id;
56304         });
56305     };
56306
56307
56308     background.bing = function() {
56309         background.baseLayerSource(background.findSource('Bing'));
56310     };
56311
56312
56313     background.showsLayer = function(d) {
56314         return d.id === baseLayer.source().id ||
56315             overlayLayers.some(function(layer) { return d.id === layer.source().id; });
56316     };
56317
56318
56319     background.overlayLayerSources = function() {
56320         return overlayLayers.map(function (l) { return l.source(); });
56321     };
56322
56323
56324     background.toggleOverlayLayer = function(d) {
56325         var layer;
56326
56327         for (var i = 0; i < overlayLayers.length; i++) {
56328             layer = overlayLayers[i];
56329             if (layer.source() === d) {
56330                 overlayLayers.splice(i, 1);
56331                 dispatch$$1.call('change');
56332                 background.updateImagery();
56333                 return;
56334             }
56335         }
56336
56337         layer = rendererTileLayer(context)
56338             .source(d)
56339             .projection(context.projection)
56340             .dimensions(baseLayer.dimensions());
56341
56342         overlayLayers.push(layer);
56343         dispatch$$1.call('change');
56344         background.updateImagery();
56345     };
56346
56347
56348     background.nudge = function(d, zoom$$1) {
56349         baseLayer.source().nudge(d, zoom$$1);
56350         dispatch$$1.call('change');
56351         background.updateImagery();
56352         return background;
56353     };
56354
56355
56356     background.offset = function(d) {
56357         if (!arguments.length) return baseLayer.source().offset();
56358         baseLayer.source().offset(d);
56359         dispatch$$1.call('change');
56360         background.updateImagery();
56361         return background;
56362     };
56363
56364
56365     background.init = function() {
56366         function parseMap(qmap) {
56367             if (!qmap) return false;
56368             var args = qmap.split('/').map(Number);
56369             if (args.length < 3 || args.some(isNaN)) return false;
56370             return geoExtent$$1([args[2], args[1]]);
56371         }
56372
56373         var dataImagery = data.imagery || [],
56374             q = utilStringQs(window.location.hash.substring(1)),
56375             requested = q.background || q.layer,
56376             extent$$1 = parseMap(q.map),
56377             first,
56378             best;
56379
56380         // Add all the available imagery sources
56381         backgroundSources = dataImagery.map(function(source) {
56382             if (source.type === 'bing') {
56383                 return rendererBackgroundSource.Bing(source, dispatch$$1);
56384             } else {
56385                 return rendererBackgroundSource(source);
56386             }
56387         });
56388
56389         first = backgroundSources.length && backgroundSources[0];
56390
56391         // Add 'None'
56392         backgroundSources.unshift(rendererBackgroundSource.None());
56393
56394         // Add 'Custom'
56395         var template = context.storage('background-custom-template') || '';
56396         var custom = rendererBackgroundSource.Custom(template);
56397         backgroundSources.unshift(custom);
56398
56399
56400         // Decide which background layer to display
56401         if (!requested && extent$$1) {
56402             best = lodash.find(this.sources(extent$$1), function(s) { return s.best(); });
56403         }
56404         if (requested && requested.indexOf('custom:') === 0) {
56405             template = requested.replace(/^custom:/, '');
56406             background.baseLayerSource(custom.template(template));
56407             context.storage('background-custom-template', template);
56408         } else {
56409             background.baseLayerSource(
56410                 background.findSource(requested) ||
56411                 best ||
56412                 background.findSource('Bing') ||
56413                 first ||
56414                 background.findSource('none')
56415             );
56416         }
56417
56418         var locator = lodash.find(backgroundSources, function(d) {
56419             return d.overlay && d.default;
56420         });
56421
56422         if (locator) {
56423             background.toggleOverlayLayer(locator);
56424         }
56425
56426         var overlays = (q.overlays || '').split(',');
56427         overlays.forEach(function(overlay) {
56428             overlay = background.findSource(overlay);
56429             if (overlay) {
56430                 background.toggleOverlayLayer(overlay);
56431             }
56432         });
56433
56434         if (q.gpx) {
56435             var gpx = context.layers().layer('gpx');
56436             if (gpx) {
56437                 gpx.url(q.gpx);
56438             }
56439         }
56440
56441         if (q.offset) {
56442             var offset = q.offset.replace(/;/g, ',').split(',').map(function(n) {
56443                 return !isNaN(n) && n;
56444             });
56445
56446             if (offset.length === 2) {
56447                 background.offset(geoMetersToOffset(offset));
56448             }
56449         }
56450     };
56451
56452
56453     return utilRebind(background, dispatch$$1, 'on');
56454 }
56455
56456 function rendererFeatures(context) {
56457     var traffic_roads = {
56458         'motorway': true,
56459         'motorway_link': true,
56460         'trunk': true,
56461         'trunk_link': true,
56462         'primary': true,
56463         'primary_link': true,
56464         'secondary': true,
56465         'secondary_link': true,
56466         'tertiary': true,
56467         'tertiary_link': true,
56468         'residential': true,
56469         'unclassified': true,
56470         'living_street': true
56471     };
56472
56473     var service_roads = {
56474         'service': true,
56475         'road': true,
56476         'track': true
56477     };
56478
56479     var paths = {
56480         'path': true,
56481         'footway': true,
56482         'cycleway': true,
56483         'bridleway': true,
56484         'steps': true,
56485         'pedestrian': true,
56486         'corridor': true
56487     };
56488
56489     var past_futures = {
56490         'proposed': true,
56491         'construction': true,
56492         'abandoned': true,
56493         'dismantled': true,
56494         'disused': true,
56495         'razed': true,
56496         'demolished': true,
56497         'obliterated': true
56498     };
56499
56500     var dispatch$$1 = dispatch('change', 'redraw'),
56501         _cullFactor = 1,
56502         _cache = {},
56503         _features = {},
56504         _stats = {},
56505         _keys = [],
56506         _hidden = [];
56507
56508
56509     function update() {
56510         _hidden = features.hidden();
56511         dispatch$$1.call('change');
56512         dispatch$$1.call('redraw');
56513     }
56514
56515
56516     function defineFeature(k, filter, max$$1) {
56517         _keys.push(k);
56518         _features[k] = {
56519             filter: filter,
56520             enabled: true,   // whether the user wants it enabled..
56521             count: 0,
56522             currentMax: (max$$1 || Infinity),
56523             defaultMax: (max$$1 || Infinity),
56524             enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
56525             disable: function() { this.enabled = false; this.currentMax = 0; },
56526             hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
56527             autoHidden: function() { return this.hidden() && this.currentMax > 0; }
56528         };
56529     }
56530
56531
56532     defineFeature('points', function isPoint(entity, resolver, geometry) {
56533         return geometry === 'point';
56534     }, 200);
56535
56536     defineFeature('traffic_roads', function isTrafficRoad(entity) {
56537         return traffic_roads[entity.tags.highway];
56538     });
56539
56540     defineFeature('service_roads', function isServiceRoad(entity) {
56541         return service_roads[entity.tags.highway];
56542     });
56543
56544     defineFeature('paths', function isPath(entity) {
56545         return paths[entity.tags.highway];
56546     });
56547
56548     defineFeature('buildings', function isBuilding(entity) {
56549         return (
56550             !!entity.tags['building:part'] ||
56551             (!!entity.tags.building && entity.tags.building !== 'no') ||
56552             entity.tags.amenity === 'shelter' ||
56553             entity.tags.parking === 'multi-storey' ||
56554             entity.tags.parking === 'sheds' ||
56555             entity.tags.parking === 'carports' ||
56556             entity.tags.parking === 'garage_boxes'
56557         );
56558     }, 250);
56559
56560     defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
56561         return geometry === 'area' &&
56562             !_features.buildings.filter(entity) &&
56563             !_features.water.filter(entity);
56564     });
56565
56566     defineFeature('boundaries', function isBoundary(entity) {
56567         return !!entity.tags.boundary;
56568     });
56569
56570     defineFeature('water', function isWater(entity) {
56571         return (
56572             !!entity.tags.waterway ||
56573             entity.tags.natural === 'water' ||
56574             entity.tags.natural === 'coastline' ||
56575             entity.tags.natural === 'bay' ||
56576             entity.tags.landuse === 'pond' ||
56577             entity.tags.landuse === 'basin' ||
56578             entity.tags.landuse === 'reservoir' ||
56579             entity.tags.landuse === 'salt_pond'
56580         );
56581     });
56582
56583     defineFeature('rail', function isRail(entity) {
56584         return (
56585             !!entity.tags.railway ||
56586             entity.tags.landuse === 'railway'
56587         ) && !(
56588             traffic_roads[entity.tags.highway] ||
56589             service_roads[entity.tags.highway] ||
56590             paths[entity.tags.highway]
56591         );
56592     });
56593
56594     defineFeature('power', function isPower(entity) {
56595         return !!entity.tags.power;
56596     });
56597
56598     // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
56599     defineFeature('past_future', function isPastFuture(entity) {
56600         if (
56601             traffic_roads[entity.tags.highway] ||
56602             service_roads[entity.tags.highway] ||
56603             paths[entity.tags.highway]
56604         ) { return false; }
56605
56606         var strings = Object.keys(entity.tags);
56607
56608         for (var i = 0; i < strings.length; i++) {
56609             var s = strings[i];
56610             if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
56611         }
56612         return false;
56613     });
56614
56615     // Lines or areas that don't match another feature filter.
56616     // IMPORTANT: The 'others' feature must be the last one defined,
56617     //   so that code in getMatches can skip this test if `hasMatch = true`
56618     defineFeature('others', function isOther(entity, resolver, geometry) {
56619         return (geometry === 'line' || geometry === 'area');
56620     });
56621
56622
56623     function features() {}
56624
56625
56626     features.features = function() {
56627         return _features;
56628     };
56629
56630
56631     features.keys = function() {
56632         return _keys;
56633     };
56634
56635
56636     features.enabled = function(k) {
56637         if (!arguments.length) {
56638             return _keys.filter(function(k) { return _features[k].enabled; });
56639         }
56640         return _features[k] && _features[k].enabled;
56641     };
56642
56643
56644     features.disabled = function(k) {
56645         if (!arguments.length) {
56646             return _keys.filter(function(k) { return !_features[k].enabled; });
56647         }
56648         return _features[k] && !_features[k].enabled;
56649     };
56650
56651
56652     features.hidden = function(k) {
56653         if (!arguments.length) {
56654             return _keys.filter(function(k) { return _features[k].hidden(); });
56655         }
56656         return _features[k] && _features[k].hidden();
56657     };
56658
56659
56660     features.autoHidden = function(k) {
56661         if (!arguments.length) {
56662             return _keys.filter(function(k) { return _features[k].autoHidden(); });
56663         }
56664         return _features[k] && _features[k].autoHidden();
56665     };
56666
56667
56668     features.enable = function(k) {
56669         if (_features[k] && !_features[k].enabled) {
56670             _features[k].enable();
56671             update();
56672         }
56673     };
56674
56675
56676     features.disable = function(k) {
56677         if (_features[k] && _features[k].enabled) {
56678             _features[k].disable();
56679             update();
56680         }
56681     };
56682
56683
56684     features.toggle = function(k) {
56685         if (_features[k]) {
56686             (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
56687             update();
56688         }
56689     };
56690
56691
56692     features.resetStats = function() {
56693         for (var i = 0; i < _keys.length; i++) {
56694             _features[_keys[i]].count = 0;
56695         }
56696         dispatch$$1.call('change');
56697     };
56698
56699
56700     features.gatherStats = function(d, resolver, dimensions) {
56701         var needsRedraw = false,
56702             type = lodash.groupBy(d, function(ent) { return ent.type; }),
56703             entities = [].concat(type.relation || [], type.way || [], type.node || []),
56704             currHidden, geometry, matches, i, j;
56705
56706         for (i = 0; i < _keys.length; i++) {
56707             _features[_keys[i]].count = 0;
56708         }
56709
56710         // adjust the threshold for point/building culling based on viewport size..
56711         // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
56712         _cullFactor = dimensions[0] * dimensions[1] / 1000000;
56713
56714         for (i = 0; i < entities.length; i++) {
56715             geometry = entities[i].geometry(resolver);
56716             if (!(geometry === 'vertex' || geometry === 'relation')) {
56717                 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
56718                 for (j = 0; j < matches.length; j++) {
56719                     _features[matches[j]].count++;
56720                 }
56721             }
56722         }
56723
56724         currHidden = features.hidden();
56725         if (currHidden !== _hidden) {
56726             _hidden = currHidden;
56727             needsRedraw = true;
56728             dispatch$$1.call('change');
56729         }
56730
56731         return needsRedraw;
56732     };
56733
56734
56735     features.stats = function() {
56736         for (var i = 0; i < _keys.length; i++) {
56737             _stats[_keys[i]] = _features[_keys[i]].count;
56738         }
56739
56740         return _stats;
56741     };
56742
56743
56744     features.clear = function(d) {
56745         for (var i = 0; i < d.length; i++) {
56746             features.clearEntity(d[i]);
56747         }
56748     };
56749
56750
56751     features.clearEntity = function(entity) {
56752         delete _cache[osmEntity$$1.key(entity)];
56753     };
56754
56755
56756     features.reset = function() {
56757         _cache = {};
56758     };
56759
56760
56761     features.getMatches = function(entity, resolver, geometry) {
56762         if (geometry === 'vertex' || geometry === 'relation') return {};
56763
56764         var ent = osmEntity$$1.key(entity);
56765         if (!_cache[ent]) {
56766             _cache[ent] = {};
56767         }
56768
56769         if (!_cache[ent].matches) {
56770             var matches = {},
56771                 hasMatch = false;
56772
56773             for (var i = 0; i < _keys.length; i++) {
56774                 if (_keys[i] === 'others') {
56775                     if (hasMatch) continue;
56776
56777                     // Multipolygon members:
56778                     // If an entity...
56779                     //   1. is a way that hasn't matched other 'interesting' feature rules,
56780                     //   2. and it belongs to a single parent multipolygon relation
56781                     // ...then match whatever feature rules the parent multipolygon has matched.
56782                     // see #2548, #2887
56783                     //
56784                     // IMPORTANT:
56785                     // For this to work, getMatches must be called on relations before ways.
56786                     //
56787                     if (entity.type === 'way') {
56788                         var parents = features.getParents(entity, resolver, geometry);
56789                         if (parents.length === 1 && parents[0].isMultipolygon()) {
56790                             var pkey = osmEntity$$1.key(parents[0]);
56791                             if (_cache[pkey] && _cache[pkey].matches) {
56792                                 matches = lodash.clone(_cache[pkey].matches);
56793                                 continue;
56794                             }
56795                         }
56796                     }
56797                 }
56798
56799                 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
56800                     matches[_keys[i]] = hasMatch = true;
56801                 }
56802             }
56803             _cache[ent].matches = matches;
56804         }
56805
56806         return _cache[ent].matches;
56807     };
56808
56809
56810     features.getParents = function(entity, resolver, geometry) {
56811         if (geometry === 'point') return [];
56812
56813         var ent = osmEntity$$1.key(entity);
56814         if (!_cache[ent]) {
56815             _cache[ent] = {};
56816         }
56817
56818         if (!_cache[ent].parents) {
56819             var parents = [];
56820             if (geometry === 'vertex') {
56821                 parents = resolver.parentWays(entity);
56822             } else {   // 'line', 'area', 'relation'
56823                 parents = resolver.parentRelations(entity);
56824             }
56825             _cache[ent].parents = parents;
56826         }
56827         return _cache[ent].parents;
56828     };
56829
56830
56831     features.isHiddenFeature = function(entity, resolver, geometry) {
56832         if (!_hidden.length) return false;
56833         if (!entity.version) return false;
56834
56835         var matches = features.getMatches(entity, resolver, geometry);
56836
56837         for (var i = 0; i < _hidden.length; i++) {
56838             if (matches[_hidden[i]]) return true;
56839         }
56840         return false;
56841     };
56842
56843
56844     features.isHiddenChild = function(entity, resolver, geometry) {
56845         if (!_hidden.length) return false;
56846         if (!entity.version || geometry === 'point') return false;
56847
56848         var parents = features.getParents(entity, resolver, geometry);
56849         if (!parents.length) return false;
56850
56851         for (var i = 0; i < parents.length; i++) {
56852             if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
56853                 return false;
56854             }
56855         }
56856         return true;
56857     };
56858
56859
56860     features.hasHiddenConnections = function(entity, resolver) {
56861         if (!_hidden.length) return false;
56862         var childNodes, connections;
56863
56864         if (entity.type === 'midpoint') {
56865             childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
56866             connections = [];
56867         } else {
56868             childNodes = entity.nodes ? resolver.childNodes(entity) : [];
56869             connections = features.getParents(entity, resolver, entity.geometry(resolver));
56870         }
56871
56872         // gather ways connected to child nodes..
56873         connections = lodash.reduce(childNodes, function(result, e) {
56874             return resolver.isShared(e) ? lodash.union(result, resolver.parentWays(e)) : result;
56875         }, connections);
56876
56877         return connections.length ? lodash.some(connections, function(e) {
56878             return features.isHidden(e, resolver, e.geometry(resolver));
56879         }) : false;
56880     };
56881
56882
56883     features.isHidden = function(entity, resolver, geometry) {
56884         if (!_hidden.length) return false;
56885         if (!entity.version) return false;
56886
56887         var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
56888         return fn(entity, resolver, geometry);
56889     };
56890
56891
56892     features.filter = function(d, resolver) {
56893         if (!_hidden.length) return d;
56894
56895         var result = [];
56896         for (var i = 0; i < d.length; i++) {
56897             var entity = d[i];
56898             if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
56899                 result.push(entity);
56900             }
56901         }
56902         return result;
56903     };
56904
56905
56906     return utilRebind(features, dispatch$$1, 'on');
56907 }
56908
56909 function utilBindOnce(target, type, listener, capture) {
56910     var typeOnce = type + '.once';
56911     function one() {
56912         target.on(typeOnce, null);
56913         listener.apply(this, arguments);
56914     }
56915     target.on(typeOnce, one, capture);
56916     return this;
56917 }
56918
56919 function rendererMap(context) {
56920
56921     var dimensions = [1, 1],
56922         dispatch$$1 = dispatch('move', 'drawn'),
56923         projection$$1 = context.projection,
56924         curtainProjection = context.curtainProjection,
56925         dblclickEnabled = true,
56926         redrawEnabled = true,
56927         transformStart = projection$$1.transform(),
56928         transformLast,
56929         transformed = false,
56930         minzoom = 0,
56931         drawLayers = svgLayers(projection$$1, context),
56932         drawPoints = svgPoints$$1(projection$$1, context),
56933         drawVertices = svgVertices$$1(projection$$1, context),
56934         drawLines = svgLines$$1(projection$$1, context),
56935         drawAreas = svgAreas$$1(projection$$1, context),
56936         drawMidpoints = svgMidpoints$$1(projection$$1, context),
56937         drawLabels = svgLabels(projection$$1, context),
56938         supersurface = select(null),
56939         wrapper = select(null),
56940         surface = select(null),
56941         mouse$$1,
56942         mousemove;
56943
56944     var zoom$$1 = zoom()
56945             .scaleExtent([ztok(2), ztok(24)])
56946             .interpolate(interpolateValue)
56947             .filter(zoomEventFilter)
56948             .on('zoom', zoomPan);
56949
56950     var _selection = select(null);
56951
56952
56953     function map(selection$$1) {
56954
56955         _selection = selection$$1;
56956
56957         context
56958             .on('change.map', immediateRedraw);
56959
56960         context.connection()
56961             .on('change.map', immediateRedraw);
56962
56963         context.history()
56964             .on('change.map', immediateRedraw)
56965             .on('undone.map redone.map', function(stack$$1) {
56966                 var mode = context.mode().id;
56967                 if (mode !== 'browse' && mode !== 'select') return;
56968
56969                 var followSelected = false;
56970                 if (Array.isArray(stack$$1.selectedIDs)) {
56971                     followSelected = (stack$$1.selectedIDs.length === 1 && stack$$1.selectedIDs[0][0] === 'n');
56972                     context.enter(
56973                         modeSelect(context, stack$$1.selectedIDs).follow(followSelected)
56974                     );
56975                 }
56976                 if (!followSelected && stack$$1.transform) {
56977                     map.transformEase(stack$$1.transform);
56978                 }
56979             });
56980
56981         context.background()
56982             .on('change.map', immediateRedraw);
56983
56984         context.features()
56985             .on('redraw.map', immediateRedraw);
56986
56987         drawLayers
56988             .on('change.map', function() {
56989                 context.background().updateImagery();
56990                 immediateRedraw();
56991             });
56992
56993         selection$$1
56994             .on('dblclick.map', dblClick)
56995             .call(zoom$$1)
56996             .call(zoom$$1.transform, projection$$1.transform());
56997
56998         supersurface = selection$$1.append('div')
56999             .attr('id', 'supersurface')
57000             .call(utilSetTransform, 0, 0);
57001
57002         // Need a wrapper div because Opera can't cope with an absolutely positioned
57003         // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
57004         wrapper = supersurface
57005             .append('div')
57006             .attr('class', 'layer layer-data');
57007
57008         map.surface = surface = wrapper
57009             .call(drawLayers)
57010             .selectAll('.surface')
57011             .attr('id', 'surface');
57012
57013         surface
57014             .call(drawLabels.observe)
57015             .on('mousedown.zoom', function() {
57016                 if (event.button === 2) {
57017                     event.stopPropagation();
57018                 }
57019             }, true)
57020             .on('mouseup.zoom', function() {
57021                 if (resetTransform()) immediateRedraw();
57022             })
57023             .on('mousemove.map', function() {
57024                 mousemove = event;
57025             })
57026             .on('mouseover.vertices', function() {
57027                 if (map.editable() && !transformed) {
57028                     var hover = event.target.__data__;
57029                     surface.selectAll('.data-layer-osm')
57030                         .call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
57031                     dispatch$$1.call('drawn', this, {full: false});
57032                 }
57033             })
57034             .on('mouseout.vertices', function() {
57035                 if (map.editable() && !transformed) {
57036                     var hover = event.relatedTarget && event.relatedTarget.__data__;
57037                     surface.selectAll('.data-layer-osm')
57038                         .call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
57039                     dispatch$$1.call('drawn', this, {full: false});
57040                 }
57041             });
57042
57043         supersurface
57044             .call(context.background());
57045
57046         context.on('enter.map', function() {
57047             if (map.editable() && !transformed) {
57048                 var all = context.intersects(map.extent()),
57049                     filter = utilFunctor(true),
57050                     graph = context.graph();
57051
57052                 all = context.features().filter(all, graph);
57053                 surface.selectAll('.data-layer-osm')
57054                     .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
57055                     .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
57056                 dispatch$$1.call('drawn', this, {full: false});
57057             }
57058         });
57059
57060         map.dimensions(utilGetDimensions(selection$$1));
57061     }
57062
57063
57064     function zoomEventFilter() {
57065         // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
57066         // Intercept `mousedown` and check if there is an orphaned zoom gesture.
57067         // This can happen if a previous `mousedown` occurred without a `mouseup`.
57068         // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
57069         // so that d3-zoom won't stop propagation of new `mousedown` events.
57070         if (event.type === 'mousedown') {
57071             var hasOrphan = false;
57072             var listeners = window.__on;
57073             for (var i = 0; i < listeners.length; i++) {
57074                 var listener = listeners[i];
57075                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
57076                     hasOrphan = true;
57077                     break;
57078                 }
57079             }
57080             if (hasOrphan) {
57081                 var event$$1 = window.CustomEvent;
57082                 if (event$$1) {
57083                     event$$1 = new event$$1('mouseup');
57084                 } else {
57085                     event$$1 = window.document.createEvent('Event');
57086                     event$$1.initEvent('mouseup', false, false);
57087                 }
57088                 // Event needs to be dispatched with an event.view property.
57089                 event$$1.view = window;
57090                 window.dispatchEvent(event$$1);
57091             }
57092         }
57093
57094         return event.button !== 2;   // ignore right clicks
57095     }
57096
57097
57098     function ztok(z) {
57099         return 256 * Math.pow(2, z);
57100     }
57101
57102     function ktoz(k) {
57103         return Math.max(Math.log(k) / Math.LN2 - 8, 0);
57104     }
57105
57106     function pxCenter() {
57107         return [dimensions[0] / 2, dimensions[1] / 2];
57108     }
57109
57110
57111     function drawVector(difference, extent$$1) {
57112         var graph = context.graph(),
57113             features = context.features(),
57114             all = context.intersects(map.extent()),
57115             data, filter;
57116
57117         if (difference) {
57118             var complete = difference.complete(map.extent());
57119             data = lodash.compact(lodash.values(complete));
57120             filter = function(d) { return d.id in complete; };
57121             features.clear(data);
57122
57123         } else {
57124             // force a full redraw if gatherStats detects that a feature
57125             // should be auto-hidden (e.g. points or buildings)..
57126             if (features.gatherStats(all, graph, dimensions)) {
57127                 extent$$1 = undefined;
57128             }
57129
57130             if (extent$$1) {
57131                 data = context.intersects(map.extent().intersection(extent$$1));
57132                 var set = set$2(lodash.map(data, 'id'));
57133                 filter = function(d) { return set.has(d.id); };
57134
57135             } else {
57136                 data = all;
57137                 filter = utilFunctor(true);
57138             }
57139         }
57140
57141         data = features.filter(data, graph);
57142
57143         surface.selectAll('.data-layer-osm')
57144             .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
57145             .call(drawLines, graph, data, filter)
57146             .call(drawAreas, graph, data, filter)
57147             .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
57148             .call(drawLabels, graph, data, filter, dimensions, !difference && !extent$$1)
57149             .call(drawPoints, graph, data, filter);
57150
57151         dispatch$$1.call('drawn', this, {full: true});
57152     }
57153
57154
57155     function editOff() {
57156         context.features().resetStats();
57157         surface.selectAll('.layer-osm *').remove();
57158         dispatch$$1.call('drawn', this, {full: true});
57159     }
57160
57161
57162     function dblClick() {
57163         if (!dblclickEnabled) {
57164             event.preventDefault();
57165             event.stopImmediatePropagation();
57166         }
57167     }
57168
57169
57170     function zoomPan(manualEvent) {
57171         var event$$1 = (manualEvent || event),
57172             source = event$$1.sourceEvent,
57173             eventTransform = event$$1.transform;
57174
57175         if (transformStart.x === eventTransform.x &&
57176             transformStart.y === eventTransform.y &&
57177             transformStart.k === eventTransform.k) {
57178             return;  // no change
57179         }
57180
57181         // Normalize mousewheel - #3029
57182         // If wheel delta is provided in LINE units, recalculate it in PIXEL units
57183         // We are essentially redoing the calculations that occur here:
57184         //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
57185         // See this for more info:
57186         //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
57187         if (source && source.type === 'wheel' && source.deltaMode === 1 /* LINE */) {
57188             // pick sensible scroll amount if user scrolling fast or slow..
57189             var lines = Math.abs(source.deltaY),
57190                 scroll = lines > 2 ? 40 : lines * 10;
57191
57192             var t0 = transformed ? transformLast : transformStart,
57193                 p0 = mouse$$1(source),
57194                 p1 = t0.invert(p0),
57195                 k2 = t0.k * Math.pow(2, -source.deltaY * scroll / 500),
57196                 x2 = p0[0] - p1[0] * k2,
57197                 y2 = p0[1] - p1[1] * k2;
57198
57199             eventTransform = identity$8.translate(x2,y2).scale(k2);
57200             _selection.node().__zoom = eventTransform;
57201         }
57202
57203         if (ktoz(eventTransform.k * 2 * Math.PI) < minzoom) {
57204             surface.interrupt();
57205             uiFlash().text(t('cannot_zoom'));
57206             setZoom(context.minEditableZoom(), true);
57207             queueRedraw();
57208             dispatch$$1.call('move', this, map);
57209             return;
57210         }
57211
57212         projection$$1.transform(eventTransform);
57213
57214         var scale = eventTransform.k / transformStart.k,
57215             tX = (eventTransform.x / scale - transformStart.x) * scale,
57216             tY = (eventTransform.y / scale - transformStart.y) * scale;
57217
57218         if (context.inIntro()) {
57219             curtainProjection.transform({
57220                 x: eventTransform.x - tX,
57221                 y: eventTransform.y - tY,
57222                 k: eventTransform.k
57223             });
57224         }
57225
57226         mousemove = event$$1;
57227         transformed = true;
57228         transformLast = eventTransform;
57229         utilSetTransform(supersurface, tX, tY, scale);
57230         queueRedraw();
57231
57232         dispatch$$1.call('move', this, map);
57233     }
57234
57235
57236     function resetTransform() {
57237         if (!transformed) return false;
57238
57239         // deprecation warning - Radial Menu to be removed in iD v3
57240         surface.selectAll('.edit-menu, .radial-menu').interrupt().remove();
57241         utilSetTransform(supersurface, 0, 0);
57242         transformed = false;
57243         if (context.inIntro()) {
57244             curtainProjection.transform(projection$$1.transform());
57245         }
57246         return true;
57247     }
57248
57249
57250     function redraw(difference, extent$$1) {
57251         if (surface.empty() || !redrawEnabled) return;
57252
57253         // If we are in the middle of a zoom/pan, we can't do differenced redraws.
57254         // It would result in artifacts where differenced entities are redrawn with
57255         // one transform and unchanged entities with another.
57256         if (resetTransform()) {
57257             difference = extent$$1 = undefined;
57258         }
57259
57260         var z = String(~~map.zoom());
57261         if (surface.attr('data-zoom') !== z) {
57262             surface.attr('data-zoom', z)
57263                 .classed('low-zoom', z <= 16);
57264         }
57265
57266         if (!difference) {
57267             supersurface.call(context.background());
57268         }
57269
57270         wrapper
57271             .call(drawLayers);
57272
57273         // OSM
57274         if (map.editable()) {
57275             context.loadTiles(projection$$1, dimensions);
57276             drawVector(difference, extent$$1);
57277         } else {
57278             editOff();
57279         }
57280
57281         transformStart = projection$$1.transform();
57282
57283         return map;
57284     }
57285
57286
57287     var queueRedraw = lodash.throttle(redraw, 750);
57288
57289
57290     var immediateRedraw = function(difference, extent$$1) {
57291         if (!difference && !extent$$1) queueRedraw.cancel();
57292         redraw(difference, extent$$1);
57293     };
57294
57295
57296     function pointLocation(p) {
57297         var translate = projection$$1.translate(),
57298             scale = projection$$1.scale() * 2 * Math.PI;
57299         return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
57300     }
57301
57302
57303     function locationPoint(l) {
57304         var translate = projection$$1.translate(),
57305             scale = projection$$1.scale() * 2 * Math.PI;
57306         return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
57307     }
57308
57309
57310     map.mouse = function() {
57311         var event$$1 = mousemove || event;
57312         if (event$$1) {
57313             var s;
57314             while ((s = event$$1.sourceEvent)) { event$$1 = s; }
57315             return mouse$$1(event$$1);
57316         }
57317         return null;
57318     };
57319
57320
57321     map.mouseCoordinates = function() {
57322         return projection$$1.invert(map.mouse());
57323     };
57324
57325
57326     map.dblclickEnable = function(_) {
57327         if (!arguments.length) return dblclickEnabled;
57328         dblclickEnabled = _;
57329         return map;
57330     };
57331
57332
57333     map.redrawEnable = function(_) {
57334         if (!arguments.length) return redrawEnabled;
57335         redrawEnabled = _;
57336         return map;
57337     };
57338
57339
57340     function setTransform(t2, duration, force) {
57341         var t$$1 = projection$$1.transform();
57342         if (!force && t2.k === t$$1.k && t2.x === t$$1.x && t2.y === t$$1.y) {
57343             return false;
57344         }
57345
57346         if (duration) {
57347             _selection
57348                 .transition()
57349                 .duration(duration)
57350                 .on('start', function() { map.startEase(); })
57351                 .call(zoom$$1.transform, identity$8.translate(t2.x, t2.y).scale(t2.k));
57352         } else {
57353             projection$$1.transform(t2);
57354             transformStart = t2;
57355             _selection.call(zoom$$1.transform, transformStart);
57356         }
57357     }
57358
57359
57360     function setZoom(z2, force, duration) {
57361         if (z2 === map.zoom() && !force) {
57362             return false;
57363         }
57364
57365         var k = projection$$1.scale(),
57366             k2 = Math.max(ztok(2), Math.min(ztok(24), ztok(z2))) / (2 * Math.PI),
57367             center = pxCenter(),
57368             l = pointLocation(center);
57369
57370         projection$$1.scale(k2);
57371
57372         var t$$1 = projection$$1.translate();
57373         l = locationPoint(l);
57374
57375         t$$1[0] += center[0] - l[0];
57376         t$$1[1] += center[1] - l[1];
57377
57378         if (duration) {
57379             projection$$1.scale(k);  // reset scale
57380             _selection
57381                 .transition()
57382                 .duration(duration)
57383                 .on('start', function() { map.startEase(); })
57384                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k2));
57385         } else {
57386             projection$$1.translate(t$$1);
57387             transformStart = projection$$1.transform();
57388             _selection.call(zoom$$1.transform, transformStart);
57389         }
57390
57391         return true;
57392     }
57393
57394
57395     function setCenter(loc2, duration) {
57396         var c = map.center();
57397         if (loc2[0] === c[0] && loc2[1] === c[1]) {
57398             return false;
57399         }
57400
57401         var t$$1 = projection$$1.translate(),
57402             k = projection$$1.scale(),
57403             pxC = pxCenter(),
57404             ll = projection$$1(loc2);
57405
57406         t$$1[0] = t$$1[0] - ll[0] + pxC[0];
57407         t$$1[1] = t$$1[1] - ll[1] + pxC[1];
57408
57409         if (duration) {
57410             _selection
57411                 .transition()
57412                 .duration(duration)
57413                 .on('start', function() { map.startEase(); })
57414                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
57415         } else {
57416             projection$$1.translate(t$$1);
57417             transformStart = projection$$1.transform();
57418             _selection.call(zoom$$1.transform, transformStart);
57419         }
57420
57421         return true;
57422     }
57423
57424
57425     map.pan = function(delta, duration) {
57426         var t$$1 = projection$$1.translate(),
57427             k = projection$$1.scale();
57428
57429         t$$1[0] += delta[0];
57430         t$$1[1] += delta[1];
57431
57432         if (duration) {
57433             _selection
57434                 .transition()
57435                 .duration(duration)
57436                 .on('start', function() { map.startEase(); })
57437                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
57438         } else {
57439             projection$$1.translate(t$$1);
57440             transformStart = projection$$1.transform();
57441             _selection.call(zoom$$1.transform, transformStart);
57442             dispatch$$1.call('move', this, map);
57443             immediateRedraw();
57444         }
57445
57446         return map;
57447     };
57448
57449
57450     map.dimensions = function(_) {
57451         if (!arguments.length) return dimensions;
57452         var center = map.center();
57453         dimensions = _;
57454         drawLayers.dimensions(dimensions);
57455         context.background().dimensions(dimensions);
57456         projection$$1.clipExtent([[0, 0], dimensions]);
57457         mouse$$1 = utilFastMouse(supersurface.node());
57458         setCenter(center);
57459
57460         queueRedraw();
57461         return map;
57462     };
57463
57464
57465     function zoomIn(delta) {
57466         setZoom(~~map.zoom() + delta, true, 250);
57467     }
57468
57469     function zoomOut(delta) {
57470         setZoom(~~map.zoom() - delta, true, 250);
57471     }
57472
57473     map.zoomIn = function() { zoomIn(1); };
57474     map.zoomInFurther = function() { zoomIn(4); };
57475
57476     map.zoomOut = function() { zoomOut(1); };
57477     map.zoomOutFurther = function() { zoomOut(4); };
57478
57479
57480     map.center = function(loc2) {
57481         if (!arguments.length) {
57482             return projection$$1.invert(pxCenter());
57483         }
57484
57485         if (setCenter(loc2)) {
57486             dispatch$$1.call('move', this, map);
57487         }
57488
57489         queueRedraw();
57490         return map;
57491     };
57492
57493
57494     map.zoom = function(z2) {
57495         if (!arguments.length) {
57496             return Math.max(ktoz(projection$$1.scale() * 2 * Math.PI), 0);
57497         }
57498
57499         if (z2 < minzoom) {
57500             surface.interrupt();
57501             uiFlash().text(t('cannot_zoom'));
57502             z2 = context.minEditableZoom();
57503         }
57504
57505         if (setZoom(z2)) {
57506             dispatch$$1.call('move', this, map);
57507         }
57508
57509         queueRedraw();
57510         return map;
57511     };
57512
57513
57514     map.zoomTo = function(entity, zoomLimits) {
57515         var extent$$1 = entity.extent(context.graph());
57516         if (!isFinite(extent$$1.area())) return;
57517
57518         var z2 = map.trimmedExtentZoom(extent$$1);
57519         zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
57520         map.centerZoom(extent$$1.center(), Math.min(Math.max(z2, zoomLimits[0]), zoomLimits[1]));
57521     };
57522
57523
57524     map.centerZoom = function(loc2, z2) {
57525         var centered = setCenter(loc2),
57526             zoomed   = setZoom(z2);
57527
57528         if (centered || zoomed) {
57529             dispatch$$1.call('move', this, map);
57530         }
57531
57532         queueRedraw();
57533         return map;
57534     };
57535
57536
57537     map.centerEase = function(loc2, duration) {
57538         duration = duration || 250;
57539         setCenter(loc2, duration);
57540         return map;
57541     };
57542
57543
57544     map.zoomEase = function(z2, duration) {
57545         duration = duration || 250;
57546         setZoom(z2, false, duration);
57547         return map;
57548     };
57549
57550
57551     map.transformEase = function(t2, duration) {
57552         duration = duration || 250;
57553         setTransform(t2, duration, false);
57554         return map;
57555     };
57556
57557
57558     map.startEase = function() {
57559         utilBindOnce(surface, 'mousedown.ease', function() {
57560             map.cancelEase();
57561         });
57562         return map;
57563     };
57564
57565
57566     map.cancelEase = function() {
57567         _selection.interrupt();
57568         return map;
57569     };
57570
57571
57572     map.extent = function(_) {
57573         if (!arguments.length) {
57574             return new geoExtent$$1(projection$$1.invert([0, dimensions[1]]),
57575                                  projection$$1.invert([dimensions[0], 0]));
57576         } else {
57577             var extent$$1 = geoExtent$$1(_);
57578             map.centerZoom(extent$$1.center(), map.extentZoom(extent$$1));
57579         }
57580     };
57581
57582
57583     map.trimmedExtent = function(_) {
57584         if (!arguments.length) {
57585             var headerY = 60, footerY = 30, pad = 10;
57586             return new geoExtent$$1(projection$$1.invert([pad, dimensions[1] - footerY - pad]),
57587                                  projection$$1.invert([dimensions[0] - pad, headerY + pad]));
57588         } else {
57589             var extent$$1 = geoExtent$$1(_);
57590             map.centerZoom(extent$$1.center(), map.trimmedExtentZoom(extent$$1));
57591         }
57592     };
57593
57594
57595     function calcZoom(extent$$1, dim) {
57596         var tl = projection$$1([extent$$1[0][0], extent$$1[1][1]]),
57597             br = projection$$1([extent$$1[1][0], extent$$1[0][1]]);
57598
57599         // Calculate maximum zoom that fits extent
57600         var hFactor = (br[0] - tl[0]) / dim[0],
57601             vFactor = (br[1] - tl[1]) / dim[1],
57602             hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
57603             vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
57604             newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
57605
57606         return newZoom;
57607     }
57608
57609
57610     map.extentZoom = function(_) {
57611         return calcZoom(geoExtent$$1(_), dimensions);
57612     };
57613
57614
57615     map.trimmedExtentZoom = function(_) {
57616         var trimY = 120, trimX = 40,
57617             trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
57618         return calcZoom(geoExtent$$1(_), trimmed);
57619     };
57620
57621
57622     map.editable = function() {
57623         return map.zoom() >= context.minEditableZoom();
57624     };
57625
57626
57627     map.minzoom = function(_) {
57628         if (!arguments.length) return minzoom;
57629         minzoom = _;
57630         return map;
57631     };
57632
57633
57634     map.layers = drawLayers;
57635
57636
57637     return utilRebind(map, dispatch$$1, 'on');
57638 }
57639
57640 var TAU = 2 * Math.PI;
57641 function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
57642 function ktoz(k) { return Math.log(k * TAU) / Math.LN2 - 8; }
57643 function vecSub(a, b) { return [ a[0] - b[0], a[1] - b[1] ]; }
57644 function vecScale(a, b) { return [ a[0] * b, a[1] * b ]; }
57645
57646
57647 function uiMapInMap(context) {
57648
57649
57650     function map_in_map(selection$$1) {
57651         var backgroundLayer = rendererTileLayer(context),
57652             overlayLayers = {},
57653             projection$$1 = geoRawMercator(),
57654             gpxLayer = svgGpx(projection$$1, context).showLabels(false),
57655             debugLayer = svgDebug(projection$$1, context),
57656             zoom$$1 = zoom()
57657                 .scaleExtent([ztok(0.5), ztok(24)])
57658                 .on('start', zoomStarted)
57659                 .on('zoom', zoomed)
57660                 .on('end', zoomEnded),
57661             isTransformed = false,
57662             isHidden = true,
57663             skipEvents = false,
57664             gesture = null,
57665             zDiff = 6,    // by default, minimap renders at (main zoom - 6)
57666             wrap = select(null),
57667             tiles = select(null),
57668             viewport = select(null),
57669             tStart,  // transform at start of gesture
57670             tCurr,   // transform at most recent event
57671             timeoutId;
57672
57673
57674         function zoomStarted() {
57675             if (skipEvents) return;
57676             tStart = tCurr = projection$$1.transform();
57677             gesture = null;
57678         }
57679
57680
57681         function zoomed() {
57682             if (skipEvents) return;
57683
57684             var x = event.transform.x,
57685                 y = event.transform.y,
57686                 k = event.transform.k,
57687                 isZooming = (k !== tStart.k),
57688                 isPanning = (x !== tStart.x || y !== tStart.y);
57689
57690             if (!isZooming && !isPanning) {
57691                 return;  // no change
57692             }
57693
57694             // lock in either zooming or panning, don't allow both in minimap.
57695             if (!gesture) {
57696                 gesture = isZooming ? 'zoom' : 'pan';
57697             }
57698
57699             var tMini = projection$$1.transform(),
57700                 tX, tY, scale;
57701
57702             if (gesture === 'zoom') {
57703                 var dMini = utilGetDimensions(wrap),
57704                     cMini = vecScale(dMini, 0.5);
57705                 scale = k / tMini.k;
57706                 tX = (cMini[0] / scale - cMini[0]) * scale;
57707                 tY = (cMini[1] / scale - cMini[1]) * scale;
57708             } else {
57709                 k = tMini.k;
57710                 scale = 1;
57711                 tX = x - tMini.x;
57712                 tY = y - tMini.y;
57713             }
57714
57715             utilSetTransform(tiles, tX, tY, scale);
57716             utilSetTransform(viewport, 0, 0, scale);
57717             isTransformed = true;
57718             tCurr = identity$8.translate(x, y).scale(k);
57719
57720             var zMain = ktoz(context.projection.scale()),
57721                 zMini = ktoz(k);
57722
57723             zDiff = zMain - zMini;
57724
57725             queueRedraw();
57726         }
57727
57728
57729         function zoomEnded() {
57730             if (skipEvents) return;
57731             if (gesture !== 'pan') return;
57732
57733             updateProjection();
57734             gesture = null;
57735             var dMini = utilGetDimensions(wrap),
57736                 cMini = vecScale(dMini, 0.5);
57737             context.map().center(projection$$1.invert(cMini));   // recenter main map..
57738         }
57739
57740
57741         function updateProjection() {
57742             var loc = context.map().center(),
57743                 dMini = utilGetDimensions(wrap),
57744                 cMini = vecScale(dMini, 0.5),
57745                 tMain = context.projection.transform(),
57746                 zMain = ktoz(tMain.k),
57747                 zMini = Math.max(zMain - zDiff, 0.5),
57748                 kMini = ztok(zMini);
57749
57750             projection$$1
57751                 .translate([tMain.x, tMain.y])
57752                 .scale(kMini);
57753
57754             var point = projection$$1(loc),
57755                 mouse$$1 = (gesture === 'pan') ? vecSub([tCurr.x, tCurr.y], [tStart.x, tStart.y]) : [0, 0],
57756                 xMini = cMini[0] - point[0] + tMain.x + mouse$$1[0],
57757                 yMini = cMini[1] - point[1] + tMain.y + mouse$$1[1];
57758
57759             projection$$1
57760                 .translate([xMini, yMini])
57761                 .clipExtent([[0, 0], dMini]);
57762
57763             tCurr = projection$$1.transform();
57764
57765             if (isTransformed) {
57766                 utilSetTransform(tiles, 0, 0);
57767                 utilSetTransform(viewport, 0, 0);
57768                 isTransformed = false;
57769             }
57770
57771             zoom$$1
57772                 .scaleExtent([ztok(0.5), ztok(zMain - 3)]);
57773
57774             skipEvents = true;
57775             wrap.call(zoom$$1.transform, tCurr);
57776             skipEvents = false;
57777         }
57778
57779
57780         function redraw() {
57781             clearTimeout(timeoutId);
57782             if (isHidden) return;
57783
57784             updateProjection();
57785
57786             var dMini = utilGetDimensions(wrap),
57787                 zMini = ktoz(projection$$1.scale());
57788
57789             // setup tile container
57790             tiles = wrap
57791                 .selectAll('.map-in-map-tiles')
57792                 .data([0]);
57793
57794             tiles = tiles.enter()
57795                 .append('div')
57796                 .attr('class', 'map-in-map-tiles')
57797                 .merge(tiles);
57798
57799             // redraw background
57800             backgroundLayer
57801                 .source(context.background().baseLayerSource())
57802                 .projection(projection$$1)
57803                 .dimensions(dMini);
57804
57805             var background = tiles
57806                 .selectAll('.map-in-map-background')
57807                 .data([0]);
57808
57809             background.enter()
57810                 .append('div')
57811                 .attr('class', 'map-in-map-background')
57812                 .merge(background)
57813                 .call(backgroundLayer);
57814
57815
57816             // redraw overlay
57817             var overlaySources = context.background().overlayLayerSources();
57818             var activeOverlayLayers = [];
57819             for (var i = 0; i < overlaySources.length; i++) {
57820                 if (overlaySources[i].validZoom(zMini)) {
57821                     if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
57822                     activeOverlayLayers.push(overlayLayers[i]
57823                         .source(overlaySources[i])
57824                         .projection(projection$$1)
57825                         .dimensions(dMini));
57826                 }
57827             }
57828
57829             var overlay = tiles
57830                 .selectAll('.map-in-map-overlay')
57831                 .data([0]);
57832
57833             overlay = overlay.enter()
57834                 .append('div')
57835                 .attr('class', 'map-in-map-overlay')
57836                 .merge(overlay);
57837
57838
57839             var overlays = overlay
57840                 .selectAll('div')
57841                 .data(activeOverlayLayers, function(d) { return d.source().name(); });
57842
57843             overlays.exit()
57844                 .remove();
57845
57846             overlays = overlays.enter()
57847                 .append('div')
57848                 .merge(overlays)
57849                 .each(function(layer) { select(this).call(layer); });
57850
57851
57852             var dataLayers = tiles
57853                 .selectAll('.map-in-map-data')
57854                 .data([0]);
57855
57856             dataLayers.exit()
57857                 .remove();
57858
57859             dataLayers = dataLayers.enter()
57860                 .append('svg')
57861                 .attr('class', 'map-in-map-data')
57862                 .merge(dataLayers)
57863                 .call(gpxLayer)
57864                 .call(debugLayer);
57865
57866
57867             // redraw viewport bounding box
57868             if (gesture !== 'pan') {
57869                 var getPath = index$4(projection$$1),
57870                     bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
57871
57872                 viewport = wrap.selectAll('.map-in-map-viewport')
57873                     .data([0]);
57874
57875                 viewport = viewport.enter()
57876                     .append('svg')
57877                     .attr('class', 'map-in-map-viewport')
57878                     .merge(viewport);
57879
57880
57881                 var path$$1 = viewport.selectAll('.map-in-map-bbox')
57882                     .data([bbox]);
57883
57884                 path$$1.enter()
57885                     .append('path')
57886                     .attr('class', 'map-in-map-bbox')
57887                     .merge(path$$1)
57888                     .attr('d', getPath)
57889                     .classed('thick', function(d) { return getPath.area(d) < 30; });
57890             }
57891         }
57892
57893
57894         function queueRedraw() {
57895             clearTimeout(timeoutId);
57896             timeoutId = setTimeout(function() { redraw(); }, 750);
57897         }
57898
57899
57900         function toggle() {
57901             if (event) event.preventDefault();
57902
57903             isHidden = !isHidden;
57904
57905             var label = select('.minimap-toggle');
57906             label.classed('active', !isHidden)
57907                 .select('input').property('checked', !isHidden);
57908
57909             if (isHidden) {
57910                 wrap
57911                     .style('display', 'block')
57912                     .style('opacity', '1')
57913                     .transition()
57914                     .duration(200)
57915                     .style('opacity', '0')
57916                     .on('end', function() {
57917                         selection$$1.selectAll('.map-in-map')
57918                             .style('display', 'none');
57919                     });
57920             } else {
57921                 wrap
57922                     .style('display', 'block')
57923                     .style('opacity', '0')
57924                     .transition()
57925                     .duration(200)
57926                     .style('opacity', '1')
57927                     .on('end', function() {
57928                         redraw();
57929                     });
57930             }
57931         }
57932
57933
57934         uiMapInMap.toggle = toggle;
57935
57936         wrap = selection$$1.selectAll('.map-in-map')
57937             .data([0]);
57938
57939         wrap = wrap.enter()
57940             .append('div')
57941             .attr('class', 'map-in-map')
57942             .style('display', (isHidden ? 'none' : 'block'))
57943             .call(zoom$$1)
57944             .on('dblclick.zoom', null)
57945             .merge(wrap);
57946
57947         context.map()
57948             .on('drawn.map-in-map', function(drawn) {
57949                 if (drawn.full === true) {
57950                     redraw();
57951                 }
57952             });
57953
57954         redraw();
57955
57956         var keybinding = d3keybinding('map-in-map')
57957             .on(t('background.minimap.key'), toggle);
57958
57959         select(document)
57960             .call(keybinding);
57961     }
57962
57963     return map_in_map;
57964 }
57965
57966 function uiTooltipHtml(text, key, heading) {
57967     var s = '';
57968
57969     if (heading) {
57970         s += '<div class="tooltip-heading"><span>' + heading + '</span></div>';
57971     }
57972     if (text) {
57973         s += '<div class="tooltip-text"><span>' + text + '</span></div>';
57974     }
57975     if (key) {
57976         s += '<div class="keyhint-wrap"><span>' + t('tooltip_keyhint') + '</span>' +
57977             '<span class="keyhint">' + key + '</span></div>';
57978     }
57979
57980     return s;
57981 }
57982
57983 function uiBackground(context) {
57984     var key = t('background.key'),
57985         detected = utilDetect(),
57986         opacities = [1, 0.75, 0.5, 0.25],
57987         directions = [
57988             ['right', [0.5, 0]],
57989             ['top', [0, -0.5]],
57990             ['left', [-0.5, 0]],
57991             ['bottom', [0, 0.5]]],
57992         opacityDefault = (context.storage('background-opacity') !== null) ?
57993             (+context.storage('background-opacity')) : 1.0,
57994         customSource = context.background().findSource('custom'),
57995         previous;
57996
57997     // Can be 0 from <1.3.0 use or due to issue #1923.
57998     if (opacityDefault === 0) opacityDefault = 1.0;
57999
58000
58001     function background(selection$$1) {
58002
58003         function sortSources(a, b) {
58004             return a.best() && !b.best() ? -1
58005                 : b.best() && !a.best() ? 1
58006                 : descending(a.area(), b.area()) || ascending(a.name(), b.name()) || 0;
58007         }
58008
58009
58010         function setOpacity(d) {
58011             var bg = context.container().selectAll('.layer-background')
58012                 .transition()
58013                 .style('opacity', d)
58014                 .attr('data-opacity', d);
58015
58016             if (!detected.opera) {
58017                 utilSetTransform(bg, 0, 0);
58018             }
58019
58020             opacityList.selectAll('li')
58021                 .classed('active', function(_) { return _ === d; });
58022
58023             context.storage('background-opacity', d);
58024         }
58025
58026
58027         function setTooltips(selection$$1) {
58028             selection$$1.each(function(d, i, nodes) {
58029                 var item = select(this).select('label'),
58030                     span = item.select('span'),
58031                     placement = (i < nodes.length / 2) ? 'bottom' : 'top',
58032                     description = d.description(),
58033                     isOverflowing = (span.property('clientWidth') !== span.property('scrollWidth'));
58034
58035                 if (d === previous) {
58036                     item.call(tooltip()
58037                         .placement(placement)
58038                         .html(true)
58039                         .title(function() {
58040                             var tip = '<div>' + t('background.switch') + '</div>';
58041                             return uiTooltipHtml(tip, uiCmd('⌘' + key));
58042                         })
58043                     );
58044                 } else if (description || isOverflowing) {
58045                     item.call(tooltip()
58046                         .placement(placement)
58047                         .title(description || d.name())
58048                     );
58049                 } else {
58050                     item.call(tooltip().destroy);
58051                 }
58052             });
58053         }
58054
58055
58056         function selectLayer() {
58057             function active$$1(d) {
58058                 return context.background().showsLayer(d);
58059             }
58060
58061             content.selectAll('.layer')
58062                 .classed('active', active$$1)
58063                 .classed('switch', function(d) { return d === previous; })
58064                 .call(setTooltips)
58065                 .selectAll('input')
58066                 .property('checked', active$$1);
58067         }
58068
58069
58070         function clickSetSource(d) {
58071             if (d.id === 'custom' && !d.template()) {
58072                 return editCustom();
58073             }
58074
58075             event.preventDefault();
58076             previous = context.background().baseLayerSource();
58077             context.background().baseLayerSource(d);
58078             selectLayer();
58079             document.activeElement.blur();
58080         }
58081
58082
58083         function editCustom() {
58084             event.preventDefault();
58085             var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
58086             var template = window.prompt(
58087                 t('background.custom_prompt', { example: example }),
58088                 customSource.template() || example
58089             );
58090
58091             if (template) {
58092                 context.storage('background-custom-template', template);
58093                 customSource.template(template);
58094                 clickSetSource(customSource);
58095             } else {
58096                 selectLayer();
58097             }
58098         }
58099
58100
58101         function clickSetOverlay(d) {
58102             event.preventDefault();
58103             context.background().toggleOverlayLayer(d);
58104             selectLayer();
58105             document.activeElement.blur();
58106         }
58107
58108
58109         function drawList(layerList, type, change, filter) {
58110             var sources = context.background()
58111                 .sources(context.map().extent())
58112                 .filter(filter);
58113
58114             var layerLinks = layerList.selectAll('li.layer')
58115                 .data(sources, function(d) { return d.name(); });
58116
58117             layerLinks.exit()
58118                 .remove();
58119
58120             var enter = layerLinks.enter()
58121                 .append('li')
58122                 .attr('class', 'layer')
58123                 .classed('layer-custom', function(d) { return d.id === 'custom'; })
58124                 .classed('best', function(d) { return d.best(); });
58125
58126             enter.filter(function(d) { return d.id === 'custom'; })
58127                 .append('button')
58128                 .attr('class', 'layer-browse')
58129                 .call(tooltip()
58130                     .title(t('background.custom_button'))
58131                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
58132                 .on('click', editCustom)
58133                 .call(svgIcon('#icon-search'));
58134
58135             enter.filter(function(d) { return d.best(); })
58136                 .append('div')
58137                 .attr('class', 'best')
58138                 .call(tooltip()
58139                     .title(t('background.best_imagery'))
58140                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
58141                 .append('span')
58142                 .html('&#9733;');
58143
58144             var label = enter
58145                 .append('label');
58146
58147             label
58148                 .append('input')
58149                 .attr('type', type)
58150                 .attr('name', 'layers')
58151                 .on('change', change);
58152
58153             label
58154                 .append('span')
58155                 .text(function(d) { return d.name(); });
58156
58157
58158             layerList.selectAll('li.layer')
58159                 .sort(sortSources)
58160                 .style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
58161         }
58162
58163
58164         function update() {
58165             backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
58166             overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
58167
58168             selectLayer();
58169             updateOffsetVal();
58170         }
58171
58172
58173         function updateOffsetVal() {
58174             var meters = geoOffsetToMeters(context.background().offset()),
58175                 x = +meters[0].toFixed(2),
58176                 y = +meters[1].toFixed(2);
58177
58178             selectAll('.nudge-inner-rect')
58179                 .select('input')
58180                 .classed('error', false)
58181                 .property('value', x + ', ' + y);
58182
58183             selectAll('.nudge-reset')
58184                 .classed('disabled', function() {
58185                     return (x === 0 && y === 0);
58186                 });
58187         }
58188
58189
58190         function resetOffset() {
58191             if (event.button !== 0) return;
58192             context.background().offset([0, 0]);
58193             updateOffsetVal();
58194         }
58195
58196
58197         function nudge(d) {
58198             context.background().nudge(d, context.map().zoom());
58199             updateOffsetVal();
58200         }
58201
58202
58203         function buttonOffset(d) {
58204             if (event.button !== 0) return;
58205             var timeout = window.setTimeout(function() {
58206                     interval = window.setInterval(nudge.bind(null, d), 100);
58207                 }, 500),
58208                 interval;
58209
58210             function doneNudge() {
58211                 window.clearTimeout(timeout);
58212                 window.clearInterval(interval);
58213                 select(window)
58214                     .on('mouseup.buttonoffset', null, true)
58215                     .on('mousedown.buttonoffset', null, true);
58216             }
58217
58218             select(window)
58219                 .on('mouseup.buttonoffset', doneNudge, true)
58220                 .on('mousedown.buttonoffset', doneNudge, true);
58221
58222             nudge(d);
58223         }
58224
58225
58226         function inputOffset() {
58227             if (event.button !== 0) return;
58228             var input = select(this);
58229             var d = input.node().value;
58230
58231             if (d === '') return resetOffset();
58232
58233             d = d.replace(/;/g, ',').split(',').map(function(n) {
58234                 // if n is NaN, it will always get mapped to false.
58235                 return !isNaN(n) && n;
58236             });
58237
58238             if (d.length !== 2 || !d[0] || !d[1]) {
58239                 input.classed('error', true);
58240                 return;
58241             }
58242
58243             context.background().offset(geoMetersToOffset(d));
58244             updateOffsetVal();
58245         }
58246
58247
58248         function dragOffset() {
58249             if (event.button !== 0) return;
58250             var origin = [event.clientX, event.clientY];
58251
58252             context.container()
58253                 .append('div')
58254                 .attr('class', 'nudge-surface');
58255
58256             select(window)
58257                 .on('mousemove.offset', function() {
58258                     var latest = [event.clientX, event.clientY];
58259                     var d = [
58260                         -(origin[0] - latest[0]) / 4,
58261                         -(origin[1] - latest[1]) / 4
58262                     ];
58263
58264                     origin = latest;
58265                     nudge(d);
58266                 })
58267                 .on('mouseup.offset', function() {
58268                     if (event.button !== 0) return;
58269                     selectAll('.nudge-surface')
58270                         .remove();
58271
58272                     select(window)
58273                         .on('mousemove.offset', null)
58274                         .on('mouseup.offset', null);
58275                 });
58276
58277             event.preventDefault();
58278         }
58279
58280
58281         function hide() {
58282             setVisible(false);
58283         }
58284
58285
58286         function toggle() {
58287             if (event) {
58288                 event.preventDefault();
58289             }
58290             tooltipBehavior.hide(button);
58291             setVisible(!button.classed('active'));
58292         }
58293
58294
58295         function quickSwitch() {
58296             if (event) {
58297                 event.stopImmediatePropagation();
58298                 event.preventDefault();
58299             }
58300             if (previous) {
58301                 clickSetSource(previous);
58302             }
58303         }
58304
58305
58306         function setVisible(show) {
58307             if (show !== shown) {
58308                 button.classed('active', show);
58309                 shown = show;
58310
58311                 if (show) {
58312                     selection$$1
58313                         .on('mousedown.background-inside', function() {
58314                             event.stopPropagation();
58315                         });
58316
58317                     content
58318                         .style('display', 'block')
58319                         .style('right', '-300px')
58320                         .transition()
58321                         .duration(200)
58322                         .style('right', '0px');
58323
58324                     content.selectAll('.layer')
58325                         .call(setTooltips);
58326
58327                 } else {
58328                     content
58329                         .style('display', 'block')
58330                         .style('right', '0px')
58331                         .transition()
58332                         .duration(200)
58333                         .style('right', '-300px')
58334                         .on('end', function() {
58335                             select(this).style('display', 'none');
58336                         });
58337
58338                     selection$$1
58339                         .on('mousedown.background-inside', null);
58340                 }
58341             }
58342         }
58343
58344
58345         var content = selection$$1
58346                 .append('div')
58347                 .attr('class', 'fillL map-overlay col3 content hide'),
58348             tooltipBehavior = tooltip()
58349                 .placement((textDirection === 'rtl') ? 'right' : 'left')
58350                 .html(true)
58351                 .title(uiTooltipHtml(t('background.description'), key)),
58352             button = selection$$1
58353                 .append('button')
58354                 .attr('tabindex', -1)
58355                 .on('click', toggle)
58356                 .call(svgIcon('#icon-layers', 'light'))
58357                 .call(tooltipBehavior),
58358             shown = false;
58359
58360
58361         /* opacity switcher */
58362
58363         var opawrap = content
58364                 .append('div')
58365                 .attr('class', 'opacity-options-wrapper');
58366
58367         opawrap
58368             .append('h4')
58369             .text(t('background.title'));
58370
58371         var opacityList = opawrap
58372             .append('ul')
58373             .attr('class', 'opacity-options');
58374
58375         opacityList.selectAll('div.opacity')
58376             .data(opacities)
58377             .enter()
58378             .append('li')
58379             .attr('data-original-title', function(d) {
58380                 return t('background.percent_brightness', { opacity: (d * 100) });
58381             })
58382             .on('click.set-opacity', setOpacity)
58383             .html('<div class="select-box"></div>')
58384             .call(tooltip()
58385                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
58386             .append('div')
58387             .attr('class', 'opacity')
58388             .style('opacity', function(d) { return 1.25 - d; });
58389
58390
58391         /* background list */
58392
58393         var backgroundList = content
58394             .append('ul')
58395             .attr('class', 'layer-list')
58396             .attr('dir', 'auto');
58397
58398         content
58399             .append('div')
58400             .attr('class', 'imagery-faq')
58401             .append('a')
58402             .attr('target', '_blank')
58403             .attr('tabindex', -1)
58404             .call(svgIcon('#icon-out-link', 'inline'))
58405             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
58406             .append('span')
58407             .text(t('background.imagery_source_faq'));
58408
58409
58410         /* overlay list */
58411
58412         var overlayList = content
58413             .append('ul')
58414             .attr('class', 'layer-list');
58415
58416         var controls = content
58417             .append('div')
58418             .attr('class', 'controls-list');
58419
58420
58421         /* minimap toggle */
58422
58423         var minimapLabel = controls
58424             .append('label')
58425             .call(tooltip()
58426                 .html(true)
58427                 .title(uiTooltipHtml(t('background.minimap.tooltip'), t('background.minimap.key')))
58428                 .placement('top')
58429             );
58430
58431         minimapLabel
58432             .classed('minimap-toggle', true)
58433             .append('input')
58434             .attr('type', 'checkbox')
58435             .on('change', function() {
58436                 uiMapInMap.toggle();
58437                 event.preventDefault();
58438             });
58439
58440         minimapLabel
58441             .append('span')
58442             .text(t('background.minimap.description'));
58443
58444
58445         /* imagery offset controls */
58446
58447         var adjustments = content
58448             .append('div')
58449             .attr('class', 'adjustments');
58450
58451         adjustments
58452             .append('a')
58453             .text(t('background.fix_misalignment'))
58454             .attr('href', '#')
58455             .classed('hide-toggle', true)
58456             .classed('expanded', false)
58457             .on('click', function() {
58458                 if (event.button !== 0) return;
58459                 var exp = select(this).classed('expanded');
58460                 nudgeContainer.style('display', exp ? 'none' : 'block');
58461                 select(this).classed('expanded', !exp);
58462                 event.preventDefault();
58463             });
58464
58465         var nudgeContainer = adjustments
58466             .append('div')
58467             .attr('class', 'nudge-container cf')
58468             .style('display', 'none');
58469
58470         nudgeContainer
58471             .append('div')
58472             .attr('class', 'nudge-instructions')
58473             .text(t('background.offset'));
58474
58475         var nudgeRect = nudgeContainer
58476             .append('div')
58477             .attr('class', 'nudge-outer-rect')
58478             .on('mousedown', dragOffset);
58479
58480         nudgeRect
58481             .append('div')
58482             .attr('class', 'nudge-inner-rect')
58483             .append('input')
58484             .on('change', inputOffset)
58485             .on('mousedown', function() {
58486                 if (event.button !== 0) return;
58487                 event.stopPropagation();
58488             });
58489
58490         nudgeContainer
58491             .append('div')
58492             .selectAll('button')
58493             .data(directions).enter()
58494             .append('button')
58495             .attr('class', function(d) { return d[0] + ' nudge'; })
58496             .on('mousedown', function(d) {
58497                 if (event.button !== 0) return;
58498                 buttonOffset(d[1]);
58499             });
58500
58501         nudgeContainer
58502             .append('button')
58503             .attr('title', t('background.reset'))
58504             .attr('class', 'nudge-reset disabled')
58505             .on('click', resetOffset)
58506             .call(
58507                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
58508             );
58509
58510         context.map()
58511             .on('move.background-update', lodash.debounce(update, 1000));
58512
58513         context.background()
58514             .on('change.background-update', update);
58515
58516
58517         update();
58518         setOpacity(opacityDefault);
58519
58520         var keybinding = d3keybinding('background')
58521             .on(key, toggle)
58522             .on(uiCmd('⌘' + key), quickSwitch)
58523             .on([t('map_data.key'), t('help.key')], hide);
58524
58525         select(document)
58526             .call(keybinding);
58527
58528         context.surface().on('mousedown.background-outside', hide);
58529         context.container().on('mousedown.background-outside', hide);
58530     }
58531
58532     return background;
58533 }
58534
58535 function uiContributors(context) {
58536     var debouncedUpdate = lodash.debounce(function() { update(); }, 1000),
58537         limit = 4,
58538         hidden = false,
58539         wrap = select(null);
58540
58541
58542     function update() {
58543         var users = {},
58544             entities = context.intersects(context.map().extent());
58545
58546         entities.forEach(function(entity) {
58547             if (entity && entity.user) users[entity.user] = true;
58548         });
58549
58550         var u = Object.keys(users),
58551             subset = u.slice(0, u.length > limit ? limit - 1 : limit);
58552
58553         wrap.html('')
58554             .call(svgIcon('#icon-nearby', 'pre-text light'));
58555
58556         var userList = select(document.createElement('span'));
58557
58558         userList.selectAll()
58559             .data(subset)
58560             .enter()
58561             .append('a')
58562             .attr('class', 'user-link')
58563             .attr('href', function(d) { return context.connection().userURL(d); })
58564             .attr('target', '_blank')
58565             .attr('tabindex', -1)
58566             .text(String);
58567
58568         if (u.length > limit) {
58569             var count = select(document.createElement('span'));
58570
58571             count.append('a')
58572                 .attr('target', '_blank')
58573                 .attr('tabindex', -1)
58574                 .attr('href', function() {
58575                     return context.connection().changesetsURL(context.map().center(), context.map().zoom());
58576                 })
58577                 .text(u.length - limit + 1);
58578
58579             wrap.append('span')
58580                 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
58581
58582         } else {
58583             wrap.append('span')
58584                 .html(t('contributors.list', { users: userList.html() }));
58585         }
58586
58587         if (!u.length) {
58588             hidden = true;
58589             wrap
58590                 .transition()
58591                 .style('opacity', 0);
58592
58593         } else if (hidden) {
58594             wrap
58595                 .transition()
58596                 .style('opacity', 1);
58597         }
58598     }
58599
58600
58601     return function(selection$$1) {
58602         wrap = selection$$1;
58603         update();
58604
58605         context.connection().on('loaded.contributors', debouncedUpdate);
58606         context.map().on('move.contributors', debouncedUpdate);
58607     };
58608 }
58609
58610 function uiFeatureInfo(context) {
58611     function update(selection$$1) {
58612         var features = context.features(),
58613             stats = features.stats(),
58614             count = 0,
58615             hiddenList = lodash.compact(lodash.map(features.hidden(), function(k) {
58616                 if (stats[k]) {
58617                     count += stats[k];
58618                     return String(stats[k]) + ' ' + t('feature.' + k + '.description');
58619                 }
58620             }));
58621
58622         selection$$1.html('');
58623
58624         if (hiddenList.length) {
58625             var tooltipBehavior = tooltip()
58626                     .placement('top')
58627                     .html(true)
58628                     .title(function() {
58629                         return uiTooltipHtml(hiddenList.join('<br/>'));
58630                     });
58631
58632             var warning = selection$$1.append('a')
58633                 .attr('href', '#')
58634                 .attr('tabindex', -1)
58635                 .html(t('feature_info.hidden_warning', { count: count }))
58636                 .call(tooltipBehavior)
58637                 .on('click', function() {
58638                     tooltipBehavior.hide(warning);
58639                     // open map data panel?
58640                     event.preventDefault();
58641                 });
58642         }
58643
58644         selection$$1
58645             .classed('hide', !hiddenList.length);
58646     }
58647
58648
58649     return function(selection$$1) {
58650         update(selection$$1);
58651
58652         context.features().on('change.feature_info', function() {
58653             update(selection$$1);
58654         });
58655     };
58656 }
58657
58658 function uiFullScreen(context) {
58659     var element = context.container().node(),
58660         keybinding = d3keybinding('full-screen');
58661         // button;
58662
58663
58664     function getFullScreenFn() {
58665         if (element.requestFullscreen) {
58666             return element.requestFullscreen;
58667         } else if (element.msRequestFullscreen) {
58668             return element.msRequestFullscreen;
58669         } else if (element.mozRequestFullScreen) {
58670             return element.mozRequestFullScreen;
58671         } else if (element.webkitRequestFullscreen) {
58672             return element.webkitRequestFullscreen;
58673         }
58674     }
58675
58676
58677     function getExitFullScreenFn() {
58678         if (document.exitFullscreen) {
58679             return document.exitFullscreen;
58680         } else if (document.msExitFullscreen) {
58681             return document.msExitFullscreen;
58682         } else if (document.mozCancelFullScreen) {
58683             return document.mozCancelFullScreen;
58684         } else if (document.webkitExitFullscreen) {
58685             return document.webkitExitFullscreen;
58686         }
58687     }
58688
58689
58690     function isFullScreen() {
58691         return document.fullscreenElement ||
58692             document.mozFullScreenElement ||
58693             document.webkitFullscreenElement ||
58694             document.msFullscreenElement;
58695     }
58696
58697
58698     function isSupported() {
58699         return !!getFullScreenFn();
58700     }
58701
58702
58703     function fullScreen() {
58704         event.preventDefault();
58705         if (!isFullScreen()) {
58706             // button.classed('active', true);
58707             getFullScreenFn().apply(element);
58708         } else {
58709             // button.classed('active', false);
58710             getExitFullScreenFn().apply(document);
58711         }
58712     }
58713
58714
58715     return function() { // selection) {
58716         if (!isSupported())
58717             return;
58718
58719         // button = selection.append('button')
58720         //     .attr('title', t('full_screen'))
58721         //     .attr('tabindex', -1)
58722         //     .on('click', fullScreen)
58723         //     .call(tooltip);
58724
58725         // button.append('span')
58726         //     .attr('class', 'icon full-screen');
58727
58728         var detected = utilDetect();
58729         var keys$$1 = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
58730         keybinding.on(keys$$1, fullScreen);
58731
58732         select(document)
58733             .call(keybinding);
58734     };
58735 }
58736
58737 function uiModal(selection$$1, blocking) {
58738     var keybinding = d3keybinding('modal');
58739     var previous = selection$$1.select('div.modal');
58740     var animate = previous.empty();
58741
58742     previous.transition()
58743         .duration(200)
58744         .style('opacity', 0)
58745         .remove();
58746
58747     var shaded = selection$$1
58748         .append('div')
58749         .attr('class', 'shaded')
58750         .style('opacity', 0);
58751
58752     shaded.close = function() {
58753         shaded
58754             .transition()
58755             .duration(200)
58756             .style('opacity',0)
58757             .remove();
58758
58759         modal
58760             .transition()
58761             .duration(200)
58762             .style('top','0px');
58763
58764         keybinding.off();
58765     };
58766
58767
58768     var modal = shaded
58769         .append('div')
58770         .attr('class', 'modal fillL col6');
58771
58772     if (!blocking) {
58773         shaded.on('click.remove-modal', function() {
58774             if (event.target === this) {
58775                 shaded.close();
58776             }
58777         });
58778
58779         modal.append('button')
58780             .attr('class', 'close')
58781             .on('click', shaded.close)
58782             .call(svgIcon('#icon-close'));
58783
58784         keybinding
58785             .on('⌫', shaded.close)
58786             .on('⎋', shaded.close);
58787
58788         select(document)
58789             .call(keybinding);
58790     }
58791
58792     modal
58793         .append('div')
58794         .attr('class', 'content');
58795
58796     if (animate) {
58797         shaded.transition().style('opacity', 1);
58798     } else {
58799         shaded.style('opacity', 1);
58800     }
58801
58802
58803     return shaded;
58804 }
58805
58806 function uiLoading(context) {
58807     var message = '',
58808         blocking = false,
58809         modalSelection;
58810
58811
58812     var loading = function(selection) {
58813         modalSelection = uiModal(selection, blocking);
58814
58815         var loadertext = modalSelection.select('.content')
58816             .classed('loading-modal', true)
58817             .append('div')
58818             .attr('class', 'modal-section fillL');
58819
58820         loadertext
58821             .append('img')
58822             .attr('class', 'loader')
58823             .attr('src', context.imagePath('loader-white.gif'));
58824
58825         loadertext
58826             .append('h3')
58827             .text(message);
58828
58829         modalSelection.select('button.close')
58830             .attr('class', 'hide');
58831
58832         return loading;
58833     };
58834
58835
58836     loading.message = function(_) {
58837         if (!arguments.length) return message;
58838         message = _;
58839         return loading;
58840     };
58841
58842
58843     loading.blocking = function(_) {
58844         if (!arguments.length) return blocking;
58845         blocking = _;
58846         return loading;
58847     };
58848
58849
58850     loading.close = function() {
58851         modalSelection.remove();
58852     };
58853
58854
58855     return loading;
58856 }
58857
58858 function uiGeolocate(context) {
58859     var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
58860         locating = uiLoading(context).message(t('geolocate.locating')).blocking(true),
58861         timeoutId;
58862
58863
58864     function click() {
58865         if (context.inIntro()) return;
58866         context.enter(modeBrowse(context));
58867         context.container().call(locating);
58868         navigator.geolocation.getCurrentPosition(success, error, geoOptions);
58869
58870         // This timeout ensures that we still call finish() even if
58871         // the user declines to share their location in Firefox
58872         timeoutId = setTimeout(finish, 10000 /* 10sec */ );
58873     }
58874
58875
58876     function success(position) {
58877         var map = context.map(),
58878             extent = geoExtent$$1([position.coords.longitude, position.coords.latitude])
58879                 .padByMeters(position.coords.accuracy);
58880
58881         map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
58882         finish();
58883     }
58884
58885
58886     function error() {
58887         finish();
58888     }
58889
58890
58891     function finish() {
58892         locating.close();  // unblock ui
58893         if (timeoutId) { clearTimeout(timeoutId); }
58894         timeoutId = undefined;
58895     }
58896
58897
58898     return function(selection) {
58899         if (!navigator.geolocation) return;
58900
58901         selection
58902             .append('button')
58903             .attr('tabindex', -1)
58904             .attr('title', t('geolocate.title'))
58905             .on('click', click)
58906             .call(svgIcon('#icon-geolocate', 'light'))
58907             .call(tooltip()
58908                 .placement((textDirection === 'rtl') ? 'right' : 'left'));
58909     };
58910 }
58911
58912 var marked = createCommonjsModule(function (module, exports) {
58913 /**
58914  * marked - a markdown parser
58915  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
58916  * https://github.com/chjj/marked
58917  */
58918
58919 (function() {
58920
58921 /**
58922  * Block-Level Grammar
58923  */
58924
58925 var block = {
58926   newline: /^\n+/,
58927   code: /^( {4}[^\n]+\n*)+/,
58928   fences: noop,
58929   hr: /^( *[-*_]){3,} *(?:\n+|$)/,
58930   heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
58931   nptable: noop,
58932   lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
58933   blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
58934   list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
58935   html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
58936   def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
58937   table: noop,
58938   paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
58939   text: /^[^\n]+/
58940 };
58941
58942 block.bullet = /(?:[*+-]|\d+\.)/;
58943 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
58944 block.item = replace(block.item, 'gm')
58945   (/bull/g, block.bullet)
58946   ();
58947
58948 block.list = replace(block.list)
58949   (/bull/g, block.bullet)
58950   ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
58951   ('def', '\\n+(?=' + block.def.source + ')')
58952   ();
58953
58954 block.blockquote = replace(block.blockquote)
58955   ('def', block.def)
58956   ();
58957
58958 block._tag = '(?!(?:'
58959   + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
58960   + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
58961   + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
58962
58963 block.html = replace(block.html)
58964   ('comment', /<!--[\s\S]*?-->/)
58965   ('closed', /<(tag)[\s\S]+?<\/\1>/)
58966   ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
58967   (/tag/g, block._tag)
58968   ();
58969
58970 block.paragraph = replace(block.paragraph)
58971   ('hr', block.hr)
58972   ('heading', block.heading)
58973   ('lheading', block.lheading)
58974   ('blockquote', block.blockquote)
58975   ('tag', '<' + block._tag)
58976   ('def', block.def)
58977   ();
58978
58979 /**
58980  * Normal Block Grammar
58981  */
58982
58983 block.normal = merge({}, block);
58984
58985 /**
58986  * GFM Block Grammar
58987  */
58988
58989 block.gfm = merge({}, block.normal, {
58990   fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
58991   paragraph: /^/,
58992   heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
58993 });
58994
58995 block.gfm.paragraph = replace(block.paragraph)
58996   ('(?!', '(?!'
58997     + block.gfm.fences.source.replace('\\1', '\\2') + '|'
58998     + block.list.source.replace('\\1', '\\3') + '|')
58999   ();
59000
59001 /**
59002  * GFM + Tables Block Grammar
59003  */
59004
59005 block.tables = merge({}, block.gfm, {
59006   nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
59007   table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
59008 });
59009
59010 /**
59011  * Block Lexer
59012  */
59013
59014 function Lexer(options) {
59015   this.tokens = [];
59016   this.tokens.links = {};
59017   this.options = options || marked.defaults;
59018   this.rules = block.normal;
59019
59020   if (this.options.gfm) {
59021     if (this.options.tables) {
59022       this.rules = block.tables;
59023     } else {
59024       this.rules = block.gfm;
59025     }
59026   }
59027 }
59028
59029 /**
59030  * Expose Block Rules
59031  */
59032
59033 Lexer.rules = block;
59034
59035 /**
59036  * Static Lex Method
59037  */
59038
59039 Lexer.lex = function(src, options) {
59040   var lexer = new Lexer(options);
59041   return lexer.lex(src);
59042 };
59043
59044 /**
59045  * Preprocessing
59046  */
59047
59048 Lexer.prototype.lex = function(src) {
59049   src = src
59050     .replace(/\r\n|\r/g, '\n')
59051     .replace(/\t/g, '    ')
59052     .replace(/\u00a0/g, ' ')
59053     .replace(/\u2424/g, '\n');
59054
59055   return this.token(src, true);
59056 };
59057
59058 /**
59059  * Lexing
59060  */
59061
59062 Lexer.prototype.token = function(src, top, bq) {
59063   var src = src.replace(/^ +$/gm, '')
59064     , next
59065     , loose
59066     , cap
59067     , bull
59068     , b
59069     , item
59070     , space
59071     , i
59072     , l;
59073
59074   while (src) {
59075     // newline
59076     if (cap = this.rules.newline.exec(src)) {
59077       src = src.substring(cap[0].length);
59078       if (cap[0].length > 1) {
59079         this.tokens.push({
59080           type: 'space'
59081         });
59082       }
59083     }
59084
59085     // code
59086     if (cap = this.rules.code.exec(src)) {
59087       src = src.substring(cap[0].length);
59088       cap = cap[0].replace(/^ {4}/gm, '');
59089       this.tokens.push({
59090         type: 'code',
59091         text: !this.options.pedantic
59092           ? cap.replace(/\n+$/, '')
59093           : cap
59094       });
59095       continue;
59096     }
59097
59098     // fences (gfm)
59099     if (cap = this.rules.fences.exec(src)) {
59100       src = src.substring(cap[0].length);
59101       this.tokens.push({
59102         type: 'code',
59103         lang: cap[2],
59104         text: cap[3] || ''
59105       });
59106       continue;
59107     }
59108
59109     // heading
59110     if (cap = this.rules.heading.exec(src)) {
59111       src = src.substring(cap[0].length);
59112       this.tokens.push({
59113         type: 'heading',
59114         depth: cap[1].length,
59115         text: cap[2]
59116       });
59117       continue;
59118     }
59119
59120     // table no leading pipe (gfm)
59121     if (top && (cap = this.rules.nptable.exec(src))) {
59122       src = src.substring(cap[0].length);
59123
59124       item = {
59125         type: 'table',
59126         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
59127         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
59128         cells: cap[3].replace(/\n$/, '').split('\n')
59129       };
59130
59131       for (i = 0; i < item.align.length; i++) {
59132         if (/^ *-+: *$/.test(item.align[i])) {
59133           item.align[i] = 'right';
59134         } else if (/^ *:-+: *$/.test(item.align[i])) {
59135           item.align[i] = 'center';
59136         } else if (/^ *:-+ *$/.test(item.align[i])) {
59137           item.align[i] = 'left';
59138         } else {
59139           item.align[i] = null;
59140         }
59141       }
59142
59143       for (i = 0; i < item.cells.length; i++) {
59144         item.cells[i] = item.cells[i].split(/ *\| */);
59145       }
59146
59147       this.tokens.push(item);
59148
59149       continue;
59150     }
59151
59152     // lheading
59153     if (cap = this.rules.lheading.exec(src)) {
59154       src = src.substring(cap[0].length);
59155       this.tokens.push({
59156         type: 'heading',
59157         depth: cap[2] === '=' ? 1 : 2,
59158         text: cap[1]
59159       });
59160       continue;
59161     }
59162
59163     // hr
59164     if (cap = this.rules.hr.exec(src)) {
59165       src = src.substring(cap[0].length);
59166       this.tokens.push({
59167         type: 'hr'
59168       });
59169       continue;
59170     }
59171
59172     // blockquote
59173     if (cap = this.rules.blockquote.exec(src)) {
59174       src = src.substring(cap[0].length);
59175
59176       this.tokens.push({
59177         type: 'blockquote_start'
59178       });
59179
59180       cap = cap[0].replace(/^ *> ?/gm, '');
59181
59182       // Pass `top` to keep the current
59183       // "toplevel" state. This is exactly
59184       // how markdown.pl works.
59185       this.token(cap, top, true);
59186
59187       this.tokens.push({
59188         type: 'blockquote_end'
59189       });
59190
59191       continue;
59192     }
59193
59194     // list
59195     if (cap = this.rules.list.exec(src)) {
59196       src = src.substring(cap[0].length);
59197       bull = cap[2];
59198
59199       this.tokens.push({
59200         type: 'list_start',
59201         ordered: bull.length > 1
59202       });
59203
59204       // Get each top-level item.
59205       cap = cap[0].match(this.rules.item);
59206
59207       next = false;
59208       l = cap.length;
59209       i = 0;
59210
59211       for (; i < l; i++) {
59212         item = cap[i];
59213
59214         // Remove the list item's bullet
59215         // so it is seen as the next token.
59216         space = item.length;
59217         item = item.replace(/^ *([*+-]|\d+\.) +/, '');
59218
59219         // Outdent whatever the
59220         // list item contains. Hacky.
59221         if (~item.indexOf('\n ')) {
59222           space -= item.length;
59223           item = !this.options.pedantic
59224             ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
59225             : item.replace(/^ {1,4}/gm, '');
59226         }
59227
59228         // Determine whether the next list item belongs here.
59229         // Backpedal if it does not belong in this list.
59230         if (this.options.smartLists && i !== l - 1) {
59231           b = block.bullet.exec(cap[i + 1])[0];
59232           if (bull !== b && !(bull.length > 1 && b.length > 1)) {
59233             src = cap.slice(i + 1).join('\n') + src;
59234             i = l - 1;
59235           }
59236         }
59237
59238         // Determine whether item is loose or not.
59239         // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
59240         // for discount behavior.
59241         loose = next || /\n\n(?!\s*$)/.test(item);
59242         if (i !== l - 1) {
59243           next = item.charAt(item.length - 1) === '\n';
59244           if (!loose) loose = next;
59245         }
59246
59247         this.tokens.push({
59248           type: loose
59249             ? 'loose_item_start'
59250             : 'list_item_start'
59251         });
59252
59253         // Recurse.
59254         this.token(item, false, bq);
59255
59256         this.tokens.push({
59257           type: 'list_item_end'
59258         });
59259       }
59260
59261       this.tokens.push({
59262         type: 'list_end'
59263       });
59264
59265       continue;
59266     }
59267
59268     // html
59269     if (cap = this.rules.html.exec(src)) {
59270       src = src.substring(cap[0].length);
59271       this.tokens.push({
59272         type: this.options.sanitize
59273           ? 'paragraph'
59274           : 'html',
59275         pre: !this.options.sanitizer
59276           && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
59277         text: cap[0]
59278       });
59279       continue;
59280     }
59281
59282     // def
59283     if ((!bq && top) && (cap = this.rules.def.exec(src))) {
59284       src = src.substring(cap[0].length);
59285       this.tokens.links[cap[1].toLowerCase()] = {
59286         href: cap[2],
59287         title: cap[3]
59288       };
59289       continue;
59290     }
59291
59292     // table (gfm)
59293     if (top && (cap = this.rules.table.exec(src))) {
59294       src = src.substring(cap[0].length);
59295
59296       item = {
59297         type: 'table',
59298         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
59299         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
59300         cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
59301       };
59302
59303       for (i = 0; i < item.align.length; i++) {
59304         if (/^ *-+: *$/.test(item.align[i])) {
59305           item.align[i] = 'right';
59306         } else if (/^ *:-+: *$/.test(item.align[i])) {
59307           item.align[i] = 'center';
59308         } else if (/^ *:-+ *$/.test(item.align[i])) {
59309           item.align[i] = 'left';
59310         } else {
59311           item.align[i] = null;
59312         }
59313       }
59314
59315       for (i = 0; i < item.cells.length; i++) {
59316         item.cells[i] = item.cells[i]
59317           .replace(/^ *\| *| *\| *$/g, '')
59318           .split(/ *\| */);
59319       }
59320
59321       this.tokens.push(item);
59322
59323       continue;
59324     }
59325
59326     // top-level paragraph
59327     if (top && (cap = this.rules.paragraph.exec(src))) {
59328       src = src.substring(cap[0].length);
59329       this.tokens.push({
59330         type: 'paragraph',
59331         text: cap[1].charAt(cap[1].length - 1) === '\n'
59332           ? cap[1].slice(0, -1)
59333           : cap[1]
59334       });
59335       continue;
59336     }
59337
59338     // text
59339     if (cap = this.rules.text.exec(src)) {
59340       // Top-level should never reach here.
59341       src = src.substring(cap[0].length);
59342       this.tokens.push({
59343         type: 'text',
59344         text: cap[0]
59345       });
59346       continue;
59347     }
59348
59349     if (src) {
59350       throw new
59351         Error('Infinite loop on byte: ' + src.charCodeAt(0));
59352     }
59353   }
59354
59355   return this.tokens;
59356 };
59357
59358 /**
59359  * Inline-Level Grammar
59360  */
59361
59362 var inline = {
59363   escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
59364   autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
59365   url: noop,
59366   tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
59367   link: /^!?\[(inside)\]\(href\)/,
59368   reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
59369   nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
59370   strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
59371   em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
59372   code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
59373   br: /^ {2,}\n(?!\s*$)/,
59374   del: noop,
59375   text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
59376 };
59377
59378 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
59379 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
59380
59381 inline.link = replace(inline.link)
59382   ('inside', inline._inside)
59383   ('href', inline._href)
59384   ();
59385
59386 inline.reflink = replace(inline.reflink)
59387   ('inside', inline._inside)
59388   ();
59389
59390 /**
59391  * Normal Inline Grammar
59392  */
59393
59394 inline.normal = merge({}, inline);
59395
59396 /**
59397  * Pedantic Inline Grammar
59398  */
59399
59400 inline.pedantic = merge({}, inline.normal, {
59401   strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
59402   em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
59403 });
59404
59405 /**
59406  * GFM Inline Grammar
59407  */
59408
59409 inline.gfm = merge({}, inline.normal, {
59410   escape: replace(inline.escape)('])', '~|])')(),
59411   url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
59412   del: /^~~(?=\S)([\s\S]*?\S)~~/,
59413   text: replace(inline.text)
59414     (']|', '~]|')
59415     ('|', '|https?://|')
59416     ()
59417 });
59418
59419 /**
59420  * GFM + Line Breaks Inline Grammar
59421  */
59422
59423 inline.breaks = merge({}, inline.gfm, {
59424   br: replace(inline.br)('{2,}', '*')(),
59425   text: replace(inline.gfm.text)('{2,}', '*')()
59426 });
59427
59428 /**
59429  * Inline Lexer & Compiler
59430  */
59431
59432 function InlineLexer(links, options) {
59433   this.options = options || marked.defaults;
59434   this.links = links;
59435   this.rules = inline.normal;
59436   this.renderer = this.options.renderer || new Renderer;
59437   this.renderer.options = this.options;
59438
59439   if (!this.links) {
59440     throw new
59441       Error('Tokens array requires a `links` property.');
59442   }
59443
59444   if (this.options.gfm) {
59445     if (this.options.breaks) {
59446       this.rules = inline.breaks;
59447     } else {
59448       this.rules = inline.gfm;
59449     }
59450   } else if (this.options.pedantic) {
59451     this.rules = inline.pedantic;
59452   }
59453 }
59454
59455 /**
59456  * Expose Inline Rules
59457  */
59458
59459 InlineLexer.rules = inline;
59460
59461 /**
59462  * Static Lexing/Compiling Method
59463  */
59464
59465 InlineLexer.output = function(src, links, options) {
59466   var inline = new InlineLexer(links, options);
59467   return inline.output(src);
59468 };
59469
59470 /**
59471  * Lexing/Compiling
59472  */
59473
59474 InlineLexer.prototype.output = function(src) {
59475   var out = ''
59476     , link
59477     , text
59478     , href
59479     , cap;
59480
59481   while (src) {
59482     // escape
59483     if (cap = this.rules.escape.exec(src)) {
59484       src = src.substring(cap[0].length);
59485       out += cap[1];
59486       continue;
59487     }
59488
59489     // autolink
59490     if (cap = this.rules.autolink.exec(src)) {
59491       src = src.substring(cap[0].length);
59492       if (cap[2] === '@') {
59493         text = cap[1].charAt(6) === ':'
59494           ? this.mangle(cap[1].substring(7))
59495           : this.mangle(cap[1]);
59496         href = this.mangle('mailto:') + text;
59497       } else {
59498         text = escape(cap[1]);
59499         href = text;
59500       }
59501       out += this.renderer.link(href, null, text);
59502       continue;
59503     }
59504
59505     // url (gfm)
59506     if (!this.inLink && (cap = this.rules.url.exec(src))) {
59507       src = src.substring(cap[0].length);
59508       text = escape(cap[1]);
59509       href = text;
59510       out += this.renderer.link(href, null, text);
59511       continue;
59512     }
59513
59514     // tag
59515     if (cap = this.rules.tag.exec(src)) {
59516       if (!this.inLink && /^<a /i.test(cap[0])) {
59517         this.inLink = true;
59518       } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
59519         this.inLink = false;
59520       }
59521       src = src.substring(cap[0].length);
59522       out += this.options.sanitize
59523         ? this.options.sanitizer
59524           ? this.options.sanitizer(cap[0])
59525           : escape(cap[0])
59526         : cap[0];
59527       continue;
59528     }
59529
59530     // link
59531     if (cap = this.rules.link.exec(src)) {
59532       src = src.substring(cap[0].length);
59533       this.inLink = true;
59534       out += this.outputLink(cap, {
59535         href: cap[2],
59536         title: cap[3]
59537       });
59538       this.inLink = false;
59539       continue;
59540     }
59541
59542     // reflink, nolink
59543     if ((cap = this.rules.reflink.exec(src))
59544         || (cap = this.rules.nolink.exec(src))) {
59545       src = src.substring(cap[0].length);
59546       link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
59547       link = this.links[link.toLowerCase()];
59548       if (!link || !link.href) {
59549         out += cap[0].charAt(0);
59550         src = cap[0].substring(1) + src;
59551         continue;
59552       }
59553       this.inLink = true;
59554       out += this.outputLink(cap, link);
59555       this.inLink = false;
59556       continue;
59557     }
59558
59559     // strong
59560     if (cap = this.rules.strong.exec(src)) {
59561       src = src.substring(cap[0].length);
59562       out += this.renderer.strong(this.output(cap[2] || cap[1]));
59563       continue;
59564     }
59565
59566     // em
59567     if (cap = this.rules.em.exec(src)) {
59568       src = src.substring(cap[0].length);
59569       out += this.renderer.em(this.output(cap[2] || cap[1]));
59570       continue;
59571     }
59572
59573     // code
59574     if (cap = this.rules.code.exec(src)) {
59575       src = src.substring(cap[0].length);
59576       out += this.renderer.codespan(escape(cap[2], true));
59577       continue;
59578     }
59579
59580     // br
59581     if (cap = this.rules.br.exec(src)) {
59582       src = src.substring(cap[0].length);
59583       out += this.renderer.br();
59584       continue;
59585     }
59586
59587     // del (gfm)
59588     if (cap = this.rules.del.exec(src)) {
59589       src = src.substring(cap[0].length);
59590       out += this.renderer.del(this.output(cap[1]));
59591       continue;
59592     }
59593
59594     // text
59595     if (cap = this.rules.text.exec(src)) {
59596       src = src.substring(cap[0].length);
59597       out += this.renderer.text(escape(this.smartypants(cap[0])));
59598       continue;
59599     }
59600
59601     if (src) {
59602       throw new
59603         Error('Infinite loop on byte: ' + src.charCodeAt(0));
59604     }
59605   }
59606
59607   return out;
59608 };
59609
59610 /**
59611  * Compile Link
59612  */
59613
59614 InlineLexer.prototype.outputLink = function(cap, link) {
59615   var href = escape(link.href)
59616     , title = link.title ? escape(link.title) : null;
59617
59618   return cap[0].charAt(0) !== '!'
59619     ? this.renderer.link(href, title, this.output(cap[1]))
59620     : this.renderer.image(href, title, escape(cap[1]));
59621 };
59622
59623 /**
59624  * Smartypants Transformations
59625  */
59626
59627 InlineLexer.prototype.smartypants = function(text) {
59628   if (!this.options.smartypants) return text;
59629   return text
59630     // em-dashes
59631     .replace(/---/g, '\u2014')
59632     // en-dashes
59633     .replace(/--/g, '\u2013')
59634     // opening singles
59635     .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
59636     // closing singles & apostrophes
59637     .replace(/'/g, '\u2019')
59638     // opening doubles
59639     .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
59640     // closing doubles
59641     .replace(/"/g, '\u201d')
59642     // ellipses
59643     .replace(/\.{3}/g, '\u2026');
59644 };
59645
59646 /**
59647  * Mangle Links
59648  */
59649
59650 InlineLexer.prototype.mangle = function(text) {
59651   if (!this.options.mangle) return text;
59652   var out = ''
59653     , l = text.length
59654     , i = 0
59655     , ch;
59656
59657   for (; i < l; i++) {
59658     ch = text.charCodeAt(i);
59659     if (Math.random() > 0.5) {
59660       ch = 'x' + ch.toString(16);
59661     }
59662     out += '&#' + ch + ';';
59663   }
59664
59665   return out;
59666 };
59667
59668 /**
59669  * Renderer
59670  */
59671
59672 function Renderer(options) {
59673   this.options = options || {};
59674 }
59675
59676 Renderer.prototype.code = function(code, lang, escaped) {
59677   if (this.options.highlight) {
59678     var out = this.options.highlight(code, lang);
59679     if (out != null && out !== code) {
59680       escaped = true;
59681       code = out;
59682     }
59683   }
59684
59685   if (!lang) {
59686     return '<pre><code>'
59687       + (escaped ? code : escape(code, true))
59688       + '\n</code></pre>';
59689   }
59690
59691   return '<pre><code class="'
59692     + this.options.langPrefix
59693     + escape(lang, true)
59694     + '">'
59695     + (escaped ? code : escape(code, true))
59696     + '\n</code></pre>\n';
59697 };
59698
59699 Renderer.prototype.blockquote = function(quote) {
59700   return '<blockquote>\n' + quote + '</blockquote>\n';
59701 };
59702
59703 Renderer.prototype.html = function(html) {
59704   return html;
59705 };
59706
59707 Renderer.prototype.heading = function(text, level, raw) {
59708   return '<h'
59709     + level
59710     + ' id="'
59711     + this.options.headerPrefix
59712     + raw.toLowerCase().replace(/[^\w]+/g, '-')
59713     + '">'
59714     + text
59715     + '</h'
59716     + level
59717     + '>\n';
59718 };
59719
59720 Renderer.prototype.hr = function() {
59721   return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
59722 };
59723
59724 Renderer.prototype.list = function(body, ordered) {
59725   var type = ordered ? 'ol' : 'ul';
59726   return '<' + type + '>\n' + body + '</' + type + '>\n';
59727 };
59728
59729 Renderer.prototype.listitem = function(text) {
59730   return '<li>' + text + '</li>\n';
59731 };
59732
59733 Renderer.prototype.paragraph = function(text) {
59734   return '<p>' + text + '</p>\n';
59735 };
59736
59737 Renderer.prototype.table = function(header, body) {
59738   return '<table>\n'
59739     + '<thead>\n'
59740     + header
59741     + '</thead>\n'
59742     + '<tbody>\n'
59743     + body
59744     + '</tbody>\n'
59745     + '</table>\n';
59746 };
59747
59748 Renderer.prototype.tablerow = function(content) {
59749   return '<tr>\n' + content + '</tr>\n';
59750 };
59751
59752 Renderer.prototype.tablecell = function(content, flags) {
59753   var type = flags.header ? 'th' : 'td';
59754   var tag = flags.align
59755     ? '<' + type + ' style="text-align:' + flags.align + '">'
59756     : '<' + type + '>';
59757   return tag + content + '</' + type + '>\n';
59758 };
59759
59760 // span level renderer
59761 Renderer.prototype.strong = function(text) {
59762   return '<strong>' + text + '</strong>';
59763 };
59764
59765 Renderer.prototype.em = function(text) {
59766   return '<em>' + text + '</em>';
59767 };
59768
59769 Renderer.prototype.codespan = function(text) {
59770   return '<code>' + text + '</code>';
59771 };
59772
59773 Renderer.prototype.br = function() {
59774   return this.options.xhtml ? '<br/>' : '<br>';
59775 };
59776
59777 Renderer.prototype.del = function(text) {
59778   return '<del>' + text + '</del>';
59779 };
59780
59781 Renderer.prototype.link = function(href, title, text) {
59782   if (this.options.sanitize) {
59783     try {
59784       var prot = decodeURIComponent(unescape(href))
59785         .replace(/[^\w:]/g, '')
59786         .toLowerCase();
59787     } catch (e) {
59788       return '';
59789     }
59790     if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
59791       return '';
59792     }
59793   }
59794   var out = '<a href="' + href + '"';
59795   if (title) {
59796     out += ' title="' + title + '"';
59797   }
59798   out += '>' + text + '</a>';
59799   return out;
59800 };
59801
59802 Renderer.prototype.image = function(href, title, text) {
59803   var out = '<img src="' + href + '" alt="' + text + '"';
59804   if (title) {
59805     out += ' title="' + title + '"';
59806   }
59807   out += this.options.xhtml ? '/>' : '>';
59808   return out;
59809 };
59810
59811 Renderer.prototype.text = function(text) {
59812   return text;
59813 };
59814
59815 /**
59816  * Parsing & Compiling
59817  */
59818
59819 function Parser(options) {
59820   this.tokens = [];
59821   this.token = null;
59822   this.options = options || marked.defaults;
59823   this.options.renderer = this.options.renderer || new Renderer;
59824   this.renderer = this.options.renderer;
59825   this.renderer.options = this.options;
59826 }
59827
59828 /**
59829  * Static Parse Method
59830  */
59831
59832 Parser.parse = function(src, options, renderer) {
59833   var parser = new Parser(options, renderer);
59834   return parser.parse(src);
59835 };
59836
59837 /**
59838  * Parse Loop
59839  */
59840
59841 Parser.prototype.parse = function(src) {
59842   this.inline = new InlineLexer(src.links, this.options, this.renderer);
59843   this.tokens = src.reverse();
59844
59845   var out = '';
59846   while (this.next()) {
59847     out += this.tok();
59848   }
59849
59850   return out;
59851 };
59852
59853 /**
59854  * Next Token
59855  */
59856
59857 Parser.prototype.next = function() {
59858   return this.token = this.tokens.pop();
59859 };
59860
59861 /**
59862  * Preview Next Token
59863  */
59864
59865 Parser.prototype.peek = function() {
59866   return this.tokens[this.tokens.length - 1] || 0;
59867 };
59868
59869 /**
59870  * Parse Text Tokens
59871  */
59872
59873 Parser.prototype.parseText = function() {
59874   var body = this.token.text;
59875
59876   while (this.peek().type === 'text') {
59877     body += '\n' + this.next().text;
59878   }
59879
59880   return this.inline.output(body);
59881 };
59882
59883 /**
59884  * Parse Current Token
59885  */
59886
59887 Parser.prototype.tok = function() {
59888   switch (this.token.type) {
59889     case 'space': {
59890       return '';
59891     }
59892     case 'hr': {
59893       return this.renderer.hr();
59894     }
59895     case 'heading': {
59896       return this.renderer.heading(
59897         this.inline.output(this.token.text),
59898         this.token.depth,
59899         this.token.text);
59900     }
59901     case 'code': {
59902       return this.renderer.code(this.token.text,
59903         this.token.lang,
59904         this.token.escaped);
59905     }
59906     case 'table': {
59907       var header = ''
59908         , body = ''
59909         , i
59910         , row
59911         , cell
59912         , flags
59913         , j;
59914
59915       // header
59916       cell = '';
59917       for (i = 0; i < this.token.header.length; i++) {
59918         flags = { header: true, align: this.token.align[i] };
59919         cell += this.renderer.tablecell(
59920           this.inline.output(this.token.header[i]),
59921           { header: true, align: this.token.align[i] }
59922         );
59923       }
59924       header += this.renderer.tablerow(cell);
59925
59926       for (i = 0; i < this.token.cells.length; i++) {
59927         row = this.token.cells[i];
59928
59929         cell = '';
59930         for (j = 0; j < row.length; j++) {
59931           cell += this.renderer.tablecell(
59932             this.inline.output(row[j]),
59933             { header: false, align: this.token.align[j] }
59934           );
59935         }
59936
59937         body += this.renderer.tablerow(cell);
59938       }
59939       return this.renderer.table(header, body);
59940     }
59941     case 'blockquote_start': {
59942       var body = '';
59943
59944       while (this.next().type !== 'blockquote_end') {
59945         body += this.tok();
59946       }
59947
59948       return this.renderer.blockquote(body);
59949     }
59950     case 'list_start': {
59951       var body = ''
59952         , ordered = this.token.ordered;
59953
59954       while (this.next().type !== 'list_end') {
59955         body += this.tok();
59956       }
59957
59958       return this.renderer.list(body, ordered);
59959     }
59960     case 'list_item_start': {
59961       var body = '';
59962
59963       while (this.next().type !== 'list_item_end') {
59964         body += this.token.type === 'text'
59965           ? this.parseText()
59966           : this.tok();
59967       }
59968
59969       return this.renderer.listitem(body);
59970     }
59971     case 'loose_item_start': {
59972       var body = '';
59973
59974       while (this.next().type !== 'list_item_end') {
59975         body += this.tok();
59976       }
59977
59978       return this.renderer.listitem(body);
59979     }
59980     case 'html': {
59981       var html = !this.token.pre && !this.options.pedantic
59982         ? this.inline.output(this.token.text)
59983         : this.token.text;
59984       return this.renderer.html(html);
59985     }
59986     case 'paragraph': {
59987       return this.renderer.paragraph(this.inline.output(this.token.text));
59988     }
59989     case 'text': {
59990       return this.renderer.paragraph(this.parseText());
59991     }
59992   }
59993 };
59994
59995 /**
59996  * Helpers
59997  */
59998
59999 function escape(html, encode) {
60000   return html
60001     .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
60002     .replace(/</g, '&lt;')
60003     .replace(/>/g, '&gt;')
60004     .replace(/"/g, '&quot;')
60005     .replace(/'/g, '&#39;');
60006 }
60007
60008 function unescape(html) {
60009         // explicitly match decimal, hex, and named HTML entities 
60010   return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
60011     n = n.toLowerCase();
60012     if (n === 'colon') return ':';
60013     if (n.charAt(0) === '#') {
60014       return n.charAt(1) === 'x'
60015         ? String.fromCharCode(parseInt(n.substring(2), 16))
60016         : String.fromCharCode(+n.substring(1));
60017     }
60018     return '';
60019   });
60020 }
60021
60022 function replace(regex, opt) {
60023   regex = regex.source;
60024   opt = opt || '';
60025   return function self(name, val) {
60026     if (!name) return new RegExp(regex, opt);
60027     val = val.source || val;
60028     val = val.replace(/(^|[^\[])\^/g, '$1');
60029     regex = regex.replace(name, val);
60030     return self;
60031   };
60032 }
60033
60034 function noop() {}
60035 noop.exec = noop;
60036
60037 function merge(obj) {
60038   var i = 1
60039     , target
60040     , key;
60041
60042   for (; i < arguments.length; i++) {
60043     target = arguments[i];
60044     for (key in target) {
60045       if (Object.prototype.hasOwnProperty.call(target, key)) {
60046         obj[key] = target[key];
60047       }
60048     }
60049   }
60050
60051   return obj;
60052 }
60053
60054
60055 /**
60056  * Marked
60057  */
60058
60059 function marked(src, opt, callback) {
60060   if (callback || typeof opt === 'function') {
60061     if (!callback) {
60062       callback = opt;
60063       opt = null;
60064     }
60065
60066     opt = merge({}, marked.defaults, opt || {});
60067
60068     var highlight = opt.highlight
60069       , tokens
60070       , pending
60071       , i = 0;
60072
60073     try {
60074       tokens = Lexer.lex(src, opt);
60075     } catch (e) {
60076       return callback(e);
60077     }
60078
60079     pending = tokens.length;
60080
60081     var done = function(err) {
60082       if (err) {
60083         opt.highlight = highlight;
60084         return callback(err);
60085       }
60086
60087       var out;
60088
60089       try {
60090         out = Parser.parse(tokens, opt);
60091       } catch (e) {
60092         err = e;
60093       }
60094
60095       opt.highlight = highlight;
60096
60097       return err
60098         ? callback(err)
60099         : callback(null, out);
60100     };
60101
60102     if (!highlight || highlight.length < 3) {
60103       return done();
60104     }
60105
60106     delete opt.highlight;
60107
60108     if (!pending) return done();
60109
60110     for (; i < tokens.length; i++) {
60111       (function(token) {
60112         if (token.type !== 'code') {
60113           return --pending || done();
60114         }
60115         return highlight(token.text, token.lang, function(err, code) {
60116           if (err) return done(err);
60117           if (code == null || code === token.text) {
60118             return --pending || done();
60119           }
60120           token.text = code;
60121           token.escaped = true;
60122           --pending || done();
60123         });
60124       })(tokens[i]);
60125     }
60126
60127     return;
60128   }
60129   try {
60130     if (opt) opt = merge({}, marked.defaults, opt);
60131     return Parser.parse(Lexer.lex(src, opt), opt);
60132   } catch (e) {
60133     e.message += '\nPlease report this to https://github.com/chjj/marked.';
60134     if ((opt || marked.defaults).silent) {
60135       return '<p>An error occured:</p><pre>'
60136         + escape(e.message + '', true)
60137         + '</pre>';
60138     }
60139     throw e;
60140   }
60141 }
60142
60143 /**
60144  * Options
60145  */
60146
60147 marked.options =
60148 marked.setOptions = function(opt) {
60149   merge(marked.defaults, opt);
60150   return marked;
60151 };
60152
60153 marked.defaults = {
60154   gfm: true,
60155   tables: true,
60156   breaks: false,
60157   pedantic: false,
60158   sanitize: false,
60159   sanitizer: null,
60160   mangle: true,
60161   smartLists: false,
60162   silent: false,
60163   highlight: null,
60164   langPrefix: 'lang-',
60165   smartypants: false,
60166   headerPrefix: '',
60167   renderer: new Renderer,
60168   xhtml: false
60169 };
60170
60171 /**
60172  * Expose
60173  */
60174
60175 marked.Parser = Parser;
60176 marked.parser = Parser.parse;
60177
60178 marked.Renderer = Renderer;
60179
60180 marked.Lexer = Lexer;
60181 marked.lexer = Lexer.lex;
60182
60183 marked.InlineLexer = InlineLexer;
60184 marked.inlineLexer = InlineLexer.output;
60185
60186 marked.parse = marked;
60187
60188 {
60189   module.exports = marked;
60190 }
60191
60192 }).call(function() {
60193   return this || (typeof window !== 'undefined' ? window : commonjsGlobal);
60194 }());
60195 });
60196
60197 function pointBox(loc, context) {
60198     var rect = context.surfaceRect();
60199     var point = context.curtainProjection(loc);
60200     return {
60201         left: point[0] + rect.left - 40,
60202         top: point[1] + rect.top - 60,
60203         width: 80,
60204         height: 90
60205     };
60206 }
60207
60208
60209 function pad$1(locOrBox, padding, context) {
60210     var box;
60211     if (locOrBox instanceof Array) {
60212         var rect = context.surfaceRect();
60213         var point = context.curtainProjection(locOrBox);
60214         box = {
60215             left: point[0] + rect.left,
60216             top: point[1] + rect.top
60217         };
60218     } else {
60219         box = locOrBox;
60220     }
60221
60222     return {
60223         left: box.left - padding,
60224         top: box.top - padding,
60225         width: (box.width || 0) + 2 * padding,
60226         height: (box.width || 0) + 2 * padding
60227     };
60228 }
60229
60230
60231 function icon(name, svgklass) {
60232     return '<svg class="icon ' + (svgklass || '') + '">' +
60233          '<use xlink:href="' + name + '"></use></svg>';
60234 }
60235
60236
60237 function slugify(text$$1) {
60238     return text$$1.toString().toLowerCase()
60239         .replace(/\s+/g, '-')           // Replace spaces with -
60240         .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
60241         .replace(/\-\-+/g, '-')         // Replace multiple - with single -
60242         .replace(/^-+/, '')             // Trim - from start of text
60243         .replace(/-+$/, '');            // Trim - from end of text
60244 }
60245
60246
60247 // console warning for missing walkthrough names
60248 var missingStrings = {};
60249 function checkKey(key, text$$1) {
60250     if (t(key, { default: undefined}) === undefined) {
60251         if (missingStrings.hasOwnProperty(key)) return;  // warn once
60252         missingStrings[key] = text$$1;
60253         var missing = key + ': ' + text$$1;
60254         if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
60255     }
60256 }
60257
60258
60259 function localize(obj) {
60260     var key;
60261
60262     // Assign name if entity has one..
60263     var name = obj.tags && obj.tags.name;
60264     if (name) {
60265         key = 'intro.graph.name.' + slugify(name);
60266         obj.tags.name = t(key, { default: name });
60267         checkKey(key, name);
60268     }
60269
60270     // Assign street name if entity has one..
60271     var street = obj.tags && obj.tags['addr:street'];
60272     if (street) {
60273         key = 'intro.graph.name.' + slugify(street);
60274         obj.tags['addr:street'] = t(key, { default: street });
60275         checkKey(key, street);
60276
60277         // Add address details common across walkthrough..
60278         var addrTags = [
60279             'block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood',
60280             'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'
60281         ];
60282         addrTags.forEach(function(k) {
60283             var key = 'intro.graph.' + k,
60284                 tag = 'addr:' + k,
60285                 val = obj.tags && obj.tags[tag],
60286                 str = t(key, { default: val });
60287
60288             if (str) {
60289                 if (str.match(/^<.*>$/) !== null) {
60290                     delete obj.tags[tag];
60291                 } else {
60292                     obj.tags[tag] = str;
60293                 }
60294             }
60295         });
60296     }
60297
60298     return obj;
60299 }
60300
60301
60302 // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
60303 function isMostlySquare(points) {
60304     // note: uses 15 here instead of the 12 from actionOrthogonalize because
60305     // actionOrthogonalize can actually straighten some larger angles as it iterates
60306     var threshold$$1 = 15, // degrees within right or straight
60307         lowerBound = Math.cos((90 - threshold$$1) * Math.PI / 180),  // near right
60308         upperBound = Math.cos(threshold$$1 * Math.PI / 180),         // near straight
60309         mag;
60310
60311     for (var i = 0; i < points.length; i++) {
60312         mag = Math.abs(normalizedDotProduct(i, points));
60313         if (mag > lowerBound && mag < upperBound) {
60314             return false;
60315         }
60316     }
60317
60318     return true;
60319
60320
60321     function normalizedDotProduct(i, points) {
60322         var a = points[(i - 1 + points.length) % points.length],
60323             b = points[i],
60324             c = points[(i + 1) % points.length],
60325             p = subtractPoints(a, b),
60326             q = subtractPoints(c, b);
60327
60328         p = normalizePoint(p);
60329         q = normalizePoint(q);
60330
60331         return p[0] * q[0] + p[1] * q[1];
60332
60333
60334         function subtractPoints(a, b) {
60335             return [a[0] - b[0], a[1] - b[1]];
60336         }
60337
60338         function normalizePoint(point) {
60339             var vector = [0, 0];
60340             var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
60341             if (length !== 0) {
60342                 vector[0] = point[0] / length;
60343                 vector[1] = point[1] / length;
60344             }
60345             return vector;
60346         }
60347     }
60348 }
60349
60350
60351 function selectMenuItem(operation) {
60352     var selector$$1 = '.edit-menu .edit-menu-item-' + operation +
60353         ', .radial-menu .radial-menu-item-' + operation;
60354     return select(selector$$1);
60355 }
60356
60357
60358 function transitionTime(point1, point2) {
60359     var distance$$1 = geoSphericalDistance(point1, point2);
60360     if (distance$$1 === 0)
60361         return 0;
60362     else if (distance$$1 < 80)
60363         return 500;
60364     else
60365         return 1000;
60366 }
60367
60368 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"}}};
60369
60370 // toggles the visibility of ui elements, using a combination of the
60371 // hide class, which sets display=none, and a d3 transition for opacity.
60372 // this will cause blinking when called repeatedly, so check that the
60373 // value actually changes between calls.
60374 function uiToggle(show, callback) {
60375     return function(selection$$1) {
60376         selection$$1
60377             .style('opacity', show ? 0 : 1)
60378             .classed('hide', false)
60379             .transition()
60380             .style('opacity', show ? 1 : 0)
60381             .on('end', function() {
60382                 select(this)
60383                     .classed('hide', !show)
60384                     .style('opacity', null);
60385                 if (callback) callback.apply(this);
60386             });
60387     };
60388 }
60389
60390 // Tooltips and svg mask used to highlight certain features
60391 function uiCurtain() {
60392
60393     var surface = select(null),
60394         tooltip = select(null),
60395         darkness = select(null);
60396
60397     function curtain(selection$$1) {
60398         surface = selection$$1
60399             .append('svg')
60400             .attr('id', 'curtain')
60401             .style('z-index', 1000)
60402             .style('pointer-events', 'none')
60403             .style('position', 'absolute')
60404             .style('top', 0)
60405             .style('left', 0);
60406
60407         darkness = surface.append('path')
60408             .attr('x', 0)
60409             .attr('y', 0)
60410             .attr('class', 'curtain-darkness');
60411
60412         select(window).on('resize.curtain', resize);
60413
60414         tooltip = selection$$1.append('div')
60415             .attr('class', 'tooltip')
60416             .style('z-index', 1002);
60417
60418         tooltip
60419             .append('div')
60420             .attr('class', 'tooltip-arrow');
60421
60422         tooltip
60423             .append('div')
60424             .attr('class', 'tooltip-inner');
60425
60426         resize();
60427
60428
60429         function resize() {
60430             surface
60431                 .attr('width', window.innerWidth)
60432                 .attr('height', window.innerHeight);
60433             curtain.cut(darkness.datum());
60434         }
60435     }
60436
60437
60438     /**
60439      * Reveal cuts the curtain to highlight the given box,
60440      * and shows a tooltip with instructions next to the box.
60441      *
60442      * @param  {String|ClientRect} [box]   box used to cut the curtain
60443      * @param  {String}    [text]          text for a tooltip
60444      * @param  {Object}    [options]
60445      * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
60446      * @param  {integer}   [options.duration]        transition time in milliseconds
60447      * @param  {string}    [options.buttonText]      if set, create a button with this text label
60448      * @param  {function}  [options.buttonCallback]  if set, the callback for the button
60449      * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
60450      */
60451     curtain.reveal = function(box, text$$1, options) {
60452         if (typeof box === 'string') {
60453             box = select(box).node();
60454         }
60455         if (box && box.getBoundingClientRect) {
60456             box = copyBox(box.getBoundingClientRect());
60457         }
60458
60459         options = options || {};
60460
60461         var tooltipBox;
60462         if (options.tooltipBox) {
60463             tooltipBox = options.tooltipBox;
60464             if (typeof tooltipBox === 'string') {
60465                 tooltipBox = select(tooltipBox).node();
60466             }
60467             if (tooltipBox && tooltipBox.getBoundingClientRect) {
60468                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
60469             }
60470         } else {
60471             tooltipBox = box;
60472         }
60473
60474         if (tooltipBox && text$$1) {
60475             // pseudo markdown bold text for the instruction section..
60476             var parts = text$$1.split('**');
60477             var html$$1 = parts[0] ? '<span>' + parts[0] + '</span>' : '';
60478             if (parts[1]) {
60479                 html$$1 += '<span class="instruction">' + parts[1] + '</span>';
60480             }
60481
60482             html$$1 = html$$1.replace(/\*(.*?)\*/g, '<em>$1</em>');   // emphasis
60483             html$$1 = html$$1.replace(/\{br\}/g, '<br/><br/>');       // linebreak
60484
60485             if (options.buttonText && options.buttonCallback) {
60486                 html$$1 += '<div class="button-section">' +
60487                     '<button href="#" class="button action col8">' + options.buttonText + '</button></div>';
60488             }
60489
60490             var classes = 'curtain-tooltip tooltip in ' + (options.tooltipClass || '');
60491             tooltip
60492                 .classed(classes, true)
60493                 .selectAll('.tooltip-inner')
60494                 .html(html$$1);
60495
60496             if (options.buttonText && options.buttonCallback) {
60497                 var button = tooltip.selectAll('.button-section .button.action');
60498                 button
60499                     .on('click', function() {
60500                         event.preventDefault();
60501                         options.buttonCallback();
60502                     });
60503             }
60504
60505             var tip = copyBox(tooltip.node().getBoundingClientRect()),
60506                 w = window.innerWidth,
60507                 h = window.innerHeight,
60508                 tooltipWidth = 200,
60509                 tooltipArrow = 5,
60510                 side, pos;
60511
60512
60513             // hack: this will have bottom placement,
60514             // so need to reserve extra space for the tooltip illustration.
60515             if (options.tooltipClass === 'intro-mouse') {
60516                 tip.height += 80;
60517             }
60518
60519             // trim box dimensions to just the portion that fits in the window..
60520             if (tooltipBox.top + tooltipBox.height > h) {
60521                 tooltipBox.height -= (tooltipBox.top + tooltipBox.height - h);
60522             }
60523             if (tooltipBox.left + tooltipBox.width > w) {
60524                 tooltipBox.width -= (tooltipBox.left + tooltipBox.width - w);
60525             }
60526
60527             // determine tooltip placement..
60528
60529             if (tooltipBox.top + tooltipBox.height < 100) {
60530                 // tooltip below box..
60531                 side = 'bottom';
60532                 pos = [
60533                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
60534                     tooltipBox.top + tooltipBox.height
60535                 ];
60536
60537             } else if (tooltipBox.top > h - 140) {
60538                 // tooltip above box..
60539                 side = 'top';
60540                 pos = [
60541                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
60542                     tooltipBox.top - tip.height
60543                 ];
60544
60545             } else {
60546                 // tooltip to the side of the tooltipBox..
60547                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
60548
60549                 if (textDirection === 'rtl') {
60550                     if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
60551                         side = 'right';
60552                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
60553
60554                     } else {
60555                         side = 'left';
60556                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
60557                     }
60558
60559                 } else {
60560                     if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
60561                         side = 'left';
60562                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
60563                     }
60564                     else {
60565                         side = 'right';
60566                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
60567                     }
60568                 }
60569             }
60570
60571             if (options.duration !== 0 || !tooltip.classed(side)) {
60572                 tooltip.call(uiToggle(true));
60573             }
60574
60575             tooltip
60576                 .style('top', pos[1] + 'px')
60577                 .style('left', pos[0] + 'px')
60578                 .attr('class', classes + ' ' + side);
60579
60580
60581             // shift tooltip-inner if it is very close to the top or bottom edge
60582             // (doesn't affect the placement of the tooltip-arrow)
60583             var shiftY = 0;
60584             if (side === 'left' || side === 'right') {
60585                 if (pos[1] < 60) {
60586                     shiftY = 60 - pos[1];
60587                 }
60588                 else if (pos[1] + tip.height > h - 100) {
60589                     shiftY = h - pos[1] - tip.height - 100;
60590                 }
60591             }
60592             tooltip.selectAll('.tooltip-inner')
60593                 .style('top', shiftY + 'px');
60594
60595         } else {
60596             tooltip
60597                 .classed('in', false)
60598                 .call(uiToggle(false));
60599         }
60600
60601         curtain.cut(box, options.duration);
60602
60603         return tooltip;
60604     };
60605
60606
60607     curtain.cut = function(datum, duration) {
60608         darkness.datum(datum)
60609             .interrupt();
60610
60611         var selection$$1;
60612         if (duration === 0) {
60613             selection$$1 = darkness;
60614         } else {
60615             selection$$1 = darkness
60616                 .transition()
60617                 .duration(duration || 600)
60618                 .ease(linear$1);
60619         }
60620
60621         selection$$1
60622             .attr('d', function(d) {
60623                 var string = 'M 0,0 L 0,' + window.innerHeight + ' L ' +
60624                     window.innerWidth + ',' + window.innerHeight + 'L' +
60625                     window.innerWidth + ',0 Z';
60626
60627                 if (!d) return string;
60628                 return string + 'M' +
60629                     d.left + ',' + d.top + 'L' +
60630                     d.left + ',' + (d.top + d.height) + 'L' +
60631                     (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
60632                     (d.left + d.width) + ',' + (d.top) + 'Z';
60633
60634             });
60635     };
60636
60637
60638     curtain.remove = function() {
60639         surface.remove();
60640         tooltip.remove();
60641         select(window).on('resize.curtain', null);
60642     };
60643
60644
60645     // ClientRects are immutable, so copy them to an object,
60646     // in case we need to trim the height/width.
60647     function copyBox(src) {
60648         return {
60649             top: src.top,
60650             right: src.right,
60651             bottom: src.bottom,
60652             left: src.left,
60653             width: src.width,
60654             height: src.height
60655         };
60656     }
60657
60658
60659     return curtain;
60660 }
60661
60662 function uiIntroWelcome(context, reveal) {
60663     var dispatch$$1 = dispatch('done'),
60664         listener = clickListener();
60665
60666     var chapter = {
60667         title: 'intro.welcome.title'
60668     };
60669
60670
60671     function welcome() {
60672         context.map().centerZoom([-85.63591, 41.94285], 19);
60673         reveal('.intro-nav-wrap .chapter-welcome',
60674             t('intro.welcome.welcome'),
60675             { buttonText: t('intro.ok'), buttonCallback: practice }
60676         );
60677     }
60678
60679     function practice() {
60680         reveal('.intro-nav-wrap .chapter-welcome',
60681             t('intro.welcome.practice'),
60682             { buttonText: t('intro.ok'), buttonCallback: words }
60683         );
60684     }
60685
60686     function words() {
60687         reveal('.intro-nav-wrap .chapter-welcome',
60688             t('intro.welcome.words'),
60689             { buttonText: t('intro.ok'), buttonCallback: mouse$$1 }
60690         );
60691     }
60692
60693
60694     function mouse$$1() {
60695         reveal('.intro-nav-wrap .chapter-welcome',
60696             t('intro.welcome.mouse'),
60697             { buttonText: t('intro.ok'), buttonCallback: leftClick }
60698         );
60699     }
60700
60701
60702     function leftClick() {
60703         var counter = 0,
60704             times = 5;
60705
60706         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
60707             t('intro.welcome.leftclick', { num: times }),
60708             { tooltipClass: 'intro-mouse' }
60709         );
60710
60711         tooltip.selectAll('.tooltip-inner')
60712             .insert('svg', 'span')
60713             .attr('class', 'tooltip-illustration')
60714             .append('use')
60715             .attr('xlink:href', '#walkthrough-mouse');
60716
60717         tooltip
60718             .append('div')
60719             .attr('class', 'counter');
60720
60721         tooltip.call(listener);
60722
60723         listener.on('click', function(which) {
60724             if (which === 'left') {
60725                 select('.curtain-tooltip.intro-mouse .counter')
60726                     .text(String(++counter));
60727
60728                 if (counter === times) {
60729                     window.setTimeout(function() { continueTo(rightClick); }, 1000);
60730                 }
60731             }
60732         });
60733
60734         function continueTo(nextStep) {
60735             listener.on('click', null);
60736             tooltip.call(listener.off);
60737             tooltip.select('.counter').remove();
60738             nextStep();
60739         }
60740     }
60741
60742
60743     function rightClick() {
60744         var counter = 0,
60745             times = 5;
60746
60747         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
60748             t('intro.welcome.rightclick', { num: times }),
60749             { tooltipClass: 'intro-mouse' }
60750         );
60751
60752         tooltip.selectAll('.tooltip-inner')
60753             .insert('svg', 'span')
60754             .attr('class', 'tooltip-illustration')
60755             .append('use')
60756             .attr('xlink:href', '#walkthrough-mouse');
60757
60758         tooltip
60759             .append('div')
60760             .attr('class', 'counter');
60761
60762         tooltip.call(listener);
60763
60764         listener.on('click', function(which) {
60765             if (which === 'right') {
60766                 select('.curtain-tooltip.intro-mouse .counter')
60767                     .text(String(++counter));
60768
60769                 if (counter === times) {
60770                     window.setTimeout(function() { continueTo(chapters); }, 1000);
60771                 }
60772             }
60773         });
60774
60775         function continueTo(nextStep) {
60776             listener.on('click', null);
60777             tooltip.call(listener.off);
60778             tooltip.select('.counter').remove();
60779             nextStep();
60780         }
60781     }
60782
60783
60784     function chapters() {
60785         dispatch$$1.call('done');
60786         reveal('.intro-nav-wrap .chapter-navigation',
60787             t('intro.welcome.chapters', { next: t('intro.navigation.title') })
60788         );
60789     }
60790
60791
60792     chapter.enter = function() {
60793         welcome();
60794     };
60795
60796
60797     chapter.exit = function() {
60798         listener.off();
60799     };
60800
60801
60802     chapter.restart = function() {
60803         chapter.exit();
60804         chapter.enter();
60805     };
60806
60807
60808     return utilRebind(chapter, dispatch$$1, 'on');
60809 }
60810
60811
60812
60813 function clickListener() {
60814     var dispatch$$1 = dispatch('click'),
60815         minTime = 120,
60816         tooltip = select(null),
60817         down = {};
60818
60819     // `down` keeps track of which buttons/keys are down.
60820     // Setting a property in `down` happens immediately.
60821     // Unsetting a property in `down` is delayed because
60822     //   on Windows a contextmenu event happens after keyup/mouseup
60823
60824     function keydown() {
60825         if (event.keyCode === 93)  {   // context menu
60826             event.preventDefault();
60827             event.stopPropagation();
60828             down.menu = event.timeStamp;
60829             tooltip.classed('rightclick', true);
60830         }
60831     }
60832
60833
60834     function keyup() {
60835         if (event.keyCode === 93)  {   // context menu
60836             event.preventDefault();
60837             event.stopPropagation();
60838             var endTime = event.timeStamp,
60839                 startTime = down.menu || endTime,
60840                 delay = (endTime - startTime < minTime) ? minTime : 0;
60841
60842             window.setTimeout(function() {
60843                 tooltip.classed('rightclick', false);
60844                 down.menu = undefined;  // delayed, for Windows
60845             }, delay);
60846
60847             dispatch$$1.call('click', this, 'right');
60848         }
60849     }
60850
60851
60852     function mousedown() {
60853         var button = event.button;
60854         if (button === 0 && !event.ctrlKey) {
60855             tooltip.classed('leftclick', true);
60856         } else if (button === 2) {
60857             tooltip.classed('rightclick', true);
60858         }
60859         down[button] = event.timeStamp;
60860     }
60861
60862
60863     function mouseup() {
60864         var button = event.button,
60865             endTime = event.timeStamp,
60866             startTime = down[button] || endTime,
60867             delay = (endTime - startTime < minTime) ? minTime : 0;
60868
60869         if (button === 0 && !event.ctrlKey) {
60870             window.setTimeout(function() {
60871                 tooltip.classed('leftclick', false);
60872                 down[button] = undefined;  // delayed, for Windows
60873             }, delay);
60874
60875             dispatch$$1.call('click', this, 'left');
60876
60877         } else if (button === 2) {
60878             window.setTimeout(function() {
60879                 tooltip.classed('rightclick', false);
60880                 down[button] = undefined;  // delayed, for Windows
60881             }, delay);
60882
60883             dispatch$$1.call('click', this, 'right');
60884
60885         } else {
60886             window.setTimeout(function() {
60887                 down[button] = undefined;  // delayed, for Windows
60888             }, delay);
60889         }
60890     }
60891
60892
60893     function contextmenu() {
60894         event.preventDefault();
60895         event.stopPropagation();
60896         if (!down[2] && !down.menu) {
60897             tooltip.classed('rightclick', true);
60898             window.setTimeout(function() {
60899                 tooltip.classed('rightclick', false);
60900             }, minTime);
60901             dispatch$$1.call('click', this, 'right');
60902         }
60903     }
60904
60905
60906     var behavior = function(selection$$1) {
60907         tooltip = selection$$1;
60908         down = {};
60909
60910         select(window)
60911             .on('keydown.intro', keydown)
60912             .on('keyup.intro', keyup)
60913             .on('mousedown.intro', mousedown)
60914             .on('mouseup.intro', mouseup)
60915             .on('contextmenu.intro', contextmenu);
60916     };
60917
60918
60919     behavior.off = function() {
60920         select(window)
60921             .on('keydown.intro', null)
60922             .on('keyup.intro', null)
60923             .on('mousedown.intro', null)
60924             .on('mouseup.intro', null)
60925             .on('contextmenu.intro', null);
60926
60927         tooltip
60928             .classed('leftclick', false)
60929             .classed('rightclick', false);
60930     };
60931
60932     return utilRebind(behavior, dispatch$$1, 'on');
60933 }
60934
60935 function uiIntroNavigation(context, reveal) {
60936     var dispatch$$1 = dispatch('done'),
60937         timeouts = [],
60938         hallId = 'n2061',
60939         townHall = [-85.63591, 41.94285],
60940         springStreetId = 'w397',
60941         springStreetEndId = 'n1834',
60942         springStreet = [-85.63582, 41.94255],
60943         onewayField = context.presets().field('oneway'),
60944         maxspeedField = context.presets().field('maxspeed');
60945
60946
60947     var chapter = {
60948         title: 'intro.navigation.title'
60949     };
60950
60951
60952     function timeout(f, t$$1) {
60953         timeouts.push(window.setTimeout(f, t$$1));
60954     }
60955
60956
60957     function eventCancel() {
60958         event.stopPropagation();
60959         event.preventDefault();
60960     }
60961
60962
60963     function isTownHallSelected() {
60964         var ids = context.selectedIDs();
60965         return ids.length === 1 && ids[0] === hallId;
60966     }
60967
60968
60969     function dragMap() {
60970         context.enter(modeBrowse(context));
60971         context.history().reset('initial');
60972
60973         var msec = transitionTime(townHall, context.map().center());
60974         if (msec) { reveal(null, null, { duration: 0 }); }
60975         context.map().zoom(19).centerEase(townHall, msec);
60976
60977         timeout(function() {
60978             var centerStart = context.map().center();
60979
60980             reveal('#surface', t('intro.navigation.drag'));
60981             context.map().on('drawn.intro', function() {
60982                 reveal('#surface', t('intro.navigation.drag'), { duration: 0 });
60983             });
60984
60985             context.map().on('move.intro', function() {
60986                 var centerNow = context.map().center();
60987                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
60988                     context.map().on('move.intro', null);
60989                     timeout(function() { continueTo(zoomMap); }, 3000);
60990                 }
60991             });
60992
60993         }, msec + 100);
60994
60995         function continueTo(nextStep) {
60996             context.map().on('move.intro drawn.intro', null);
60997             nextStep();
60998         }
60999     }
61000
61001
61002     function zoomMap() {
61003         var zoomStart = context.map().zoom();
61004
61005         reveal('#surface',
61006             t('intro.navigation.zoom', {
61007                 plus: icon('#icon-plus', 'pre-text'),
61008                 minus: icon('#icon-minus', 'pre-text')
61009             })
61010         );
61011
61012         context.map().on('drawn.intro', function() {
61013             reveal('#surface',
61014                 t('intro.navigation.zoom', {
61015                     plus: icon('#icon-plus', 'pre-text'),
61016                     minus: icon('#icon-minus', 'pre-text')
61017                 }), { duration: 0 }
61018             );
61019         });
61020
61021         context.map().on('move.intro', function() {
61022             if (context.map().zoom() !== zoomStart) {
61023                 context.map().on('move.intro', null);
61024                 timeout(function() { continueTo(features); }, 3000);
61025             }
61026         });
61027
61028         function continueTo(nextStep) {
61029             context.map().on('move.intro drawn.intro', null);
61030             nextStep();
61031         }
61032     }
61033
61034
61035     function features() {
61036         var onClick = function() { continueTo(pointsLinesAreas); };
61037
61038         reveal('#surface', t('intro.navigation.features'),
61039             { buttonText: t('intro.ok'), buttonCallback: onClick }
61040         );
61041
61042         context.map().on('drawn.intro', function() {
61043             reveal('#surface', t('intro.navigation.features'),
61044                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
61045             );
61046         });
61047
61048         function continueTo(nextStep) {
61049             context.map().on('drawn.intro', null);
61050             nextStep();
61051         }
61052     }
61053
61054     function pointsLinesAreas() {
61055         var onClick = function() { continueTo(nodesWays); };
61056
61057         reveal('#surface', t('intro.navigation.points_lines_areas'),
61058             { buttonText: t('intro.ok'), buttonCallback: onClick }
61059         );
61060
61061         context.map().on('drawn.intro', function() {
61062             reveal('#surface', t('intro.navigation.points_lines_areas'),
61063                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
61064             );
61065         });
61066
61067         function continueTo(nextStep) {
61068             context.map().on('drawn.intro', null);
61069             nextStep();
61070         }
61071     }
61072
61073     function nodesWays() {
61074         var onClick = function() { continueTo(clickTownHall); };
61075
61076         reveal('#surface', t('intro.navigation.nodes_ways'),
61077             { buttonText: t('intro.ok'), buttonCallback: onClick }
61078         );
61079
61080         context.map().on('drawn.intro', function() {
61081             reveal('#surface', t('intro.navigation.nodes_ways'),
61082                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
61083             );
61084         });
61085
61086         function continueTo(nextStep) {
61087             context.map().on('drawn.intro', null);
61088             nextStep();
61089         }
61090     }
61091
61092     function clickTownHall() {
61093         context.enter(modeBrowse(context));
61094         context.history().reset('initial');
61095
61096         reveal(null, null, { duration: 0 });
61097         context.map().zoomEase(19, 500);
61098
61099         timeout(function() {
61100             var entity = context.hasEntity(hallId);
61101             if (!entity) return;
61102             context.map().centerEase(entity.loc, 500);
61103
61104             timeout(function() {
61105                 var entity = context.hasEntity(hallId);
61106                 if (!entity) return;
61107                 var box = pointBox(entity.loc, context);
61108                 reveal(box, t('intro.navigation.click_townhall'));
61109
61110                 context.map().on('move.intro drawn.intro', function() {
61111                     var entity = context.hasEntity(hallId);
61112                     if (!entity) return;
61113                     var box = pointBox(entity.loc, context);
61114                     reveal(box, t('intro.navigation.click_townhall'), { duration: 0 });
61115                 });
61116
61117                 context.on('enter.intro', function() {
61118                     if (isTownHallSelected()) continueTo(selectedTownHall);
61119                 });
61120
61121             }, 550);  // after centerEase
61122
61123         }, 550); // after zoomEase
61124
61125         context.history().on('change.intro', function() {
61126             if (!context.hasEntity(hallId)) {
61127                 continueTo(clickTownHall);
61128             }
61129         });
61130
61131         function continueTo(nextStep) {
61132             context.on('enter.intro', null);
61133             context.map().on('move.intro drawn.intro', null);
61134             context.history().on('change.intro', null);
61135             nextStep();
61136         }
61137     }
61138
61139
61140     function selectedTownHall() {
61141         if (!isTownHallSelected()) return clickTownHall();
61142
61143         var entity = context.hasEntity(hallId);
61144         if (!entity) return clickTownHall();
61145
61146         var box = pointBox(entity.loc, context);
61147         var onClick = function() { continueTo(editorTownHall); };
61148
61149         reveal(box, t('intro.navigation.selected_townhall'),
61150             { buttonText: t('intro.ok'), buttonCallback: onClick }
61151         );
61152
61153         context.map().on('move.intro drawn.intro', function() {
61154             var entity = context.hasEntity(hallId);
61155             if (!entity) return;
61156             var box = pointBox(entity.loc, context);
61157             reveal(box, t('intro.navigation.selected_townhall'),
61158                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
61159             );
61160         });
61161
61162         context.history().on('change.intro', function() {
61163             if (!context.hasEntity(hallId)) {
61164                 continueTo(clickTownHall);
61165             }
61166         });
61167
61168         function continueTo(nextStep) {
61169             context.map().on('move.intro drawn.intro', null);
61170             context.history().on('change.intro', null);
61171             nextStep();
61172         }
61173     }
61174
61175
61176     function editorTownHall() {
61177         if (!isTownHallSelected()) return clickTownHall();
61178
61179         // disallow scrolling
61180         select('.inspector-wrap').on('wheel.intro', eventCancel);
61181
61182         var onClick = function() { continueTo(presetTownHall); };
61183
61184         reveal('.entity-editor-pane',
61185             t('intro.navigation.editor_townhall'),
61186             { buttonText: t('intro.ok'), buttonCallback: onClick }
61187         );
61188
61189         context.on('exit.intro', function() {
61190             continueTo(clickTownHall);
61191         });
61192
61193         context.history().on('change.intro', function() {
61194             if (!context.hasEntity(hallId)) {
61195                 continueTo(clickTownHall);
61196             }
61197         });
61198
61199         function continueTo(nextStep) {
61200             context.on('exit.intro', null);
61201             context.history().on('change.intro', null);
61202             select('.inspector-wrap').on('wheel.intro', null);
61203             nextStep();
61204         }
61205     }
61206
61207
61208     function presetTownHall() {
61209         if (!isTownHallSelected()) return clickTownHall();
61210
61211         // reset pane, in case user happened to change it..
61212         select('.inspector-wrap .panewrap').style('right', '0%');
61213         // disallow scrolling
61214         select('.inspector-wrap').on('wheel.intro', eventCancel);
61215
61216         // preset match, in case the user happened to change it.
61217         var entity = context.entity(context.selectedIDs()[0]);
61218         var preset = context.presets().match(entity, context.graph());
61219
61220         var onClick = function() { continueTo(fieldsTownHall); };
61221
61222         context.on('exit.intro', function() {
61223             continueTo(clickTownHall);
61224         });
61225
61226         context.history().on('change.intro', function() {
61227             if (!context.hasEntity(hallId)) {
61228                 continueTo(clickTownHall);
61229             }
61230         });
61231
61232         reveal('.inspector-body .preset-list-item.inspector-inner',
61233             t('intro.navigation.preset_townhall', { preset: preset.name() }),
61234             { buttonText: t('intro.ok'), buttonCallback: onClick }
61235         );
61236
61237         function continueTo(nextStep) {
61238             context.on('exit.intro', null);
61239             context.history().on('change.intro', null);
61240             select('.inspector-wrap').on('wheel.intro', null);
61241             nextStep();
61242         }
61243     }
61244
61245
61246     function fieldsTownHall() {
61247         if (!isTownHallSelected()) return clickTownHall();
61248
61249         // reset pane, in case user happened to change it..
61250         select('.inspector-wrap .panewrap').style('right', '0%');
61251         // disallow scrolling
61252         select('.inspector-wrap').on('wheel.intro', eventCancel);
61253
61254         var onClick = function() { continueTo(closeTownHall); };
61255
61256         reveal('.inspector-body .inspector-preset',
61257             t('intro.navigation.fields_townhall'),
61258             { buttonText: t('intro.ok'), buttonCallback: onClick }
61259         );
61260
61261         context.on('exit.intro', function() {
61262             continueTo(clickTownHall);
61263         });
61264
61265         context.history().on('change.intro', function() {
61266             if (!context.hasEntity(hallId)) {
61267                 continueTo(clickTownHall);
61268             }
61269         });
61270
61271         function continueTo(nextStep) {
61272             context.on('exit.intro', null);
61273             context.history().on('change.intro', null);
61274             select('.inspector-wrap').on('wheel.intro', null);
61275             nextStep();
61276         }
61277     }
61278
61279
61280     function closeTownHall() {
61281         if (!isTownHallSelected()) return clickTownHall();
61282
61283         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61284         var href = select(selector$$1).attr('href') || '#icon-close';
61285
61286         reveal('.entity-editor-pane',
61287             t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') })
61288         );
61289
61290         context.on('exit.intro', function() {
61291             continueTo(searchStreet);
61292         });
61293
61294         context.history().on('change.intro', function() {
61295             // update the close icon in the tooltip if the user edits something.
61296             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61297             var href = select(selector$$1).attr('href') || '#icon-close';
61298
61299             reveal('.entity-editor-pane',
61300                 t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }),
61301                 { duration: 0 }
61302             );
61303         });
61304
61305         function continueTo(nextStep) {
61306             context.on('exit.intro', null);
61307             context.history().on('change.intro', null);
61308             nextStep();
61309         }
61310     }
61311
61312
61313     function searchStreet() {
61314         context.enter(modeBrowse(context));
61315         context.history().reset('initial');  // ensure spring street exists
61316
61317         var msec = transitionTime(springStreet, context.map().center());
61318         if (msec) { reveal(null, null, { duration: 0 }); }
61319         context.map().zoom(19).centerEase(springStreet, msec);  // ..and user can see it
61320
61321         timeout(function() {
61322             reveal('.search-header input',
61323                 t('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') })
61324             );
61325
61326             select('.search-header input')
61327                 .on('keyup.intro', checkSearchResult);
61328         }, msec + 100);
61329     }
61330
61331
61332     function checkSearchResult() {
61333         var first = select('.feature-list-item:nth-child(0n+2)'),  // skip "No Results" item
61334             firstName = first.select('.entity-name'),
61335             name = t('intro.graph.name.spring-street');
61336
61337         if (!firstName.empty() && firstName.text() === name) {
61338             reveal(first.node(),
61339                 t('intro.navigation.choose_street', { name: name }),
61340                 { duration: 300 }
61341             );
61342
61343             context.on('exit.intro', function() {
61344                 continueTo(selectedStreet);
61345             });
61346
61347             select('.search-header input')
61348                 .on('keydown.intro', eventCancel, true)
61349                 .on('keyup.intro', null);
61350         }
61351
61352         function continueTo(nextStep) {
61353             context.on('exit.intro', null);
61354             select('.search-header input')
61355                 .on('keydown.intro', null)
61356                 .on('keyup.intro', null);
61357             nextStep();
61358         }
61359     }
61360
61361
61362     function selectedStreet() {
61363         if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
61364             return searchStreet();
61365         }
61366
61367         var onClick = function() { continueTo(editorStreet); };
61368         var entity = context.entity(springStreetEndId);
61369         var box = pointBox(entity.loc, context);
61370         box.height = 500;
61371
61372         reveal(box,
61373             t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
61374             { duration: 600, buttonText: t('intro.ok'), buttonCallback: onClick }
61375         );
61376
61377         timeout(function() {
61378             context.map().on('move.intro drawn.intro', function() {
61379                 var entity = context.hasEntity(springStreetEndId);
61380                 if (!entity) return;
61381                 var box = pointBox(entity.loc, context);
61382                 box.height = 500;
61383                 reveal(box,
61384                     t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
61385                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
61386                 );
61387             });
61388         }, 600);  // after reveal.
61389
61390         context.on('enter.intro', function(mode) {
61391             if (!context.hasEntity(springStreetId)) {
61392                 return continueTo(searchStreet);
61393             }
61394             var ids = context.selectedIDs();
61395             if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
61396                 // keep Spring Street selected..
61397                 context.enter(modeSelect(context, [springStreetId]));
61398             }
61399         });
61400
61401         context.history().on('change.intro', function() {
61402             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
61403                 timeout(function() {
61404                     continueTo(searchStreet);
61405                 }, 300);  // after any transition (e.g. if user deleted intersection)
61406             }
61407         });
61408
61409         function continueTo(nextStep) {
61410             context.map().on('move.intro drawn.intro', null);
61411             context.on('enter.intro', null);
61412             context.history().on('change.intro', null);
61413             nextStep();
61414         }
61415     }
61416
61417
61418     function editorStreet() {
61419         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61420         var href = select(selector$$1).attr('href') || '#icon-close';
61421
61422         reveal('.entity-editor-pane',
61423             t('intro.navigation.editor_street', {
61424                 button: icon(href, 'pre-text'),
61425                 field1: onewayField.label(),
61426                 field2: maxspeedField.label()
61427             })
61428         );
61429
61430         context.on('exit.intro', function() {
61431             continueTo(play);
61432         });
61433
61434         context.history().on('change.intro', function() {
61435             // update the close icon in the tooltip if the user edits something.
61436             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61437             var href = select(selector$$1).attr('href') || '#icon-close';
61438
61439             reveal('.entity-editor-pane',
61440                 t('intro.navigation.editor_street', {
61441                     button: icon(href, 'pre-text'),
61442                     field1: onewayField.label().toLowerCase(),
61443                     field2: maxspeedField.label().toLowerCase()
61444                 }), { duration: 0 }
61445             );
61446         });
61447
61448         function continueTo(nextStep) {
61449             context.on('exit.intro', null);
61450             context.history().on('change.intro', null);
61451             nextStep();
61452         }
61453     }
61454
61455
61456     function play() {
61457         dispatch$$1.call('done');
61458         reveal('#id-container',
61459             t('intro.navigation.play', { next: t('intro.points.title') }), {
61460                 tooltipBox: '.intro-nav-wrap .chapter-point',
61461                 buttonText: t('intro.ok'),
61462                 buttonCallback: function() { reveal('#id-container'); }
61463             }
61464         );
61465     }
61466
61467
61468     chapter.enter = function() {
61469         dragMap();
61470     };
61471
61472
61473     chapter.exit = function() {
61474         timeouts.forEach(window.clearTimeout);
61475         context.on('enter.intro exit.intro', null);
61476         context.map().on('move.intro drawn.intro', null);
61477         context.history().on('change.intro', null);
61478         select('.inspector-wrap').on('wheel.intro', null);
61479         select('.search-header input').on('keydown.intro keyup.intro', null);
61480     };
61481
61482
61483     chapter.restart = function() {
61484         chapter.exit();
61485         chapter.enter();
61486     };
61487
61488
61489     return utilRebind(chapter, dispatch$$1, 'on');
61490 }
61491
61492 function uiIntroPoint(context, reveal) {
61493     var dispatch$$1 = dispatch('done'),
61494         timeouts = [],
61495         intersection = [-85.63279, 41.94394],
61496         building = [-85.632422, 41.944045],
61497         cafePreset = context.presets().item('amenity/cafe'),
61498         pointId = null;
61499
61500
61501     var chapter = {
61502         title: 'intro.points.title'
61503     };
61504
61505
61506     function timeout(f, t$$1) {
61507         timeouts.push(window.setTimeout(f, t$$1));
61508     }
61509
61510
61511     function revealEditMenu(loc, text$$1, options) {
61512         var rect = context.surfaceRect();
61513         var point = context.curtainProjection(loc);
61514         var pad = 40;
61515         var width = 250 + (2 * pad);
61516         var height = 250;
61517         var startX = rect.left + point[0];
61518         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
61519         var box = {
61520             left: left,
61521             top: point[1] + rect.top - 60,
61522             width: width,
61523             height: height
61524         };
61525         reveal(box, text$$1, options);
61526     }
61527
61528
61529     function eventCancel() {
61530         event.stopPropagation();
61531         event.preventDefault();
61532     }
61533
61534
61535     function addPoint() {
61536         context.enter(modeBrowse(context));
61537         context.history().reset('initial');
61538
61539         var msec = transitionTime(intersection, context.map().center());
61540         if (msec) { reveal(null, null, { duration: 0 }); }
61541         context.map().zoom(19).centerEase(intersection, msec);
61542
61543         timeout(function() {
61544             var tooltip = reveal('button.add-point',
61545                 t('intro.points.add_point', { button: icon('#icon-point', 'pre-text') }));
61546
61547             pointId = null;
61548
61549             tooltip.selectAll('.tooltip-inner')
61550                 .insert('svg', 'span')
61551                 .attr('class', 'tooltip-illustration')
61552                 .append('use')
61553                 .attr('xlink:href', '#poi-images');
61554
61555             context.on('enter.intro', function(mode) {
61556                 if (mode.id !== 'add-point') return;
61557                 continueTo(placePoint);
61558             });
61559         }, msec + 100);
61560
61561         function continueTo(nextStep) {
61562             context.on('enter.intro', null);
61563             nextStep();
61564         }
61565     }
61566
61567
61568     function placePoint() {
61569         if (context.mode().id !== 'add-point') {
61570             return chapter.restart();
61571         }
61572
61573         var pointBox$$1 = pad$1(building, 150, context);
61574         reveal(pointBox$$1, t('intro.points.place_point'));
61575
61576         context.map().on('move.intro drawn.intro', function() {
61577             pointBox$$1 = pad$1(building, 150, context);
61578             reveal(pointBox$$1, t('intro.points.place_point'), { duration: 0 });
61579         });
61580
61581         context.on('enter.intro', function(mode) {
61582             if (mode.id !== 'select') return chapter.restart();
61583             pointId = context.mode().selectedIDs()[0];
61584             continueTo(searchPreset);
61585         });
61586
61587         function continueTo(nextStep) {
61588             context.map().on('move.intro drawn.intro', null);
61589             context.on('enter.intro', null);
61590             nextStep();
61591         }
61592     }
61593
61594
61595     function searchPreset() {
61596         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61597             return addPoint();
61598         }
61599
61600         // disallow scrolling
61601         select('.inspector-wrap').on('wheel.intro', eventCancel);
61602
61603         select('.preset-search-input')
61604             .on('keydown.intro', null)
61605             .on('keyup.intro', checkPresetSearch);
61606
61607         reveal('.preset-search-input',
61608             t('intro.points.search_cafe', { preset: cafePreset.name() })
61609         );
61610
61611         context.on('enter.intro', function(mode) {
61612             if (!pointId || !context.hasEntity(pointId)) {
61613                 return continueTo(addPoint);
61614             }
61615
61616             var ids = context.selectedIDs();
61617             if (mode.id !== 'select' || !ids.length || ids[0] !== pointId) {
61618                 // keep the user's point selected..
61619                 context.enter(modeSelect(context, [pointId]));
61620
61621                 // disallow scrolling
61622                 select('.inspector-wrap').on('wheel.intro', eventCancel);
61623
61624                 select('.preset-search-input')
61625                     .on('keydown.intro', null)
61626                     .on('keyup.intro', checkPresetSearch);
61627
61628                 reveal('.preset-search-input',
61629                     t('intro.points.search_cafe', { preset: cafePreset.name() })
61630                 );
61631
61632                 context.history().on('change.intro', null);
61633             }
61634         });
61635
61636
61637         function checkPresetSearch() {
61638             var first = select('.preset-list-item:first-child');
61639
61640             if (first.classed('preset-amenity-cafe')) {
61641                 select('.preset-search-input')
61642                     .on('keydown.intro', eventCancel, true)
61643                     .on('keyup.intro', null);
61644
61645                 reveal(first.select('.preset-list-button').node(),
61646                     t('intro.points.choose_cafe', { preset: cafePreset.name() }),
61647                     { duration: 300 }
61648                 );
61649
61650                 context.history().on('change.intro', function() {
61651                     continueTo(aboutFeatureEditor);
61652                 });
61653             }
61654         }
61655
61656         function continueTo(nextStep) {
61657             context.on('enter.intro', null);
61658             context.history().on('change.intro', null);
61659             select('.inspector-wrap').on('wheel.intro', null);
61660             select('.preset-search-input').on('keydown.intro keyup.intro', null);
61661             nextStep();
61662         }
61663     }
61664
61665
61666     function aboutFeatureEditor() {
61667         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61668             return addPoint();
61669         }
61670
61671         timeout(function() {
61672             reveal('.entity-editor-pane', t('intro.points.feature_editor'), {
61673                 tooltipClass: 'intro-points-describe',
61674                 buttonText: t('intro.ok'),
61675                 buttonCallback: function() { continueTo(addName); }
61676             });
61677         }, 400);
61678
61679         context.on('exit.intro', function() {
61680             // if user leaves select mode here, just continue with the tutorial.
61681             continueTo(reselectPoint);
61682         });
61683
61684         function continueTo(nextStep) {
61685             context.on('exit.intro', null);
61686             nextStep();
61687         }
61688     }
61689
61690
61691     function addName() {
61692         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61693             return addPoint();
61694         }
61695
61696         // reset pane, in case user happened to change it..
61697         select('.inspector-wrap .panewrap').style('right', '0%');
61698
61699         timeout(function() {
61700             // It's possible for the user to add a name in a previous step..
61701             // If so, don't tell them to add the name in this step.
61702             // Give them an OK button instead.
61703             var entity = context.entity(pointId);
61704             if (entity.tags.name) {
61705                 var tooltip = reveal('.entity-editor-pane', t('intro.points.add_name'), {
61706                     tooltipClass: 'intro-points-describe',
61707                     buttonText: t('intro.ok'),
61708                     buttonCallback: function() { continueTo(addCloseEditor); }
61709                 });
61710                 tooltip.select('.instruction').style('display', 'none');
61711
61712             } else {
61713                 reveal('.entity-editor-pane', t('intro.points.add_name'),
61714                     { tooltipClass: 'intro-points-describe' }
61715                 );
61716             }
61717         }, 400);
61718
61719         context.history().on('change.intro', function() {
61720             continueTo(addCloseEditor);
61721         });
61722
61723         context.on('exit.intro', function() {
61724             // if user leaves select mode here, just continue with the tutorial.
61725             continueTo(reselectPoint);
61726         });
61727
61728         function continueTo(nextStep) {
61729             context.on('exit.intro', null);
61730             context.history().on('change.intro', null);
61731             nextStep();
61732         }
61733     }
61734
61735
61736     function addCloseEditor() {
61737         // reset pane, in case user happened to change it..
61738         select('.inspector-wrap .panewrap').style('right', '0%');
61739
61740         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
61741         var href = select(selector$$1).attr('href') || '#icon-close';
61742
61743         context.on('exit.intro', function() {
61744             continueTo(reselectPoint);
61745         });
61746
61747         reveal('.entity-editor-pane',
61748             t('intro.points.add_close', { button: icon(href, 'pre-text') })
61749         );
61750
61751         function continueTo(nextStep) {
61752             context.on('exit.intro', null);
61753             nextStep();
61754         }
61755     }
61756
61757
61758     function reselectPoint() {
61759         if (!pointId) return chapter.restart();
61760         var entity = context.hasEntity(pointId);
61761         if (!entity) return chapter.restart();
61762
61763         // make sure it's still a cafe, in case user somehow changed it..
61764         var oldPreset = context.presets().match(entity, context.graph());
61765         context.replace(actionChangePreset(pointId, oldPreset, cafePreset));
61766
61767         context.enter(modeBrowse(context));
61768
61769         var msec = transitionTime(entity.loc, context.map().center());
61770         if (msec) { reveal(null, null, { duration: 0 }); }
61771         context.map().centerEase(entity.loc, msec);
61772
61773         timeout(function() {
61774             var box = pointBox(entity.loc, context);
61775             reveal(box, t('intro.points.reselect'), { duration: 600 });
61776
61777             timeout(function() {
61778                 context.map().on('move.intro drawn.intro', function() {
61779                     var entity = context.hasEntity(pointId);
61780                     if (!entity) return chapter.restart();
61781                     var box = pointBox(entity.loc, context);
61782                     reveal(box, t('intro.points.reselect'), { duration: 0 });
61783                 });
61784             }, 600); // after reveal..
61785
61786             context.on('enter.intro', function(mode) {
61787                 if (mode.id !== 'select') return;
61788                 continueTo(updatePoint);
61789             });
61790
61791         }, msec + 100);
61792
61793         function continueTo(nextStep) {
61794             context.map().on('move.intro drawn.intro', null);
61795             context.on('enter.intro', null);
61796             nextStep();
61797         }
61798     }
61799
61800
61801     function updatePoint() {
61802         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61803             return continueTo(reselectPoint);
61804         }
61805
61806         // reset pane, in case user happened to untag the point..
61807         select('.inspector-wrap .panewrap').style('right', '0%');
61808
61809         context.on('exit.intro', function() {
61810             continueTo(reselectPoint);
61811         });
61812
61813         context.history().on('change.intro', function() {
61814             continueTo(updateCloseEditor);
61815         });
61816
61817         timeout(function() {
61818             reveal('.entity-editor-pane', t('intro.points.update'),
61819                 { tooltipClass: 'intro-points-describe' }
61820             );
61821         }, 400);
61822
61823         function continueTo(nextStep) {
61824             context.on('exit.intro', null);
61825             context.history().on('change.intro', null);
61826             nextStep();
61827         }
61828     }
61829
61830
61831     function updateCloseEditor() {
61832         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
61833             return continueTo(reselectPoint);
61834         }
61835
61836         // reset pane, in case user happened to change it..
61837         select('.inspector-wrap .panewrap').style('right', '0%');
61838
61839         context.on('exit.intro', function() {
61840             continueTo(rightClickPoint);
61841         });
61842
61843         timeout(function() {
61844             reveal('.entity-editor-pane',
61845                 t('intro.points.update_close', { button: icon('#icon-apply', 'pre-text') })
61846             );
61847         }, 500);
61848
61849         function continueTo(nextStep) {
61850             context.on('exit.intro', null);
61851             nextStep();
61852         }
61853     }
61854
61855
61856     function rightClickPoint() {
61857         if (!pointId) return chapter.restart();
61858         var entity = context.hasEntity(pointId);
61859         if (!entity) return chapter.restart();
61860
61861         context.enter(modeBrowse(context));
61862
61863         var box = pointBox(entity.loc, context);
61864         reveal(box, t('intro.points.rightclick'), { duration: 600 });
61865
61866         timeout(function() {
61867             context.map().on('move.intro drawn.intro', function() {
61868                 var entity = context.hasEntity(pointId);
61869                 if (!entity) return chapter.restart();
61870                 var box = pointBox(entity.loc, context);
61871                 reveal(box, t('intro.points.rightclick'), { duration: 0 });
61872             });
61873         }, 600); // after reveal
61874
61875         context.on('enter.intro', function(mode) {
61876             if (mode.id !== 'select') return;
61877             var ids = context.selectedIDs();
61878             if (ids.length !== 1 || ids[0] !== pointId) return;
61879
61880             timeout(function() {
61881                 var node = selectMenuItem('delete').node();
61882                 if (!node) return;
61883                 continueTo(enterDelete);
61884             }, 300);  // after menu visible
61885         });
61886
61887         function continueTo(nextStep) {
61888             context.on('enter.intro', null);
61889             context.map().on('move.intro drawn.intro', null);
61890             nextStep();
61891         }
61892     }
61893
61894
61895     function enterDelete() {
61896         if (!pointId) return chapter.restart();
61897         var entity = context.hasEntity(pointId);
61898         if (!entity) return chapter.restart();
61899
61900         var node = selectMenuItem('delete').node();
61901         if (!node) { return continueTo(rightClickPoint); }
61902
61903         revealEditMenu(entity.loc,
61904             t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') })
61905         );
61906
61907         timeout(function() {
61908             context.map().on('move.intro drawn.intro', function() {
61909                 revealEditMenu(entity.loc,
61910                     t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') }),
61911                     { duration: 0}
61912                 );
61913             });
61914         }, 300); // after menu visible
61915
61916         context.on('exit.intro', function() {
61917             if (!pointId) return chapter.restart();
61918             var entity = context.hasEntity(pointId);
61919             if (entity) return continueTo(rightClickPoint);  // point still exists
61920         });
61921
61922         context.history().on('change.intro', function(changed) {
61923             if (changed.deleted().length) {
61924                 continueTo(undo);
61925             }
61926         });
61927
61928         function continueTo(nextStep) {
61929             context.map().on('move.intro drawn.intro', null);
61930             context.history().on('change.intro', null);
61931             context.on('exit.intro', null);
61932             nextStep();
61933         }
61934     }
61935
61936
61937     function undo() {
61938         context.history().on('change.intro', function() {
61939             continueTo(play);
61940         });
61941
61942         var iconName = '#icon-' + (textDirection === 'rtl' ? 'redo' : 'undo');
61943         reveal('#bar button.undo-button',
61944             t('intro.points.undo', { button: icon(iconName, 'pre-text') })
61945         );
61946
61947         function continueTo(nextStep) {
61948             context.history().on('change.intro', null);
61949             nextStep();
61950         }
61951     }
61952
61953
61954     function play() {
61955         dispatch$$1.call('done');
61956         reveal('#id-container',
61957             t('intro.points.play', { next: t('intro.areas.title') }), {
61958                 tooltipBox: '.intro-nav-wrap .chapter-area',
61959                 buttonText: t('intro.ok'),
61960                 buttonCallback: function() { reveal('#id-container'); }
61961             }
61962         );
61963     }
61964
61965
61966     chapter.enter = function() {
61967         addPoint();
61968     };
61969
61970
61971     chapter.exit = function() {
61972         timeouts.forEach(window.clearTimeout);
61973         context.on('enter.intro exit.intro', null);
61974         context.map().on('move.intro drawn.intro', null);
61975         context.history().on('change.intro', null);
61976         select('.inspector-wrap').on('wheel.intro', eventCancel);
61977         select('.preset-search-input').on('keydown.intro keyup.intro', null);
61978     };
61979
61980
61981     chapter.restart = function() {
61982         chapter.exit();
61983         chapter.enter();
61984     };
61985
61986
61987     return utilRebind(chapter, dispatch$$1, 'on');
61988 }
61989
61990 function uiIntroArea(context, reveal) {
61991     var dispatch$$1 = dispatch('done'),
61992         playground = [-85.63552, 41.94159],
61993         playgroundPreset = context.presets().item('leisure/playground'),
61994         descriptionField = context.presets().field('description'),
61995         timeouts = [],
61996         areaId;
61997
61998
61999     var chapter = {
62000         title: 'intro.areas.title'
62001     };
62002
62003
62004     function timeout(f, t$$1) {
62005         timeouts.push(window.setTimeout(f, t$$1));
62006     }
62007
62008
62009     function eventCancel() {
62010         event.stopPropagation();
62011         event.preventDefault();
62012     }
62013
62014
62015     function revealPlayground(center, text$$1, options) {
62016         var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
62017         var box = pad$1(center, padding, context);
62018         reveal(box, text$$1, options);
62019     }
62020
62021
62022     function addArea() {
62023         context.enter(modeBrowse(context));
62024         context.history().reset('initial');
62025         areaId = null;
62026
62027         var msec = transitionTime(playground, context.map().center());
62028         if (msec) { reveal(null, null, { duration: 0 }); }
62029         context.map().zoom(19).centerEase(playground, msec);
62030
62031         timeout(function() {
62032             var tooltip = reveal('button.add-area',
62033                 t('intro.areas.add_playground', { button: icon('#icon-area', 'pre-text') }));
62034
62035             tooltip.selectAll('.tooltip-inner')
62036                 .insert('svg', 'span')
62037                 .attr('class', 'tooltip-illustration')
62038                 .append('use')
62039                 .attr('xlink:href', '#landuse-images');
62040
62041             context.on('enter.intro', function(mode) {
62042                 if (mode.id !== 'add-area') return;
62043                 continueTo(startPlayground);
62044             });
62045         }, msec + 100);
62046
62047         function continueTo(nextStep) {
62048             context.on('enter.intro', null);
62049             nextStep();
62050         }
62051     }
62052
62053
62054     function startPlayground() {
62055         if (context.mode().id !== 'add-area') {
62056             return chapter.restart();
62057         }
62058
62059         areaId = null;
62060         context.map().zoomEase(19.5, 500);
62061
62062         timeout(function() {
62063             revealPlayground(playground,
62064                 t('intro.areas.start_playground'), { duration: 250 }
62065             );
62066
62067             timeout(function() {
62068                 context.map().on('move.intro drawn.intro', function() {
62069                     revealPlayground(playground,
62070                         t('intro.areas.start_playground'), { duration: 0 }
62071                     );
62072                 });
62073                 context.on('enter.intro', function(mode) {
62074                     if (mode.id !== 'draw-area') return chapter.restart();
62075                     continueTo(continuePlayground);
62076                 });
62077             }, 250);  // after reveal
62078
62079         }, 550);  // after easing
62080
62081         function continueTo(nextStep) {
62082             context.map().on('move.intro drawn.intro', null);
62083             context.on('enter.intro', null);
62084             nextStep();
62085         }
62086     }
62087
62088
62089     function continuePlayground() {
62090         if (context.mode().id !== 'draw-area') {
62091             return chapter.restart();
62092         }
62093
62094         areaId = null;
62095         revealPlayground(playground,
62096             t('intro.areas.continue_playground', { alt: uiCmd.display('⌥') }),
62097             { duration: 250 }
62098         );
62099
62100         timeout(function() {
62101             context.map().on('move.intro drawn.intro', function() {
62102                 revealPlayground(playground,
62103                     t('intro.areas.continue_playground', { alt: uiCmd.display('⌥') }),
62104                     { duration: 0 }
62105                 );
62106             });
62107         }, 250);  // after reveal
62108
62109         context.on('enter.intro', function(mode) {
62110             if (mode.id === 'draw-area') {
62111                 var entity = context.hasEntity(context.selectedIDs()[0]);
62112                 if (entity && entity.nodes.length >= 6) {
62113                     return continueTo(finishPlayground);
62114                 } else {
62115                     return;
62116                 }
62117             } else if (mode.id === 'select') {
62118                 areaId = context.selectedIDs()[0];
62119                 return continueTo(searchPresets);
62120             } else {
62121                 return chapter.restart();
62122             }
62123         });
62124
62125         function continueTo(nextStep) {
62126             context.map().on('move.intro drawn.intro', null);
62127             context.on('enter.intro', null);
62128             nextStep();
62129         }
62130     }
62131
62132
62133     function finishPlayground() {
62134         if (context.mode().id !== 'draw-area') {
62135             return chapter.restart();
62136         }
62137
62138         areaId = null;
62139         revealPlayground(playground,
62140             t('intro.areas.finish_playground'), { duration: 250 }
62141         );
62142
62143         timeout(function() {
62144             context.map().on('move.intro drawn.intro', function() {
62145                 revealPlayground(playground,
62146                     t('intro.areas.finish_playground'), { duration: 0 }
62147                 );
62148             });
62149         }, 250);  // after reveal
62150
62151         context.on('enter.intro', function(mode) {
62152             if (mode.id === 'draw-area') {
62153                 return;
62154             } else if (mode.id === 'select') {
62155                 areaId = context.selectedIDs()[0];
62156                 return continueTo(searchPresets);
62157             } else {
62158                 return chapter.restart();
62159             }
62160         });
62161
62162         function continueTo(nextStep) {
62163             context.map().on('move.intro drawn.intro', null);
62164             context.on('enter.intro', null);
62165             nextStep();
62166         }
62167     }
62168
62169
62170     function searchPresets() {
62171         if (!areaId || !context.hasEntity(areaId)) {
62172             return addArea();
62173         }
62174         var ids = context.selectedIDs();
62175         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62176             context.enter(modeSelect(context, [areaId]));
62177         }
62178
62179         // disallow scrolling
62180         select('.inspector-wrap').on('wheel.intro', eventCancel);
62181
62182         timeout(function() {
62183             // reset pane, in case user somehow happened to change it..
62184             select('.inspector-wrap .panewrap').style('right', '-100%');
62185
62186             select('.preset-search-input')
62187                 .on('keydown.intro', null)
62188                 .on('keyup.intro', checkPresetSearch);
62189
62190             reveal('.preset-search-input',
62191                 t('intro.areas.search_playground', { preset: playgroundPreset.name() })
62192             );
62193         }, 400);  // after preset list pane visible..
62194
62195         context.on('enter.intro', function(mode) {
62196             if (!areaId || !context.hasEntity(areaId)) {
62197                 return continueTo(addArea);
62198             }
62199
62200             var ids = context.selectedIDs();
62201             if (mode.id !== 'select' || !ids.length || ids[0] !== areaId) {
62202                 // keep the user's area selected..
62203                 context.enter(modeSelect(context, [areaId]));
62204
62205                 // reset pane, in case user somehow happened to change it..
62206                 select('.inspector-wrap .panewrap').style('right', '-100%');
62207                 // disallow scrolling
62208                 select('.inspector-wrap').on('wheel.intro', eventCancel);
62209
62210                 select('.preset-search-input')
62211                     .on('keydown.intro', null)
62212                     .on('keyup.intro', checkPresetSearch);
62213
62214                 reveal('.preset-search-input',
62215                     t('intro.areas.search_playground', { preset: playgroundPreset.name() })
62216                 );
62217
62218                 context.history().on('change.intro', null);
62219             }
62220         });
62221
62222         function checkPresetSearch() {
62223             var first = select('.preset-list-item:first-child');
62224
62225             if (first.classed('preset-leisure-playground')) {
62226                 reveal(first.select('.preset-list-button').node(),
62227                     t('intro.areas.choose_playground', { preset: playgroundPreset.name() }),
62228                     { duration: 300 }
62229                 );
62230
62231                 select('.preset-search-input')
62232                     .on('keydown.intro', eventCancel, true)
62233                     .on('keyup.intro', null);
62234
62235                 context.history().on('change.intro', function() {
62236                     continueTo(clickAddField);
62237                 });
62238             }
62239         }
62240
62241         function continueTo(nextStep) {
62242             select('.inspector-wrap').on('wheel.intro', null);
62243             context.on('enter.intro', null);
62244             context.history().on('change.intro', null);
62245             select('.preset-search-input').on('keydown.intro keyup.intro', null);
62246             nextStep();
62247         }
62248     }
62249
62250
62251     function clickAddField() {
62252         if (!areaId || !context.hasEntity(areaId)) {
62253             return addArea();
62254         }
62255         var ids = context.selectedIDs();
62256         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62257             return searchPresets();
62258         }
62259
62260         if (!select('.form-field-description').empty()) {
62261             return continueTo(describePlayground);
62262         }
62263
62264         // disallow scrolling
62265         select('.inspector-wrap').on('wheel.intro', eventCancel);
62266
62267         timeout(function() {
62268             // reset pane, in case user somehow happened to change it..
62269             select('.inspector-wrap .panewrap').style('right', '0%');
62270
62271             // It's possible for the user to add a description in a previous step..
62272             // If they did this already, just continue to next step.
62273             var entity = context.entity(areaId);
62274             if (entity.tags.description) {
62275                 return continueTo(play);
62276             }
62277
62278             reveal('.more-fields .combobox-input',
62279                 t('intro.areas.add_field'),
62280                 { duration: 300 }
62281             );
62282
62283             select('.more-fields .combobox-input')
62284                 .on('click.intro', function() {
62285                     continueTo(chooseDescriptionField);
62286                 });
62287         }, 400);  // after editor pane visible
62288
62289         context.on('exit.intro', function() {
62290             return continueTo(searchPresets);
62291         });
62292
62293         function continueTo(nextStep) {
62294             select('.inspector-wrap').on('wheel.intro', null);
62295             select('.more-fields .combobox-input').on('click.intro', null);
62296             context.on('exit.intro', null);
62297             nextStep();
62298         }
62299     }
62300
62301
62302     function chooseDescriptionField() {
62303         if (!areaId || !context.hasEntity(areaId)) {
62304             return addArea();
62305         }
62306         var ids = context.selectedIDs();
62307         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62308             return searchPresets();
62309         }
62310
62311         if (!select('.form-field-description').empty()) {
62312             return continueTo(describePlayground);
62313         }
62314
62315         // Make sure combobox is ready..
62316         if (select('div.combobox').empty()) {
62317             return continueTo(clickAddField);
62318         }
62319         // Watch for the combobox to go away..
62320         var watcher;
62321         watcher = window.setInterval(function() {
62322             if (select('div.combobox').empty()) {
62323                 window.clearInterval(watcher);
62324                 timeout(function() {
62325                     if (select('.form-field-description').empty()) {
62326                         continueTo(retryChooseDescription);
62327                     } else {
62328                         continueTo(describePlayground);
62329                     }
62330                 }, 300);  // after description field added.
62331             }
62332         }, 300);
62333
62334         reveal('div.combobox',
62335             t('intro.areas.choose_field', { field: descriptionField.label() }),
62336             { duration: 300 }
62337         );
62338
62339         context.on('exit.intro', function() {
62340             return continueTo(searchPresets);
62341         });
62342
62343         function continueTo(nextStep) {
62344             if (watcher) window.clearInterval(watcher);
62345             context.on('exit.intro', null);
62346             nextStep();
62347         }
62348     }
62349
62350
62351     function describePlayground() {
62352         if (!areaId || !context.hasEntity(areaId)) {
62353             return addArea();
62354         }
62355         var ids = context.selectedIDs();
62356         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62357             return searchPresets();
62358         }
62359
62360         // reset pane, in case user happened to change it..
62361         select('.inspector-wrap .panewrap').style('right', '0%');
62362
62363         if (select('.form-field-description').empty()) {
62364             return continueTo(retryChooseDescription);
62365         }
62366
62367         context.on('exit.intro', function() {
62368             continueTo(play);
62369         });
62370
62371         reveal('.entity-editor-pane',
62372             t('intro.areas.describe_playground', { button: icon('#icon-apply', 'pre-text') }),
62373             { duration: 300 }
62374         );
62375
62376         function continueTo(nextStep) {
62377             context.on('exit.intro', null);
62378             nextStep();
62379         }
62380     }
62381
62382
62383     function retryChooseDescription() {
62384         if (!areaId || !context.hasEntity(areaId)) {
62385             return addArea();
62386         }
62387         var ids = context.selectedIDs();
62388         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
62389             return searchPresets();
62390         }
62391
62392         // reset pane, in case user happened to change it..
62393         select('.inspector-wrap .panewrap').style('right', '0%');
62394
62395         reveal('.entity-editor-pane',
62396             t('intro.areas.retry_add_field', { field: descriptionField.label() }), {
62397             buttonText: t('intro.ok'),
62398             buttonCallback: function() { continueTo(clickAddField); }
62399         });
62400
62401         context.on('exit.intro', function() {
62402             return continueTo(searchPresets);
62403         });
62404
62405         function continueTo(nextStep) {
62406             context.on('exit.intro', null);
62407             nextStep();
62408         }
62409     }
62410
62411
62412     function play() {
62413         dispatch$$1.call('done');
62414         reveal('#id-container',
62415             t('intro.areas.play', { next: t('intro.lines.title') }), {
62416                 tooltipBox: '.intro-nav-wrap .chapter-line',
62417                 buttonText: t('intro.ok'),
62418                 buttonCallback: function() { reveal('#id-container'); }
62419             }
62420         );
62421     }
62422
62423
62424     chapter.enter = function() {
62425         addArea();
62426     };
62427
62428
62429     chapter.exit = function() {
62430         timeouts.forEach(window.clearTimeout);
62431         context.on('enter.intro exit.intro', null);
62432         context.map().on('move.intro drawn.intro', null);
62433         context.history().on('change.intro', null);
62434         select('.inspector-wrap').on('wheel.intro', null);
62435         select('.preset-search-input').on('keydown.intro keyup.intro', null);
62436         select('.more-fields .combobox-input').on('click.intro', null);
62437     };
62438
62439
62440     chapter.restart = function() {
62441         chapter.exit();
62442         chapter.enter();
62443     };
62444
62445
62446     return utilRebind(chapter, dispatch$$1, 'on');
62447 }
62448
62449 function uiIntroLine(context, reveal) {
62450     var dispatch$$1 = dispatch('done'),
62451         timeouts = [],
62452         tulipRoadId = null,
62453         flowerRoadId = 'w646',
62454         tulipRoadStart = [-85.6297754121684, 41.95805253325314],
62455         tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204],
62456         tulipRoadIntersection = [-85.62974496187628, 41.95742515554585],
62457         roadCategory = context.presets().item('category-road'),
62458         residentialPreset = context.presets().item('highway/residential'),
62459         woodRoadId = 'w525',
62460         woodRoadEndId = 'n2862',
62461         woodRoadAddNode = [-85.62390110349587, 41.95397111462291],
62462         woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487],
62463         woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872],
62464         washingtonStreetId = 'w522',
62465         twelfthAvenueId = 'w1',
62466         eleventhAvenueEndId = 'n3550',
62467         twelfthAvenueEndId = 'n5',
62468         washingtonSegmentId = null,
62469         eleventhAvenueEnd = context.entity(eleventhAvenueEndId).loc,
62470         twelfthAvenueEnd = context.entity(twelfthAvenueEndId).loc,
62471         deleteLinesLoc = [-85.6219395542764, 41.95228033922477],
62472         twelfthAvenue = [-85.62219310052491, 41.952505413152956];
62473
62474
62475     var chapter = {
62476         title: 'intro.lines.title'
62477     };
62478
62479
62480     function timeout(f, t$$1) {
62481         timeouts.push(window.setTimeout(f, t$$1));
62482     }
62483
62484
62485     function eventCancel() {
62486         event.stopPropagation();
62487         event.preventDefault();
62488     }
62489
62490
62491     function revealEditMenu(loc, text$$1, options) {
62492         var rect = context.surfaceRect();
62493         var point = context.curtainProjection(loc);
62494         var pad = 40;
62495         var width = 250 + (2 * pad);
62496         var height = 350;
62497         var startX = rect.left + point[0];
62498         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
62499         var box = {
62500             left: left,
62501             top: point[1] + rect.top - 60,
62502             width: width,
62503             height: height
62504         };
62505         reveal(box, text$$1, options);
62506     }
62507
62508
62509     function addLine() {
62510         context.enter(modeBrowse(context));
62511         context.history().reset('initial');
62512
62513         var msec = transitionTime(tulipRoadStart, context.map().center());
62514         if (msec) { reveal(null, null, { duration: 0 }); }
62515         context.map().zoom(18.5).centerEase(tulipRoadStart, msec);
62516
62517         timeout(function() {
62518             var tooltip = reveal('button.add-line',
62519                 t('intro.lines.add_line', { button: icon('#icon-line', 'pre-text') }));
62520
62521             tooltip.selectAll('.tooltip-inner')
62522                 .insert('svg', 'span')
62523                 .attr('class', 'tooltip-illustration')
62524                 .append('use')
62525                 .attr('xlink:href', '#feature-images');
62526
62527             context.on('enter.intro', function(mode) {
62528                 if (mode.id !== 'add-line') return;
62529                 continueTo(startLine);
62530             });
62531         }, msec + 100);
62532
62533         function continueTo(nextStep) {
62534             context.on('enter.intro', null);
62535             nextStep();
62536         }
62537     }
62538
62539
62540     function startLine() {
62541         if (context.mode().id !== 'add-line') {
62542             return chapter.restart();
62543         }
62544
62545         tulipRoadId = null;
62546
62547         var padding = 70 * Math.pow(2, context.map().zoom() - 18);
62548         var box = pad$1(tulipRoadStart, padding, context);
62549         box.height = box.height + 100;
62550         reveal(box, t('intro.lines.start_line'));
62551
62552         context.map().on('move.intro drawn.intro', function() {
62553             padding = 70 * Math.pow(2, context.map().zoom() - 18);
62554             box = pad$1(tulipRoadStart, padding, context);
62555             box.height = box.height + 100;
62556             reveal(box, t('intro.lines.start_line'), { duration: 0 });
62557         });
62558
62559         context.on('enter.intro', function(mode) {
62560             if (mode.id !== 'draw-line') return chapter.restart();
62561             continueTo(drawLine);
62562         });
62563
62564         function continueTo(nextStep) {
62565             context.map().on('move.intro drawn.intro', null);
62566             context.on('enter.intro', null);
62567             nextStep();
62568         }
62569     }
62570
62571
62572     function drawLine() {
62573         if (context.mode().id !== 'draw-line') {
62574             return chapter.restart();
62575         }
62576
62577         tulipRoadId = context.mode().selectedIDs()[0];
62578         context.map().centerEase(tulipRoadMidpoint, 500);
62579
62580         timeout(function() {
62581             var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
62582             var box = pad$1(tulipRoadMidpoint, padding, context);
62583             box.height = box.height * 2;
62584             reveal(box,
62585                 t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') })
62586             );
62587
62588             context.map().on('move.intro drawn.intro', function() {
62589                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
62590                 box = pad$1(tulipRoadMidpoint, padding, context);
62591                 box.height = box.height * 2;
62592                 reveal(box,
62593                     t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') }),
62594                     { duration: 0 }
62595                 );
62596             });
62597         }, 550);  // after easing..
62598
62599         context.history().on('change.intro', function() {
62600             var entity = tulipRoadId && context.hasEntity(tulipRoadId);
62601             if (!entity) return chapter.restart();
62602
62603             if (isLineConnected()) {
62604                 continueTo(continueLine);
62605             }
62606         });
62607
62608         context.on('enter.intro', function(mode) {
62609             if (mode.id === 'draw-line')
62610                 return;
62611             else if (mode.id === 'select') {
62612                 continueTo(retryIntersect);
62613                 return;
62614             }
62615             else
62616                 return chapter.restart();
62617         });
62618
62619         function continueTo(nextStep) {
62620             context.map().on('move.intro drawn.intro', null);
62621             context.history().on('change.intro', null);
62622             context.on('enter.intro', null);
62623             nextStep();
62624         }
62625     }
62626
62627
62628     function isLineConnected() {
62629         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
62630         if (!entity) return false;
62631
62632         var drawNodes = context.graph().childNodes(entity);
62633         return lodash.some(drawNodes, function(node) {
62634             return lodash.some(context.graph().parentWays(node), function(parent) {
62635                 return parent.id === flowerRoadId;
62636             });
62637         });
62638     }
62639
62640
62641     function retryIntersect() {
62642         select(window).on('mousedown.intro', eventCancel, true);
62643
62644         var box = pad$1(tulipRoadIntersection, 80, context);
62645         reveal(box,
62646             t('intro.lines.retry_intersect', { name: t('intro.graph.name.flower-street') })
62647         );
62648
62649         timeout(chapter.restart, 3000);
62650     }
62651
62652
62653     function continueLine() {
62654         if (context.mode().id !== 'draw-line') return chapter.restart();
62655         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
62656         if (!entity) return chapter.restart();
62657
62658         context.map().centerEase(tulipRoadIntersection, 500);
62659
62660         reveal('#surface', t('intro.lines.continue_line'));
62661
62662         context.on('enter.intro', function(mode) {
62663             if (mode.id === 'draw-line')
62664                 return;
62665             else if (mode.id === 'select')
62666                 return continueTo(chooseCategoryRoad);
62667             else
62668                 return chapter.restart();
62669         });
62670
62671         function continueTo(nextStep) {
62672             context.on('enter.intro', null);
62673             nextStep();
62674         }
62675     }
62676
62677
62678     function chooseCategoryRoad() {
62679         if (context.mode().id !== 'select') {
62680             return chapter.restart();
62681         }
62682
62683         context.on('exit.intro', function() {
62684             return chapter.restart();
62685         });
62686
62687         var button = select('.preset-category-road .preset-list-button');
62688         if (button.empty()) return chapter.restart();
62689
62690         // disallow scrolling
62691         select('.inspector-wrap').on('wheel.intro', eventCancel);
62692
62693         timeout(function() {
62694             // reset pane, in case user somehow happened to change it..
62695             select('.inspector-wrap .panewrap').style('right', '-100%');
62696
62697             reveal(button.node(),
62698                 t('intro.lines.choose_category_road', { category: roadCategory.name() })
62699             );
62700
62701             button.on('click.intro', function() {
62702                 continueTo(choosePresetResidential);
62703             });
62704
62705         }, 400);  // after editor pane visible
62706
62707         function continueTo(nextStep) {
62708             select('.inspector-wrap').on('wheel.intro', null);
62709             select('.preset-list-button').on('click.intro', null);
62710             context.on('exit.intro', null);
62711             nextStep();
62712         }
62713     }
62714
62715
62716     function choosePresetResidential() {
62717         if (context.mode().id !== 'select') {
62718             return chapter.restart();
62719         }
62720
62721         context.on('exit.intro', function() {
62722             return chapter.restart();
62723         });
62724
62725         var subgrid = select('.preset-category-road .subgrid');
62726         if (subgrid.empty()) return chapter.restart();
62727
62728         subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button')
62729             .on('click.intro', function() {
62730                 continueTo(retryPresetResidential);
62731             });
62732
62733         subgrid.selectAll('.preset-highway-residential .preset-list-button')
62734             .on('click.intro', function() {
62735                 continueTo(nameRoad);
62736             });
62737
62738         timeout(function() {
62739             reveal(subgrid.node(),
62740                 t('intro.lines.choose_preset_residential', { preset: residentialPreset.name() }),
62741                 { tooltipBox: '.preset-highway-residential .preset-list-button', duration: 300 }
62742             );
62743         }, 300);
62744
62745         function continueTo(nextStep) {
62746             select('.preset-list-button').on('click.intro', null);
62747             context.on('exit.intro', null);
62748             nextStep();
62749         }
62750     }
62751
62752
62753     // selected wrong road type
62754     function retryPresetResidential() {
62755         if (context.mode().id !== 'select') {
62756             return chapter.restart();
62757         }
62758
62759         context.on('exit.intro', function() {
62760             return chapter.restart();
62761         });
62762
62763         // disallow scrolling
62764         select('.inspector-wrap').on('wheel.intro', eventCancel);
62765
62766         timeout(function() {
62767             var button = select('.entity-editor-pane .preset-list-button');
62768
62769             reveal(button.node(),
62770                 t('intro.lines.retry_preset_residential', { preset: residentialPreset.name() })
62771             );
62772
62773             button.on('click.intro', function() {
62774                 continueTo(chooseCategoryRoad);
62775             });
62776
62777         }, 500);
62778
62779         function continueTo(nextStep) {
62780             select('.inspector-wrap').on('wheel.intro', null);
62781             select('.preset-list-button').on('click.intro', null);
62782             context.on('exit.intro', null);
62783             nextStep();
62784         }
62785     }
62786
62787
62788     function nameRoad() {
62789         context.on('exit.intro', function() {
62790             continueTo(didNameRoad);
62791         });
62792
62793         timeout(function() {
62794             reveal('.entity-editor-pane',
62795                 t('intro.lines.name_road', { button: icon('#icon-apply', 'pre-text') }),
62796                 { tooltipClass: 'intro-lines-name_road' }
62797             );
62798         }, 500);
62799
62800         function continueTo(nextStep) {
62801             context.on('exit.intro', null);
62802             nextStep();
62803         }
62804     }
62805
62806
62807     function didNameRoad() {
62808         context.history().checkpoint('doneAddLine');
62809
62810         timeout(function() {
62811             reveal('#surface', t('intro.lines.did_name_road'), {
62812                 buttonText: t('intro.ok'),
62813                 buttonCallback: function() { continueTo(updateLine); }
62814             });
62815         }, 500);
62816
62817         function continueTo(nextStep) {
62818             nextStep();
62819         }
62820     }
62821
62822
62823     function updateLine() {
62824         context.history().reset('doneAddLine');
62825         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62826             return chapter.restart();
62827         }
62828
62829         var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
62830         if (msec) { reveal(null, null, { duration: 0 }); }
62831         context.map().zoom(19).centerEase(woodRoadDragMidpoint, msec);
62832
62833         timeout(function() {
62834             var padding = 250 * Math.pow(2, context.map().zoom() - 19);
62835             var box = pad$1(woodRoadDragMidpoint, padding, context);
62836             var advance = function() { continueTo(addNode); };
62837
62838             reveal(box, t('intro.lines.update_line'),
62839                 { buttonText: t('intro.ok'), buttonCallback: advance }
62840             );
62841
62842             context.map().on('move.intro drawn.intro', function() {
62843                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
62844                 var box = pad$1(woodRoadDragMidpoint, padding, context);
62845                 reveal(box, t('intro.lines.update_line'),
62846                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
62847                 );
62848             });
62849         }, msec + 100);
62850
62851         function continueTo(nextStep) {
62852             context.map().on('move.intro drawn.intro', null);
62853             nextStep();
62854         }
62855     }
62856
62857
62858     function addNode() {
62859         context.history().reset('doneAddLine');
62860         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62861             return chapter.restart();
62862         }
62863
62864         var padding = 40 * Math.pow(2, context.map().zoom() - 19);
62865         var box = pad$1(woodRoadAddNode, padding, context);
62866         reveal(box, t('intro.lines.add_node'));
62867
62868         context.map().on('move.intro drawn.intro', function() {
62869             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
62870             var box = pad$1(woodRoadAddNode, padding, context);
62871             reveal(box, t('intro.lines.add_node'), { duration: 0 });
62872         });
62873
62874         context.history().on('change.intro', function(changed) {
62875             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62876                 return continueTo(updateLine);
62877             }
62878             if (changed.created().length === 1) {
62879                 timeout(function() { continueTo(startDragEndpoint); }, 500);
62880             }
62881         });
62882
62883         context.on('enter.intro', function(mode) {
62884             if (mode.id !== 'select') {
62885                 continueTo(updateLine);
62886             }
62887         });
62888
62889         function continueTo(nextStep) {
62890             context.map().on('move.intro drawn.intro', null);
62891             context.history().on('change.intro', null);
62892             context.on('enter.intro', null);
62893             nextStep();
62894         }
62895     }
62896
62897
62898     function startDragEndpoint() {
62899         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62900             return continueTo(updateLine);
62901         }
62902         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
62903             context.enter(modeSelect(context, [woodRoadId]));
62904         }
62905
62906         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62907         var box = pad$1(woodRoadDragEndpoint, padding, context);
62908         reveal(box, t('intro.lines.start_drag_endpoint'));
62909
62910         context.map().on('move.intro drawn.intro', function() {
62911             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62912                 return continueTo(updateLine);
62913             }
62914             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62915             var box = pad$1(woodRoadDragEndpoint, padding, context);
62916             reveal(box, t('intro.lines.start_drag_endpoint'), { duration: 0 });
62917
62918             var entity = context.entity(woodRoadEndId);
62919             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
62920                 continueTo(finishDragEndpoint);
62921             }
62922         });
62923
62924         context.on('enter.intro', function(mode) {
62925             if (mode.id !== 'select') {
62926                 // keep Wood Road selected so endpoint stays draggable..
62927                 context.enter(modeSelect(context, [woodRoadId]));
62928             }
62929         });
62930
62931         function continueTo(nextStep) {
62932             context.map().on('move.intro drawn.intro', null);
62933             context.on('enter.intro', null);
62934             nextStep();
62935         }
62936     }
62937
62938
62939     function finishDragEndpoint() {
62940         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62941             return continueTo(updateLine);
62942         }
62943
62944         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62945         var box = pad$1(woodRoadDragEndpoint, padding, context);
62946         reveal(box, t('intro.lines.finish_drag_endpoint'));
62947
62948         context.map().on('move.intro drawn.intro', function() {
62949             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62950                 return continueTo(updateLine);
62951             }
62952             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
62953             var box = pad$1(woodRoadDragEndpoint, padding, context);
62954             reveal(box, t('intro.lines.finish_drag_endpoint'), { duration: 0 });
62955
62956             var entity = context.entity(woodRoadEndId);
62957             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
62958                 continueTo(startDragEndpoint);
62959             }
62960         });
62961
62962         context.on('enter.intro', function() {
62963             continueTo(startDragMidpoint);
62964         });
62965
62966         function continueTo(nextStep) {
62967             context.map().on('move.intro drawn.intro', null);
62968             context.on('enter.intro', null);
62969             nextStep();
62970         }
62971     }
62972
62973
62974     function startDragMidpoint() {
62975         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62976             return continueTo(updateLine);
62977         }
62978         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
62979             context.enter(modeSelect(context, [woodRoadId]));
62980         }
62981
62982         var padding = 80 * Math.pow(2, context.map().zoom() - 19);
62983         var box = pad$1(woodRoadDragMidpoint, padding, context);
62984         reveal(box, t('intro.lines.start_drag_midpoint'));
62985
62986         context.map().on('move.intro drawn.intro', function() {
62987             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
62988                 return continueTo(updateLine);
62989             }
62990             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
62991             var box = pad$1(woodRoadDragMidpoint, padding, context);
62992             reveal(box, t('intro.lines.start_drag_midpoint'), { duration: 0 });
62993         });
62994
62995         context.history().on('change.intro', function(changed) {
62996             if (changed.created().length === 1) {
62997                 continueTo(continueDragMidpoint);
62998             }
62999         });
63000
63001         context.on('enter.intro', function(mode) {
63002             if (mode.id !== 'select') {
63003                 // keep Wood Road selected so midpoint triangles are drawn..
63004                 context.enter(modeSelect(context, [woodRoadId]));
63005             }
63006         });
63007
63008         function continueTo(nextStep) {
63009             context.map().on('move.intro drawn.intro', null);
63010             context.history().on('change.intro', null);
63011             context.on('enter.intro', null);
63012             nextStep();
63013         }
63014     }
63015
63016
63017     function continueDragMidpoint() {
63018         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
63019             return continueTo(updateLine);
63020         }
63021
63022         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
63023         var box = pad$1(woodRoadDragEndpoint, padding, context);
63024         box.height += 400;
63025
63026         var advance = function() {
63027             context.history().checkpoint('doneUpdateLine');
63028             continueTo(deleteLines);
63029         };
63030
63031         reveal(box, t('intro.lines.continue_drag_midpoint'),
63032             { buttonText: t('intro.ok'), buttonCallback: advance }
63033         );
63034
63035         context.map().on('move.intro drawn.intro', function() {
63036             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
63037                 return continueTo(updateLine);
63038             }
63039             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
63040             var box = pad$1(woodRoadDragEndpoint, padding, context);
63041             box.height += 400;
63042             reveal(box, t('intro.lines.continue_drag_midpoint'),
63043                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
63044             );
63045         });
63046
63047         function continueTo(nextStep) {
63048             context.map().on('move.intro drawn.intro', null);
63049             nextStep();
63050         }
63051     }
63052
63053
63054     function deleteLines() {
63055         context.history().reset('doneUpdateLine');
63056         context.enter(modeBrowse(context));
63057
63058         if (!context.hasEntity(washingtonStreetId) ||
63059             !context.hasEntity(twelfthAvenueId) ||
63060             !context.hasEntity(eleventhAvenueEndId)) {
63061             return chapter.restart();
63062         }
63063
63064         var msec = transitionTime(deleteLinesLoc, context.map().center());
63065         if (msec) { reveal(null, null, { duration: 0 }); }
63066         context.map().zoom(18).centerEase(deleteLinesLoc, msec);
63067
63068         timeout(function() {
63069             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63070             var box = pad$1(deleteLinesLoc, padding, context);
63071             box.top -= 200;
63072             box.height += 400;
63073             var advance = function() { continueTo(rightClickIntersection); };
63074
63075             reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
63076                 { buttonText: t('intro.ok'), buttonCallback: advance }
63077             );
63078
63079             context.map().on('move.intro drawn.intro', function() {
63080                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63081                 var box = pad$1(deleteLinesLoc, padding, context);
63082                 box.top -= 200;
63083                 box.height += 400;
63084                 reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
63085                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
63086                 );
63087             });
63088
63089             context.history().on('change.intro', function() {
63090                 timeout(function() {
63091                     continueTo(deleteLines);
63092                 }, 500);  // after any transition (e.g. if user deleted intersection)
63093             });
63094
63095         }, msec + 100);
63096
63097         function continueTo(nextStep) {
63098             context.map().on('move.intro drawn.intro', null);
63099             context.history().on('change.intro', null);
63100             nextStep();
63101         }
63102     }
63103
63104
63105     function rightClickIntersection() {
63106         context.history().reset('doneUpdateLine');
63107         context.enter(modeBrowse(context));
63108
63109         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
63110
63111         timeout(function() {
63112             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
63113             var box = pad$1(eleventhAvenueEnd, padding, context);
63114             reveal(box, t('intro.lines.rightclick_intersection',
63115                 { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') })
63116             );
63117
63118             context.map().on('move.intro drawn.intro', function() {
63119                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
63120                 var box = pad$1(eleventhAvenueEnd, padding, context);
63121                 reveal(box, t('intro.lines.rightclick_intersection',
63122                     { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') }),
63123                     { duration: 0 }
63124                 );
63125             });
63126
63127             context.on('enter.intro', function(mode) {
63128                 if (mode.id !== 'select') return;
63129                 var ids = context.selectedIDs();
63130                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndId) return;
63131
63132                 timeout(function() {
63133                     var node = selectMenuItem('split').node();
63134                     if (!node) return;
63135                     continueTo(splitIntersection);
63136                 }, 300);  // after menu visible
63137             });
63138
63139             context.history().on('change.intro', function() {
63140                 timeout(function() {
63141                     continueTo(deleteLines);
63142                 }, 300);  // after any transition (e.g. if user deleted intersection)
63143             });
63144
63145         }, 600);
63146
63147         function continueTo(nextStep) {
63148             context.map().on('move.intro drawn.intro', null);
63149             context.on('enter.intro', null);
63150             context.history().on('change.intro', null);
63151             nextStep();
63152         }
63153     }
63154
63155
63156     function splitIntersection() {
63157         if (!context.hasEntity(washingtonStreetId) ||
63158             !context.hasEntity(twelfthAvenueId) ||
63159             !context.hasEntity(eleventhAvenueEndId)) {
63160             return continueTo(deleteLines);
63161         }
63162
63163         var node = selectMenuItem('split').node();
63164         if (!node) { return continueTo(rightClickIntersection); }
63165
63166         var wasChanged = false;
63167         var menuCoords = context.map().mouseCoordinates();
63168         washingtonSegmentId = null;
63169
63170         revealEditMenu(menuCoords, t('intro.lines.split_intersection',
63171             { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') })
63172         );
63173
63174         context.map().on('move.intro drawn.intro', function() {
63175             var node = selectMenuItem('split').node();
63176             if (!wasChanged && !node) { return continueTo(rightClickIntersection); }
63177
63178             revealEditMenu(menuCoords, t('intro.lines.split_intersection',
63179                 { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') }),
63180                 { duration: 0 }
63181             );
63182         });
63183
63184         context.history().on('change.intro', function(changed) {
63185             wasChanged = true;
63186             timeout(function() {
63187                 if (context.history().undoAnnotation() === t('operations.split.annotation.line')) {
63188                     washingtonSegmentId = changed.created()[0].id;
63189                     continueTo(didSplit);
63190                 } else {
63191                     washingtonSegmentId = null;
63192                     continueTo(retrySplit);
63193                 }
63194             }, 300);  // after any transition (e.g. if user deleted intersection)
63195         });
63196
63197         function continueTo(nextStep) {
63198             context.map().on('move.intro drawn.intro', null);
63199             context.history().on('change.intro', null);
63200             nextStep();
63201         }
63202     }
63203
63204
63205     function retrySplit() {
63206         context.enter(modeBrowse(context));
63207         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
63208         var advance = function() { continueTo(rightClickIntersection); };
63209
63210         var padding = 60 * Math.pow(2, context.map().zoom() - 18);
63211         var box = pad$1(eleventhAvenueEnd, padding, context);
63212         reveal(box, t('intro.lines.retry_split'),
63213             { buttonText: t('intro.ok'), buttonCallback: advance }
63214         );
63215
63216         context.map().on('move.intro drawn.intro', function() {
63217             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
63218             var box = pad$1(eleventhAvenueEnd, padding, context);
63219             reveal(box, t('intro.lines.retry_split'),
63220                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
63221             );
63222         });
63223
63224         function continueTo(nextStep) {
63225             context.map().on('move.intro drawn.intro', null);
63226             nextStep();
63227         }
63228     }
63229
63230
63231     function didSplit() {
63232         if (!washingtonSegmentId ||
63233             !context.hasEntity(washingtonSegmentId) ||
63234             !context.hasEntity(washingtonStreetId) ||
63235             !context.hasEntity(twelfthAvenueId) ||
63236             !context.hasEntity(eleventhAvenueEndId)) {
63237             return continueTo(rightClickIntersection);
63238         }
63239
63240         var ids = context.selectedIDs();
63241         var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
63242         var street = t('intro.graph.name.washington-street');
63243
63244         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63245         var box = pad$1(twelfthAvenue, padding, context);
63246         box.width = box.width / 2;
63247         reveal(box, t(string, { street1: street, street2: street }),
63248             { duration: 500 }
63249         );
63250
63251         timeout(function() {
63252             context.map().zoom(18).centerEase(twelfthAvenue, 500);
63253
63254             context.map().on('move.intro drawn.intro', function() {
63255                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63256                 var box = pad$1(twelfthAvenue, padding, context);
63257                 box.width = box.width / 2;
63258                 reveal(box, t(string, { street1: street, street2: street }),
63259                     { duration: 0 }
63260                 );
63261             });
63262         }, 600);  // after initial reveal and curtain cut
63263
63264         context.on('enter.intro', function() {
63265             var ids = context.selectedIDs();
63266             if (ids.length === 1 && ids[0] === washingtonSegmentId) {
63267                 continueTo(multiSelect);
63268             }
63269         });
63270
63271         context.history().on('change.intro', function() {
63272             if (!washingtonSegmentId ||
63273                 !context.hasEntity(washingtonSegmentId) ||
63274                 !context.hasEntity(washingtonStreetId) ||
63275                 !context.hasEntity(twelfthAvenueId) ||
63276                 !context.hasEntity(eleventhAvenueEndId)) {
63277                 return continueTo(rightClickIntersection);
63278             }
63279         });
63280
63281         function continueTo(nextStep) {
63282             context.map().on('move.intro drawn.intro', null);
63283             context.on('enter.intro', null);
63284             context.history().on('change.intro', null);
63285             nextStep();
63286         }
63287     }
63288
63289
63290     function multiSelect() {
63291         if (!washingtonSegmentId ||
63292             !context.hasEntity(washingtonSegmentId) ||
63293             !context.hasEntity(washingtonStreetId) ||
63294             !context.hasEntity(twelfthAvenueId) ||
63295             !context.hasEntity(eleventhAvenueEndId)) {
63296             return continueTo(rightClickIntersection);
63297         }
63298
63299         var ids = context.selectedIDs();
63300         var hasWashington = ids.indexOf(washingtonSegmentId) !== -1;
63301         var hasTwelfth = ids.indexOf(twelfthAvenueId) !== -1;
63302
63303         if (hasWashington && hasTwelfth) {
63304             return continueTo(multiRightClick);
63305         } else if (!hasWashington && !hasTwelfth) {
63306             return continueTo(didSplit);
63307         }
63308
63309         context.map().zoom(18).centerEase(twelfthAvenue, 500);
63310
63311         timeout(function() {
63312             var selected, other, padding, box;
63313             if (hasWashington) {
63314                 selected = t('intro.graph.name.washington-street');
63315                 other = t('intro.graph.name.12th-avenue');
63316                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
63317                 box = pad$1(twelfthAvenueEnd, padding, context);
63318                 box.width *= 3;
63319             } else {
63320                 selected = t('intro.graph.name.12th-avenue');
63321                 other = t('intro.graph.name.washington-street');
63322                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
63323                 box = pad$1(twelfthAvenue, padding, context);
63324                 box.width /= 2;
63325             }
63326
63327             reveal(box,
63328                 t('intro.lines.multi_select', { selected: selected, other1: other, other2: other })
63329             );
63330
63331             context.map().on('move.intro drawn.intro', function() {
63332                 if (hasWashington) {
63333                     selected = t('intro.graph.name.washington-street');
63334                     other = t('intro.graph.name.12th-avenue');
63335                     padding = 60 * Math.pow(2, context.map().zoom() - 18);
63336                     box = pad$1(twelfthAvenueEnd, padding, context);
63337                     box.width *= 3;
63338                 } else {
63339                     selected = t('intro.graph.name.12th-avenue');
63340                     other = t('intro.graph.name.washington-street');
63341                     padding = 200 * Math.pow(2, context.map().zoom() - 18);
63342                     box = pad$1(twelfthAvenue, padding, context);
63343                     box.width /= 2;
63344                 }
63345
63346                 reveal(box,
63347                     t('intro.lines.multi_select', { selected: selected, other1: other, other2: other }),
63348                     { duration: 0 }
63349                 );
63350             });
63351
63352             context.on('enter.intro', function() {
63353                 continueTo(multiSelect);
63354             });
63355
63356             context.history().on('change.intro', function() {
63357                 if (!washingtonSegmentId ||
63358                     !context.hasEntity(washingtonSegmentId) ||
63359                     !context.hasEntity(washingtonStreetId) ||
63360                     !context.hasEntity(twelfthAvenueId) ||
63361                     !context.hasEntity(eleventhAvenueEndId)) {
63362                     return continueTo(rightClickIntersection);
63363                 }
63364             });
63365         }, 600);
63366
63367         function continueTo(nextStep) {
63368             context.map().on('move.intro drawn.intro', null);
63369             context.on('enter.intro', null);
63370             context.history().on('change.intro', null);
63371             nextStep();
63372         }
63373     }
63374
63375
63376     function multiRightClick() {
63377         if (!washingtonSegmentId ||
63378             !context.hasEntity(washingtonSegmentId) ||
63379             !context.hasEntity(washingtonStreetId) ||
63380             !context.hasEntity(twelfthAvenueId) ||
63381             !context.hasEntity(eleventhAvenueEndId)) {
63382             return continueTo(rightClickIntersection);
63383         }
63384
63385         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63386         var box = pad$1(twelfthAvenue, padding, context);
63387         reveal(box, t('intro.lines.multi_rightclick'));
63388
63389         context.map().on('move.intro drawn.intro', function() {
63390             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63391             var box = pad$1(twelfthAvenue, padding, context);
63392             reveal(box, t('intro.lines.multi_rightclick'), { duration: 0 });
63393         });
63394
63395         select(window).on('click.intro contextmenu.intro', function() {
63396             timeout(function() {
63397                 var ids = context.selectedIDs();
63398                 if (ids.length === 2 &&
63399                     ids.indexOf(twelfthAvenueId) !== -1 &&
63400                     ids.indexOf(washingtonSegmentId) !== -1) {
63401                         var node = selectMenuItem('delete').node();
63402                         if (!node) return;
63403                         continueTo(multiDelete);
63404                 } else if (ids.length === 1 &&
63405                     ids.indexOf(washingtonSegmentId) !== -1) {
63406                     return continueTo(multiSelect);
63407                 } else {
63408                     return continueTo(didSplit);
63409                 }
63410             }, 300);  // after edit menu visible
63411         }, true);
63412
63413         context.history().on('change.intro', function() {
63414             if (!washingtonSegmentId ||
63415                 !context.hasEntity(washingtonSegmentId) ||
63416                 !context.hasEntity(washingtonStreetId) ||
63417                 !context.hasEntity(twelfthAvenueId) ||
63418                 !context.hasEntity(eleventhAvenueEndId)) {
63419                 return continueTo(rightClickIntersection);
63420             }
63421         });
63422
63423         function continueTo(nextStep) {
63424             context.map().on('move.intro drawn.intro', null);
63425             select(window).on('click.intro contextmenu.intro', null, true);
63426             context.history().on('change.intro', null);
63427             nextStep();
63428         }
63429     }
63430
63431
63432     function multiDelete() {
63433         if (!washingtonSegmentId ||
63434             !context.hasEntity(washingtonSegmentId) ||
63435             !context.hasEntity(washingtonStreetId) ||
63436             !context.hasEntity(twelfthAvenueId) ||
63437             !context.hasEntity(eleventhAvenueEndId)) {
63438             return continueTo(rightClickIntersection);
63439         }
63440
63441         var node = selectMenuItem('delete').node();
63442         if (!node) return continueTo(multiRightClick);
63443
63444         var menuCoords = context.map().mouseCoordinates();
63445         revealEditMenu(menuCoords,
63446             t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') })
63447         );
63448
63449         context.map().on('move.intro drawn.intro', function() {
63450             revealEditMenu(menuCoords,
63451                 t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') }),
63452                 { duration: 0 }
63453             );
63454         });
63455
63456         context.on('exit.intro', function() {
63457             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
63458                 return continueTo(multiSelect);  // left select mode but roads still exist
63459             }
63460         });
63461
63462         context.history().on('change.intro', function() {
63463             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
63464                 continueTo(retryDelete);         // changed something but roads still exist
63465             } else {
63466                 continueTo(play);
63467             }
63468         });
63469
63470         function continueTo(nextStep) {
63471             context.map().on('move.intro drawn.intro', null);
63472             context.on('exit.intro', null);
63473             context.history().on('change.intro', null);
63474             nextStep();
63475         }
63476     }
63477
63478
63479     function retryDelete() {
63480         context.enter(modeBrowse(context));
63481
63482         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
63483         var box = pad$1(twelfthAvenue, padding, context);
63484         reveal(box, t('intro.lines.retry_delete'), {
63485             buttonText: t('intro.ok'),
63486             buttonCallback: function() { continueTo(multiSelect); }
63487         });
63488
63489         function continueTo(nextStep) {
63490             nextStep();
63491         }
63492     }
63493
63494
63495     function play() {
63496         dispatch$$1.call('done');
63497         reveal('#id-container',
63498             t('intro.lines.play', { next: t('intro.buildings.title') }), {
63499                 tooltipBox: '.intro-nav-wrap .chapter-building',
63500                 buttonText: t('intro.ok'),
63501                 buttonCallback: function() { reveal('#id-container'); }
63502             }
63503         );
63504    }
63505
63506
63507     chapter.enter = function() {
63508         addLine();
63509     };
63510
63511
63512     chapter.exit = function() {
63513         timeouts.forEach(window.clearTimeout);
63514         select(window).on('mousedown.intro', null, true);
63515         context.on('enter.intro exit.intro', null);
63516         context.map().on('move.intro drawn.intro', null);
63517         context.history().on('change.intro', null);
63518         select('.inspector-wrap').on('wheel.intro', null);
63519         select('.preset-list-button').on('click.intro', null);
63520     };
63521
63522
63523     chapter.restart = function() {
63524         chapter.exit();
63525         chapter.enter();
63526     };
63527
63528
63529     return utilRebind(chapter, dispatch$$1, 'on');
63530 }
63531
63532 function uiIntroBuilding(context, reveal) {
63533     var dispatch$$1 = dispatch('done'),
63534         house = [-85.62815, 41.95638],
63535         tank = [-85.62732, 41.95347],
63536         buildingCatetory = context.presets().item('category-building'),
63537         housePreset = context.presets().item('building/house'),
63538         tankPreset = context.presets().item('man_made/storage_tank'),
63539         timeouts = [],
63540         houseId = null,
63541         tankId = null;
63542
63543
63544     var chapter = {
63545         title: 'intro.buildings.title'
63546     };
63547
63548
63549     function timeout(f, t$$1) {
63550         timeouts.push(window.setTimeout(f, t$$1));
63551     }
63552
63553
63554     function eventCancel() {
63555         event.stopPropagation();
63556         event.preventDefault();
63557     }
63558
63559
63560     function revealHouse(center, text$$1, options) {
63561         var padding = 160 * Math.pow(2, context.map().zoom() - 20);
63562         var box = pad$1(center, padding, context);
63563         reveal(box, text$$1, options);
63564     }
63565
63566
63567     function revealTank(center, text$$1, options) {
63568         var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
63569         var box = pad$1(center, padding, context);
63570         reveal(box, text$$1, options);
63571     }
63572
63573
63574     function revealEditMenu(loc, text$$1, options) {
63575         var rect = context.surfaceRect();
63576         var point = context.curtainProjection(loc);
63577         var pad = 40;
63578         var width = 250 + (2 * pad);
63579         var height = 350;
63580         var startX = rect.left + point[0];
63581         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
63582         var box = {
63583             left: left,
63584             top: point[1] + rect.top - 60,
63585             width: width,
63586             height: height
63587         };
63588         reveal(box, text$$1, options);
63589     }
63590
63591
63592     function addHouse() {
63593         context.enter(modeBrowse(context));
63594         context.history().reset('initial');
63595         houseId = null;
63596
63597         var msec = transitionTime(house, context.map().center());
63598         if (msec) { reveal(null, null, { duration: 0 }); }
63599         context.map().zoom(19).centerEase(house, msec);
63600
63601         timeout(function() {
63602             var tooltip = reveal('button.add-area',
63603                 t('intro.buildings.add_building', { button: icon('#icon-area', 'pre-text') }));
63604
63605             tooltip.selectAll('.tooltip-inner')
63606                 .insert('svg', 'span')
63607                 .attr('class', 'tooltip-illustration')
63608                 .append('use')
63609                 .attr('xlink:href', '#building-images');
63610
63611             context.on('enter.intro', function(mode) {
63612                 if (mode.id !== 'add-area') return;
63613                 continueTo(startHouse);
63614             });
63615         }, msec + 100);
63616
63617         function continueTo(nextStep) {
63618             context.on('enter.intro', null);
63619             nextStep();
63620         }
63621     }
63622
63623
63624     function startHouse() {
63625         if (context.mode().id !== 'add-area') {
63626             return continueTo(addHouse);
63627         }
63628
63629         houseId = null;
63630         context.map().zoomEase(20, 500);
63631
63632         timeout(function() {
63633             revealHouse(house, t('intro.buildings.start_building'));
63634
63635             context.map().on('move.intro drawn.intro', function() {
63636                 revealHouse(house, t('intro.buildings.start_building'), { duration: 0 });
63637             });
63638
63639             context.on('enter.intro', function(mode) {
63640                 if (mode.id !== 'draw-area') return chapter.restart();
63641                 continueTo(continueHouse);
63642             });
63643
63644         }, 550);  // after easing
63645
63646         function continueTo(nextStep) {
63647             context.map().on('move.intro drawn.intro', null);
63648             context.on('enter.intro', null);
63649             nextStep();
63650         }
63651     }
63652
63653
63654     function continueHouse() {
63655         if (context.mode().id !== 'draw-area') {
63656             return continueTo(addHouse);
63657         }
63658
63659         houseId = null;
63660
63661         revealHouse(house, t('intro.buildings.continue_building'));
63662
63663         context.map().on('move.intro drawn.intro', function() {
63664             revealHouse(house, t('intro.buildings.continue_building'), { duration: 0 });
63665         });
63666
63667         context.on('enter.intro', function(mode) {
63668             if (mode.id === 'draw-area') {
63669                 return;
63670             } else if (mode.id === 'select') {
63671                 var graph = context.graph(),
63672                     way = context.entity(context.selectedIDs()[0]),
63673                     nodes = graph.childNodes(way),
63674                     points = lodash.uniq(nodes).map(function(n) { return context.projection(n.loc); });
63675
63676                 if (isMostlySquare(points)) {
63677                     houseId = way.id;
63678                     return continueTo(chooseCategoryBuilding);
63679                 } else {
63680                     return continueTo(retryHouse);
63681                 }
63682
63683             } else {
63684                 return chapter.restart();
63685             }
63686         });
63687
63688         function continueTo(nextStep) {
63689             context.map().on('move.intro drawn.intro', null);
63690             context.on('enter.intro', null);
63691             nextStep();
63692         }
63693     }
63694
63695
63696     function retryHouse() {
63697         var onClick = function() { continueTo(addHouse); };
63698
63699         revealHouse(house, t('intro.buildings.retry_building'),
63700             { buttonText: t('intro.ok'), buttonCallback: onClick }
63701         );
63702
63703         context.map().on('move.intro drawn.intro', function() {
63704             revealHouse(house, t('intro.buildings.retry_building'),
63705                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
63706             );
63707         });
63708
63709         function continueTo(nextStep) {
63710             context.map().on('move.intro drawn.intro', null);
63711             nextStep();
63712         }
63713     }
63714
63715
63716     function chooseCategoryBuilding() {
63717         if (!houseId || !context.hasEntity(houseId)) {
63718             return addHouse();
63719         }
63720         var ids = context.selectedIDs();
63721         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
63722             context.enter(modeSelect(context, [houseId]));
63723         }
63724
63725         // disallow scrolling
63726         select('.inspector-wrap').on('wheel.intro', eventCancel);
63727
63728         timeout(function() {
63729             // reset pane, in case user somehow happened to change it..
63730             select('.inspector-wrap .panewrap').style('right', '-100%');
63731
63732             var button = select('.preset-category-building .preset-list-button');
63733
63734             reveal(button.node(),
63735                 t('intro.buildings.choose_category_building', { category: buildingCatetory.name() })
63736             );
63737
63738             button.on('click.intro', function() {
63739                 button.on('click.intro', null);
63740                 continueTo(choosePresetHouse);
63741             });
63742
63743         }, 400);  // after preset list pane visible..
63744
63745
63746         context.on('enter.intro', function(mode) {
63747             if (!houseId || !context.hasEntity(houseId)) {
63748                 return continueTo(addHouse);
63749             }
63750             var ids = context.selectedIDs();
63751             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
63752                 return continueTo(chooseCategoryBuilding);
63753             }
63754         });
63755
63756         function continueTo(nextStep) {
63757             select('.inspector-wrap').on('wheel.intro', null);
63758             select('.preset-list-button').on('click.intro', null);
63759             context.on('enter.intro', null);
63760             nextStep();
63761         }
63762     }
63763
63764
63765     function choosePresetHouse() {
63766         if (!houseId || !context.hasEntity(houseId)) {
63767             return addHouse();
63768         }
63769         var ids = context.selectedIDs();
63770         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
63771             context.enter(modeSelect(context, [houseId]));
63772         }
63773
63774         // disallow scrolling
63775         select('.inspector-wrap').on('wheel.intro', eventCancel);
63776
63777         timeout(function() {
63778             // reset pane, in case user somehow happened to change it..
63779             select('.inspector-wrap .panewrap').style('right', '-100%');
63780
63781             var button = select('.preset-building-house .preset-list-button');
63782
63783             reveal(button.node(),
63784                 t('intro.buildings.choose_preset_house', { preset: housePreset.name() }),
63785                 { duration: 300 }
63786             );
63787
63788             button.on('click.intro', function() {
63789                 button.on('click.intro', null);
63790                 continueTo(closeEditorHouse);
63791             });
63792
63793
63794         }, 400);  // after preset list pane visible..
63795
63796         context.on('enter.intro', function(mode) {
63797             if (!houseId || !context.hasEntity(houseId)) {
63798                 return continueTo(addHouse);
63799             }
63800             var ids = context.selectedIDs();
63801             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
63802                 return continueTo(chooseCategoryBuilding);
63803             }
63804         });
63805
63806         function continueTo(nextStep) {
63807             select('.inspector-wrap').on('wheel.intro', null);
63808             select('.preset-list-button').on('click.intro', null);
63809             context.on('enter.intro', null);
63810             nextStep();
63811         }
63812     }
63813
63814
63815     function closeEditorHouse() {
63816         if (!houseId || !context.hasEntity(houseId)) {
63817             return addHouse();
63818         }
63819         var ids = context.selectedIDs();
63820         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
63821             context.enter(modeSelect(context, [houseId]));
63822         }
63823
63824         context.history().checkpoint('hasHouse');
63825
63826         context.on('exit.intro', function() {
63827             continueTo(rightClickHouse);
63828         });
63829
63830         timeout(function() {
63831             reveal('.entity-editor-pane',
63832                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
63833             );
63834         }, 500);
63835
63836         function continueTo(nextStep) {
63837             context.on('exit.intro', null);
63838             nextStep();
63839         }
63840     }
63841
63842
63843     function rightClickHouse() {
63844         if (!houseId) return chapter.restart();
63845
63846         context.enter(modeBrowse(context));
63847         context.history().reset('hasHouse');
63848         context.map().centerEase(house, 500);
63849
63850         timeout(function() {
63851             if (context.map().zoom() < 20) {
63852                 context.map().zoomEase(20, 500);
63853             }
63854         }, 520);
63855
63856         context.on('enter.intro', function(mode) {
63857             if (mode.id !== 'select') return;
63858             var ids = context.selectedIDs();
63859             if (ids.length !== 1 || ids[0] !== houseId) return;
63860
63861             timeout(function() {
63862                 var node = selectMenuItem('orthogonalize').node();
63863                 if (!node) return;
63864                 continueTo(clickSquare);
63865             }, 300);  // after menu visible
63866         });
63867
63868         context.map().on('move.intro drawn.intro', function() {
63869             revealHouse(house, t('intro.buildings.rightclick_building'), { duration: 0 });
63870         });
63871
63872         context.history().on('change.intro', function() {
63873             continueTo(rightClickHouse);
63874         });
63875
63876         function continueTo(nextStep) {
63877             context.on('enter.intro', null);
63878             context.map().on('move.intro drawn.intro', null);
63879             context.history().on('change.intro', null);
63880             nextStep();
63881         }
63882     }
63883
63884
63885     function clickSquare() {
63886         if (!houseId) return chapter.restart();
63887         var entity = context.hasEntity(houseId);
63888         if (!entity) return continueTo(rightClickHouse);
63889
63890         var node = selectMenuItem('orthogonalize').node();
63891         if (!node) { return continueTo(rightClickHouse); }
63892
63893         var wasChanged = false;
63894         var menuCoords = context.map().mouseCoordinates();
63895
63896         revealEditMenu(menuCoords,
63897             t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') })
63898         );
63899
63900         context.on('enter.intro', function(mode) {
63901             if (mode.id === 'browse') {
63902                 continueTo(rightClickHouse);
63903             } else if (mode.id === 'move' || mode.id === 'rotate') {
63904                 continueTo(retryClickSquare);
63905             }
63906         });
63907
63908         context.map().on('move.intro drawn.intro', function() {
63909             var node = selectMenuItem('orthogonalize').node();
63910             if (!wasChanged && !node) { return continueTo(rightClickHouse); }
63911
63912             revealEditMenu(menuCoords,
63913                 t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') }),
63914                 { duration: 0 }
63915             );
63916         });
63917
63918         context.history().on('change.intro', function() {
63919             wasChanged = true;
63920             context.history().on('change.intro', null);
63921
63922             // Something changed.  Wait for transition to complete and check undo annotation.
63923             timeout(function() {
63924                 if (context.history().undoAnnotation() === t('operations.orthogonalize.annotation.area')) {
63925                     continueTo(doneSquare);
63926                 } else {
63927                     continueTo(retryClickSquare);
63928                 }
63929             }, 500);  // after transitioned actions
63930         });
63931
63932         function continueTo(nextStep) {
63933             context.on('enter.intro', null);
63934             context.map().on('move.intro drawn.intro', null);
63935             context.history().on('change.intro', null);
63936             nextStep();
63937         }
63938     }
63939
63940
63941     function retryClickSquare() {
63942         context.enter(modeBrowse(context));
63943
63944         revealHouse(house, t('intro.buildings.retry_square'), {
63945             buttonText: t('intro.ok'),
63946             buttonCallback: function() { continueTo(rightClickHouse); }
63947         });
63948
63949         function continueTo(nextStep) {
63950             nextStep();
63951         }
63952     }
63953
63954
63955     function doneSquare() {
63956         context.history().checkpoint('doneSquare');
63957
63958         revealHouse(house, t('intro.buildings.done_square'), {
63959             buttonText: t('intro.ok'),
63960             buttonCallback: function() { continueTo(addTank); }
63961         });
63962
63963         function continueTo(nextStep) {
63964             nextStep();
63965         }
63966     }
63967
63968
63969     function addTank() {
63970         context.enter(modeBrowse(context));
63971         context.history().reset('doneSquare');
63972         tankId = null;
63973
63974         var msec = transitionTime(tank, context.map().center());
63975         if (msec) { reveal(null, null, { duration: 0 }); }
63976         context.map().zoom(19.5).centerEase(tank, msec);
63977
63978         timeout(function() {
63979             reveal('button.add-area',
63980                 t('intro.buildings.add_tank', { button: icon('#icon-area', 'pre-text') })
63981             );
63982
63983             context.on('enter.intro', function(mode) {
63984                 if (mode.id !== 'add-area') return;
63985                 continueTo(startTank);
63986             });
63987         }, msec + 100);
63988
63989         function continueTo(nextStep) {
63990             context.on('enter.intro', null);
63991             nextStep();
63992         }
63993     }
63994
63995
63996     function startTank() {
63997         if (context.mode().id !== 'add-area') {
63998             return continueTo(addTank);
63999         }
64000
64001         tankId = null;
64002
64003         timeout(function() {
64004             revealTank(tank, t('intro.buildings.start_tank'));
64005
64006             context.map().on('move.intro drawn.intro', function() {
64007                 revealTank(tank, t('intro.buildings.start_tank'), { duration: 0 });
64008             });
64009
64010             context.on('enter.intro', function(mode) {
64011                 if (mode.id !== 'draw-area') return chapter.restart();
64012                 continueTo(continueTank);
64013             });
64014
64015         }, 550);  // after easing
64016
64017         function continueTo(nextStep) {
64018             context.map().on('move.intro drawn.intro', null);
64019             context.on('enter.intro', null);
64020             nextStep();
64021         }
64022     }
64023
64024
64025     function continueTank() {
64026         if (context.mode().id !== 'draw-area') {
64027             return continueTo(addTank);
64028         }
64029
64030         tankId = null;
64031
64032         revealTank(tank, t('intro.buildings.continue_tank'));
64033
64034         context.map().on('move.intro drawn.intro', function() {
64035             revealTank(tank, t('intro.buildings.continue_tank'), { duration: 0 });
64036         });
64037
64038         context.on('enter.intro', function(mode) {
64039             if (mode.id === 'draw-area') {
64040                 return;
64041             } else if (mode.id === 'select') {
64042                 tankId = context.selectedIDs()[0];
64043                 return continueTo(searchPresetTank);
64044             } else {
64045                 return continueTo(addTank);
64046             }
64047         });
64048
64049         function continueTo(nextStep) {
64050             context.map().on('move.intro drawn.intro', null);
64051             context.on('enter.intro', null);
64052             nextStep();
64053         }
64054     }
64055
64056
64057     function searchPresetTank() {
64058         if (!tankId || !context.hasEntity(tankId)) {
64059             return addTank();
64060         }
64061         var ids = context.selectedIDs();
64062         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
64063             context.enter(modeSelect(context, [tankId]));
64064         }
64065
64066         // disallow scrolling
64067         select('.inspector-wrap').on('wheel.intro', eventCancel);
64068
64069         timeout(function() {
64070             // reset pane, in case user somehow happened to change it..
64071             select('.inspector-wrap .panewrap').style('right', '-100%');
64072
64073             select('.preset-search-input')
64074                 .on('keydown.intro', null)
64075                 .on('keyup.intro', checkPresetSearch);
64076
64077             reveal('.preset-search-input',
64078                 t('intro.buildings.search_tank', { preset: tankPreset.name() })
64079             );
64080         }, 400);  // after preset list pane visible..
64081
64082         context.on('enter.intro', function(mode) {
64083             if (!tankId || !context.hasEntity(tankId)) {
64084                 return continueTo(addTank);
64085             }
64086
64087             var ids = context.selectedIDs();
64088             if (mode.id !== 'select' || !ids.length || ids[0] !== tankId) {
64089                 // keep the user's area selected..
64090                 context.enter(modeSelect(context, [tankId]));
64091
64092                 // reset pane, in case user somehow happened to change it..
64093                 select('.inspector-wrap .panewrap').style('right', '-100%');
64094                 // disallow scrolling
64095                 select('.inspector-wrap').on('wheel.intro', eventCancel);
64096
64097                 select('.preset-search-input')
64098                     .on('keydown.intro', null)
64099                     .on('keyup.intro', checkPresetSearch);
64100
64101                 reveal('.preset-search-input',
64102                     t('intro.buildings.search_tank', { preset: tankPreset.name() })
64103                 );
64104
64105                 context.history().on('change.intro', null);
64106             }
64107         });
64108
64109         function checkPresetSearch() {
64110             var first = select('.preset-list-item:first-child');
64111
64112             if (first.classed('preset-man_made-storage_tank')) {
64113                 reveal(first.select('.preset-list-button').node(),
64114                     t('intro.buildings.choose_tank', { preset: tankPreset.name() }),
64115                     { duration: 300 }
64116                 );
64117
64118                 select('.preset-search-input')
64119                     .on('keydown.intro', eventCancel, true)
64120                     .on('keyup.intro', null);
64121
64122                 context.history().on('change.intro', function() {
64123                     continueTo(closeEditorTank);
64124                 });
64125             }
64126         }
64127
64128         function continueTo(nextStep) {
64129             select('.inspector-wrap').on('wheel.intro', null);
64130             context.on('enter.intro', null);
64131             context.history().on('change.intro', null);
64132             select('.preset-search-input').on('keydown.intro keyup.intro', null);
64133             nextStep();
64134         }
64135     }
64136
64137
64138     function closeEditorTank() {
64139         if (!tankId || !context.hasEntity(tankId)) {
64140             return addTank();
64141         }
64142         var ids = context.selectedIDs();
64143         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
64144             context.enter(modeSelect(context, [tankId]));
64145         }
64146
64147         context.history().checkpoint('hasTank');
64148
64149         context.on('exit.intro', function() {
64150             continueTo(rightClickTank);
64151         });
64152
64153         timeout(function() {
64154             reveal('.entity-editor-pane',
64155                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
64156             );
64157         }, 500);
64158
64159         function continueTo(nextStep) {
64160             context.on('exit.intro', null);
64161             nextStep();
64162         }
64163     }
64164
64165
64166     function rightClickTank() {
64167         if (!tankId) return continueTo(addTank);
64168
64169         context.enter(modeBrowse(context));
64170         context.history().reset('hasTank');
64171         context.map().centerEase(tank, 500);
64172
64173         timeout(function() {
64174             context.on('enter.intro', function(mode) {
64175                 if (mode.id !== 'select') return;
64176                 var ids = context.selectedIDs();
64177                 if (ids.length !== 1 || ids[0] !== tankId) return;
64178
64179                 timeout(function() {
64180                     var node = selectMenuItem('circularize').node();
64181                     if (!node) return;
64182                     continueTo(clickCircle);
64183                 }, 300);  // after menu visible
64184             });
64185
64186             revealTank(tank, t('intro.buildings.rightclick_tank'));
64187
64188             context.map().on('move.intro drawn.intro', function() {
64189                 revealTank(tank, t('intro.buildings.rightclick_tank'), { duration: 0 });
64190             });
64191
64192             context.history().on('change.intro', function() {
64193                 continueTo(rightClickTank);
64194             });
64195
64196         }, 600);
64197
64198         function continueTo(nextStep) {
64199             context.on('enter.intro', null);
64200             context.map().on('move.intro drawn.intro', null);
64201             context.history().on('change.intro', null);
64202             nextStep();
64203         }
64204     }
64205
64206
64207     function clickCircle() {
64208         if (!tankId) return chapter.restart();
64209         var entity = context.hasEntity(tankId);
64210         if (!entity) return continueTo(rightClickTank);
64211
64212         var node = selectMenuItem('circularize').node();
64213         if (!node) { return continueTo(rightClickTank); }
64214
64215         var wasChanged = false;
64216         var menuCoords = context.map().mouseCoordinates();
64217
64218         revealEditMenu(menuCoords,
64219             t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') })
64220         );
64221
64222         context.on('enter.intro', function(mode) {
64223             if (mode.id === 'browse') {
64224                 continueTo(rightClickTank);
64225             } else if (mode.id === 'move' || mode.id === 'rotate') {
64226                 continueTo(retryClickCircle);
64227             }
64228         });
64229
64230         context.map().on('move.intro drawn.intro', function() {
64231             var node = selectMenuItem('circularize').node();
64232             if (!wasChanged && !node) { return continueTo(rightClickTank); }
64233
64234             revealEditMenu(menuCoords,
64235                 t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') }),
64236                 { duration: 0 }
64237             );
64238         });
64239
64240         context.history().on('change.intro', function() {
64241             wasChanged = true;
64242             context.history().on('change.intro', null);
64243
64244             // Something changed.  Wait for transition to complete and check undo annotation.
64245             timeout(function() {
64246                 if (context.history().undoAnnotation() === t('operations.circularize.annotation.area')) {
64247                     continueTo(play);
64248                 } else {
64249                     continueTo(retryClickCircle);
64250                 }
64251             }, 500);  // after transitioned actions
64252         });
64253
64254         function continueTo(nextStep) {
64255             context.on('enter.intro', null);
64256             context.map().on('move.intro drawn.intro', null);
64257             context.history().on('change.intro', null);
64258             nextStep();
64259         }
64260     }
64261
64262
64263     function retryClickCircle() {
64264         context.enter(modeBrowse(context));
64265
64266         revealTank(tank, t('intro.buildings.retry_circle'), {
64267             buttonText: t('intro.ok'),
64268             buttonCallback: function() { continueTo(rightClickTank); }
64269         });
64270
64271         function continueTo(nextStep) {
64272             nextStep();
64273         }
64274     }
64275
64276
64277     function play() {
64278         dispatch$$1.call('done');
64279         reveal('#id-container',
64280             t('intro.buildings.play', { next: t('intro.startediting.title') }), {
64281                 tooltipBox: '.intro-nav-wrap .chapter-startEditing',
64282                 buttonText: t('intro.ok'),
64283                 buttonCallback: function() { reveal('#id-container'); }
64284             }
64285         );
64286     }
64287
64288
64289     chapter.enter = function() {
64290         addHouse();
64291     };
64292
64293
64294     chapter.exit = function() {
64295         timeouts.forEach(window.clearTimeout);
64296         context.on('enter.intro exit.intro', null);
64297         context.map().on('move.intro drawn.intro', null);
64298         context.history().on('change.intro', null);
64299         select('.inspector-wrap').on('wheel.intro', null);
64300         select('.preset-search-input').on('keydown.intro keyup.intro', null);
64301         select('.more-fields .combobox-input').on('click.intro', null);
64302     };
64303
64304
64305     chapter.restart = function() {
64306         chapter.exit();
64307         chapter.enter();
64308     };
64309
64310
64311     return utilRebind(chapter, dispatch$$1, 'on');
64312 }
64313
64314 function uiIntroStartEditing(context, reveal) {
64315     var dispatch$$1 = dispatch('done', 'startEditing'),
64316         modalSelection = select(null);
64317
64318
64319     var chapter = {
64320         title: 'intro.startediting.title'
64321     };
64322
64323     function showHelp() {
64324         reveal('.map-control.help-control',
64325             t('intro.startediting.help', { button: icon('#icon-help', 'pre-text'), key: t('help.key') }), {
64326                 buttonText: t('intro.ok'),
64327                 buttonCallback: function() { shortcuts(); }
64328             }
64329         );
64330     }
64331
64332     function shortcuts() {
64333         reveal('.map-control.help-control',
64334             t('intro.startediting.shortcuts', { key: t('shortcuts.toggle.key') }), {
64335                 buttonText: t('intro.ok'),
64336                 buttonCallback: function() { showSave(); }
64337             }
64338         );
64339     }
64340
64341     function showSave() {
64342         selectAll('.shaded').remove();  // in case user opened keyboard shortcuts
64343         reveal('#bar button.save',
64344             t('intro.startediting.save'), {
64345                 buttonText: t('intro.ok'),
64346                 buttonCallback: function() { showStart(); }
64347             }
64348         );
64349     }
64350
64351     function showStart() {
64352         selectAll('.shaded').remove();  // in case user opened keyboard shortcuts
64353
64354         modalSelection = uiModal(context.container());
64355
64356         modalSelection.select('.modal')
64357             .attr('class', 'modal-splash modal col6');
64358
64359         modalSelection.selectAll('.close').remove();
64360
64361         var startbutton = modalSelection.select('.content')
64362             .attr('class', 'fillL')
64363             .append('button')
64364                 .attr('class', 'modal-section huge-modal-button')
64365                 .on('click', function() {
64366                     modalSelection.remove();
64367                 });
64368
64369             startbutton
64370                 .append('svg')
64371                 .attr('class', 'illustration')
64372                 .append('use')
64373                 .attr('xlink:href', '#logo-walkthrough');
64374
64375             startbutton
64376                 .append('h2')
64377                 .text(t('intro.startediting.start'));
64378
64379         dispatch$$1.call('startEditing');
64380     }
64381
64382
64383     chapter.enter = function() {
64384         showHelp();
64385     };
64386
64387
64388     chapter.exit = function() {
64389         modalSelection.remove();
64390         selectAll('.shaded').remove();  // in case user opened keyboard shortcuts
64391     };
64392
64393
64394     return utilRebind(chapter, dispatch$$1, 'on');
64395 }
64396
64397 var chapterUi = {
64398     welcome: uiIntroWelcome,
64399     navigation: uiIntroNavigation,
64400     point: uiIntroPoint,
64401     area: uiIntroArea,
64402     line: uiIntroLine,
64403     building: uiIntroBuilding,
64404     startEditing: uiIntroStartEditing
64405 };
64406
64407 var chapterFlow = [
64408     'welcome',
64409     'navigation',
64410     'point',
64411     'area',
64412     'line',
64413     'building',
64414     'startEditing'
64415 ];
64416
64417
64418 function uiIntro(context) {
64419     var introGraph = {},
64420         currChapter;
64421
64422
64423     // create entities for intro graph and localize names
64424     for (var id in dataIntroGraph) {
64425         introGraph[id] = osmEntity$$1(localize(dataIntroGraph[id]));
64426     }
64427
64428
64429     function intro(selection$$1) {
64430         context.enter(modeBrowse(context));
64431
64432         // Save current map state
64433         var history = context.history().toJSON(),
64434             hash = window.location.hash,
64435             center = context.map().center(),
64436             zoom$$1 = context.map().zoom(),
64437             background = context.background().baseLayerSource(),
64438             overlays = context.background().overlayLayerSources(),
64439             opacity = selectAll('#map .layer-background').style('opacity'),
64440             loadedTiles = context.connection().loadedTiles(),
64441             baseEntities = context.history().graph().base().entities,
64442             countryCode = services.geocoder.countryCode;
64443
64444         // Block saving
64445         context.inIntro(true);
64446
64447         // Load semi-real data used in intro
64448         context.connection().toggle(false).reset();
64449         context.history().reset();
64450         context.history().merge(values(coreGraph$$1().load(introGraph).entities));
64451         context.history().checkpoint('initial');
64452         context.background().bing();
64453         overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
64454
64455         // Mock geocoder
64456         services.geocoder.countryCode = function(location, callback) {
64457             callback(null, t('intro.graph.countrycode'));
64458         };
64459
64460         selectAll('#map .layer-background').style('opacity', 1);
64461
64462         var curtain = uiCurtain();
64463         selection$$1.call(curtain);
64464
64465         var chapters = chapterFlow.map(function(chapter, i) {
64466             var s = chapterUi[chapter](context, curtain.reveal)
64467                 .on('done', function() {
64468                     context.presets().init();  // clear away "recent" presets
64469
64470                     buttons.filter(function(d) {
64471                         return d.title === s.title;
64472                     }).classed('finished', true);
64473
64474                     if (i < chapterFlow.length - 1) {
64475                         var next = chapterFlow[i + 1];
64476                         select('button.chapter-' + next)
64477                             .classed('next', true);
64478                     }
64479                 });
64480             return s;
64481         });
64482
64483         chapters[chapters.length - 1].on('startEditing', function() {
64484             curtain.remove();
64485             navwrap.remove();
64486             selectAll('#map .layer-background').style('opacity', opacity);
64487             context.connection().toggle(true).reset().loadedTiles(loadedTiles);
64488             context.history().reset().merge(values(baseEntities));
64489             context.background().baseLayerSource(background);
64490             overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
64491             if (history) context.history().fromJSON(history, false);
64492             context.map().centerZoom(center, zoom$$1);
64493             window.location.replace(hash);
64494             services.geocoder.countryCode = countryCode;
64495             context.inIntro(false);
64496         });
64497
64498         var navwrap = selection$$1
64499             .append('div')
64500             .attr('class', 'intro-nav-wrap fillD');
64501
64502         navwrap
64503             .append('svg')
64504             .attr('class', 'intro-nav-wrap-logo')
64505             .append('use')
64506             .attr('xlink:href', '#logo-walkthrough');
64507
64508         var buttonwrap = navwrap
64509             .append('div')
64510             .attr('class', 'joined')
64511             .selectAll('button.chapter');
64512
64513         var buttons = buttonwrap
64514             .data(chapters)
64515             .enter()
64516             .append('button')
64517             .attr('class', function(d, i) { return 'chapter chapter-' + chapterFlow[i]; })
64518             .on('click', enterChapter);
64519
64520         buttons
64521             .append('span')
64522             .text(function(d) { return t(d.title); });
64523
64524         buttons
64525             .append('span')
64526             .attr('class', 'status')
64527             .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'));
64528
64529         enterChapter(chapters[0]);
64530
64531
64532         function enterChapter(newChapter) {
64533             if (currChapter) { currChapter.exit(); }
64534             context.enter(modeBrowse(context));
64535
64536             currChapter = newChapter;
64537             currChapter.enter();
64538
64539             buttons
64540                 .classed('next', false)
64541                 .classed('active', function(d) {
64542                     return d.title === currChapter.title;
64543                 });
64544         }
64545     }
64546
64547
64548     return intro;
64549 }
64550
64551 function uiShortcuts() {
64552     var detected = utilDetect();
64553     var activeTab = 0;
64554     var modalSelection;
64555     var savedSelection;
64556
64557
64558     var keybinding = d3keybinding('shortcuts')
64559         .on(t('shortcuts.toggle.key'), function () {
64560             if (selectAll('.modal-shortcuts').size()) {  // already showing
64561                 if (modalSelection) {
64562                     modalSelection.close();
64563                     modalSelection = null;
64564                 }
64565             } else {
64566                 modalSelection = uiModal(savedSelection);
64567                 shortcutsModal(modalSelection);
64568             }
64569         });
64570
64571     select(document)
64572         .call(keybinding);
64573
64574
64575
64576     function shortcutsModal(modalSelection) {
64577         modalSelection.select('.modal')
64578             .classed('modal-shortcuts', true);
64579
64580         var shortcutsModal = modalSelection.select('.content');
64581
64582         shortcutsModal
64583             .append('div')
64584             .attr('class', 'modal-section')
64585             .append('h3')
64586             .text(t('shortcuts.title'));
64587
64588         shortcutsModal
64589             .call(render);
64590     }
64591
64592
64593     function render(selection$$1) {
64594         var wrapper = selection$$1
64595             .selectAll('.wrapper')
64596             .data([0]);
64597
64598         var wrapperEnter = wrapper
64599             .enter()
64600             .append('div')
64601             .attr('class', 'wrapper modal-section');
64602
64603         var tabsBar = wrapperEnter
64604             .append('div')
64605             .attr('class', 'tabs-bar');
64606
64607         var shortcutsList = wrapperEnter
64608             .append('div')
64609             .attr('class', 'shortcuts-list');
64610
64611         wrapper = wrapper.merge(wrapperEnter);
64612
64613         var tabs = tabsBar
64614             .selectAll('.tab')
64615             .data(dataShortcuts);
64616
64617         var tabsEnter = tabs
64618             .enter()
64619             .append('div')
64620             .attr('class', 'tab')
64621             .on('click', function (d, i) {
64622                 activeTab = i;
64623                 render(selection$$1);
64624             });
64625
64626         tabsEnter
64627             .append('span')
64628             .text(function (d) { return t(d.text); });
64629
64630         tabs = tabs
64631             .merge(tabsEnter);
64632
64633         // Update
64634         wrapper.selectAll('.tab')
64635             .classed('active', function (d, i) {
64636                 return i === activeTab;
64637             });
64638
64639
64640         var shortcuts = shortcutsList
64641             .selectAll('.shortcut-tab')
64642             .data(dataShortcuts);
64643
64644         var shortcutsEnter = shortcuts
64645             .enter()
64646             .append('div')
64647             .attr('class', function(d) { return 'shortcut-tab shortcut-tab-' + d.tab; });
64648
64649         var columnsEnter = shortcutsEnter
64650             .selectAll('.shortcut-column')
64651             .data(function (d) { return d.columns; })
64652             .enter()
64653             .append('table')
64654             .attr('class', 'shortcut-column');
64655
64656         var rowsEnter = columnsEnter
64657             .selectAll('.shortcut-row')
64658             .data(function (d) { return d.rows; })
64659             .enter()
64660             .append('tr')
64661             .attr('class', 'shortcut-row');
64662
64663
64664         var sectionRows = rowsEnter
64665             .filter(function (d) { return !d.shortcuts; });
64666
64667         sectionRows
64668             .append('td');
64669
64670         sectionRows
64671             .append('td')
64672             .attr('class', 'shortcut-section')
64673             .append('h3')
64674             .text(function (d) { return t(d.text); });
64675
64676
64677         var shortcutRows = rowsEnter
64678             .filter(function (d) { return d.shortcuts; });
64679
64680         var shortcutKeys = shortcutRows
64681             .append('td')
64682             .attr('class', 'shortcut-keys');
64683
64684         var modifierKeys = shortcutKeys
64685             .filter(function (d) { return d.modifiers; });
64686
64687         modifierKeys
64688             .selectAll('kbd.modifier')
64689             .data(function (d) {
64690                 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
64691                     return ['⌘'];
64692                 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
64693                     return [];
64694                 } else {
64695                     return d.modifiers;
64696                 }
64697             })
64698             .enter()
64699             .each(function () {
64700                 var selection$$1 = select(this);
64701
64702                 selection$$1
64703                     .append('kbd')
64704                     .attr('class', 'modifier')
64705                     .text(function (d) { return uiCmd.display(d); });
64706
64707                 selection$$1
64708                     .append('span')
64709                     .text('+');
64710             });
64711
64712
64713         shortcutKeys
64714             .selectAll('kbd.shortcut')
64715             .data(function (d) {
64716                 var arr = d.shortcuts;
64717                 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
64718                     arr = ['Y'];
64719                 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
64720                     arr = ['F11'];
64721                 }
64722
64723                 return arr.map(function(s) {
64724                     return {
64725                         shortcut: s,
64726                         separator: d.separator
64727                     };
64728                 });
64729             })
64730             .enter()
64731             .each(function (d, i, nodes) {
64732                 var selection$$1 = select(this);
64733                 var click = d.shortcut.toLowerCase().match(/(.*).click/);
64734
64735                 if (click && click[1]) {
64736                     selection$$1
64737                         .call(svgIcon('#walkthrough-mouse', 'mouseclick', click[1]));
64738                 } else {
64739                     selection$$1
64740                         .append('kbd')
64741                         .attr('class', 'shortcut')
64742                         .text(function (d) {
64743                             var key = d.shortcut;
64744                             return key.indexOf('.') !== -1 ? uiCmd.display(t(key)) : uiCmd.display(key);
64745                         });
64746                 }
64747
64748                 if (i < nodes.length - 1) {
64749                     selection$$1
64750                         .append('span')
64751                         .text(d.separator || '\u00a0' + t('shortcuts.or') + '\u00a0');
64752                 }
64753             });
64754
64755
64756         shortcutKeys
64757             .filter(function(d) { return d.gesture; })
64758             .each(function () {
64759                 var selection$$1 = select(this);
64760
64761                 selection$$1
64762                     .append('span')
64763                     .text('+');
64764
64765                 selection$$1
64766                     .append('span')
64767                     .attr('class', 'gesture')
64768                     .text(function (d) { return t(d.gesture); });
64769             });
64770
64771
64772         shortcutRows
64773             .append('td')
64774             .attr('class', 'shortcut-desc')
64775             .text(function (d) { return d.text ? t(d.text) : '\u00a0'; });
64776
64777
64778         shortcuts = shortcuts
64779             .merge(shortcutsEnter);
64780
64781         // Update
64782         wrapper.selectAll('.shortcut-tab')
64783             .style('display', function (d, i) {
64784                 return i === activeTab ? 'flex' : 'none';
64785             });
64786     }
64787
64788
64789     return function(selection$$1, show) {
64790         savedSelection = selection$$1;
64791         if (show) {
64792             modalSelection = uiModal(selection$$1);
64793             shortcutsModal(modalSelection);
64794         }
64795     };
64796 }
64797
64798 function uiHelp(context) {
64799     var key = t('help.key');
64800
64801     var docKeys = [
64802         'help.help',
64803         'help.editing_saving',
64804         'help.roads',
64805         'help.gps',
64806         'help.imagery',
64807         'help.addresses',
64808         'help.inspector',
64809         'help.buildings',
64810         'help.relations'];
64811
64812     var docs = docKeys.map(function(key) {
64813         var text$$1 = t(key);
64814         return {
64815             title: text$$1.split('\n')[0].replace('#', '').trim(),
64816             html: marked(text$$1.split('\n').slice(1).join('\n'))
64817         };
64818     });
64819
64820
64821     function help(selection$$1) {
64822
64823         function hide() {
64824             setVisible(false);
64825         }
64826
64827
64828         function toggle() {
64829             if (event) event.preventDefault();
64830             tooltipBehavior.hide(button);
64831             setVisible(!button.classed('active'));
64832         }
64833
64834
64835         function setVisible(show) {
64836             if (show !== shown) {
64837                 button.classed('active', show);
64838                 shown = show;
64839
64840                 if (show) {
64841                     selection$$1.on('mousedown.help-inside', function() {
64842                         return event.stopPropagation();
64843                     });
64844                     pane.style('display', 'block')
64845                         .style('right', '-500px')
64846                         .transition()
64847                         .duration(200)
64848                         .style('right', '0px');
64849                 } else {
64850                     pane.style('right', '0px')
64851                         .transition()
64852                         .duration(200)
64853                         .style('right', '-500px')
64854                         .on('end', function() {
64855                             select(this).style('display', 'none');
64856                         });
64857                     selection$$1.on('mousedown.help-inside', null);
64858                 }
64859             }
64860         }
64861
64862
64863         function clickHelp(d, i) {
64864             var rtl = (textDirection === 'rtl');
64865             pane.property('scrollTop', 0);
64866             doctitle.html(d.title);
64867
64868             body.html(d.html);
64869             body.selectAll('a')
64870                 .attr('target', '_blank');
64871             menuItems.classed('selected', function(m) {
64872                 return m.title === d.title;
64873             });
64874
64875             nav.html('');
64876             if (rtl) {
64877                 nav.call(drawNext).call(drawPrevious);
64878             } else {
64879                 nav.call(drawPrevious).call(drawNext);
64880             }
64881
64882
64883             function drawNext(selection$$1) {
64884                 if (i < docs.length - 1) {
64885                     var nextLink = selection$$1
64886                         .append('a')
64887                         .attr('class', 'next')
64888                         .on('click', function() {
64889                             clickHelp(docs[i + 1], i + 1);
64890                         });
64891
64892                     nextLink
64893                         .append('span')
64894                         .text(docs[i + 1].title)
64895                         .call(svgIcon((rtl ? '#icon-backward' : '#icon-forward'), 'inline'));
64896                 }
64897             }
64898
64899
64900             function drawPrevious(selection$$1) {
64901                 if (i > 0) {
64902                     var prevLink = selection$$1
64903                         .append('a')
64904                         .attr('class', 'previous')
64905                         .on('click', function() {
64906                             clickHelp(docs[i - 1], i - 1);
64907                         });
64908
64909                     prevLink
64910                         .call(svgIcon((rtl ? '#icon-forward' : '#icon-backward'), 'inline'))
64911                         .append('span')
64912                         .text(docs[i - 1].title);
64913                 }
64914             }
64915         }
64916
64917
64918         function clickWalkthrough() {
64919             if (context.inIntro()) return;
64920             context.container().call(uiIntro(context));
64921             setVisible(false);
64922         }
64923
64924
64925         function clickShortcuts() {
64926             context.container().call(uiShortcuts(context), true);
64927         }
64928
64929
64930         var pane = selection$$1.append('div')
64931                 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
64932             tooltipBehavior = tooltip()
64933                 .placement((textDirection === 'rtl') ? 'right' : 'left')
64934                 .html(true)
64935                 .title(uiTooltipHtml(t('help.title'), key)),
64936             button = selection$$1.append('button')
64937                 .attr('tabindex', -1)
64938                 .on('click', toggle)
64939                 .call(svgIcon('#icon-help', 'light'))
64940                 .call(tooltipBehavior),
64941             shown = false;
64942
64943
64944         var toc = pane.append('ul')
64945             .attr('class', 'toc');
64946
64947         var menuItems = toc.selectAll('li')
64948             .data(docs)
64949             .enter()
64950             .append('li')
64951             .append('a')
64952             .html(function(d) { return d.title; })
64953             .on('click', clickHelp);
64954
64955         var shortcuts = toc
64956             .append('li')
64957             .attr('class', 'shortcuts')
64958             .call(tooltip()
64959                 .html(true)
64960                 .title(uiTooltipHtml(t('shortcuts.tooltip'), '?'))
64961                 .placement('top')
64962             )
64963             .append('a')
64964             .on('click', clickShortcuts);
64965
64966         shortcuts
64967             .append('div')
64968             .text(t('shortcuts.title'));
64969
64970         var walkthrough = toc
64971             .append('li')
64972             .attr('class', 'walkthrough')
64973             .append('a')
64974             .on('click', clickWalkthrough);
64975
64976         walkthrough
64977             .append('svg')
64978             .attr('class', 'logo logo-walkthrough')
64979             .append('use')
64980             .attr('xlink:href', '#logo-walkthrough');
64981
64982         walkthrough
64983             .append('div')
64984             .text(t('splash.walkthrough'));
64985
64986
64987         var content = pane.append('div')
64988             .attr('class', 'left-content');
64989
64990         var doctitle = content.append('h2')
64991             .text(t('help.title'));
64992
64993         var body = content.append('div')
64994             .attr('class', 'body');
64995
64996         var nav = content.append('div')
64997             .attr('class', 'nav');
64998
64999         clickHelp(docs[0], 0);
65000
65001         var keybinding = d3keybinding('help')
65002             .on(key, toggle)
65003             .on([t('background.key'), t('map_data.key')], hide);
65004
65005         select(document)
65006             .call(keybinding);
65007
65008         context.surface().on('mousedown.help-outside', hide);
65009         context.container().on('mousedown.help-outside', hide);
65010     }
65011
65012     return help;
65013 }
65014
65015 function uiPanelBackground(context) {
65016     var background = context.background();
65017     var currSource = null;
65018     var currZoom = '';
65019     var currVintage = '';
65020
65021
65022     function redraw(selection$$1) {
65023         if (currSource !== background.baseLayerSource().name()) {
65024             currSource = background.baseLayerSource().name();
65025             currZoom = '';
65026             currVintage = '';
65027         }
65028
65029         selection$$1.html('');
65030
65031         var list = selection$$1
65032             .append('ul')
65033             .attr('class', 'background-info');
65034
65035         list
65036             .append('li')
65037             .text(currSource);
65038
65039         list
65040             .append('li')
65041             .text(t('info_panels.background.zoom') + ': ')
65042             .append('span')
65043             .attr('class', 'zoom')
65044             .text(currZoom);
65045
65046         list
65047             .append('li')
65048             .text(t('info_panels.background.vintage') + ': ')
65049             .append('span')
65050             .attr('class', 'vintage')
65051             .text(currVintage);
65052
65053         if (!currVintage) {
65054             debouncedGetVintage(selection$$1);
65055         }
65056
65057         var toggle = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
65058
65059         selection$$1
65060             .append('a')
65061             .text(t('info_panels.background.' + toggle))
65062             .attr('href', '#')
65063             .attr('class', 'button button-toggle-tiles')
65064             .on('click', function() {
65065                 event.preventDefault();
65066                 context.setDebug('tile', !context.getDebug('tile'));
65067                 selection$$1.call(redraw);
65068             });
65069     }
65070
65071
65072     var debouncedGetVintage = lodash.debounce(getVintage, 250);
65073     function getVintage(selection$$1) {
65074         var tile = select('.layer-background img.tile-center');   // tile near viewport center
65075         if (tile.empty()) return;
65076
65077         var d = tile.datum(),
65078             zoom$$1 = (d && d.length >= 3 && d[2]) || Math.floor(context.map().zoom()),
65079             center = context.map().center();
65080
65081         currZoom = String(zoom$$1);
65082         selection$$1.selectAll('.zoom')
65083             .text(currZoom);
65084
65085         if (!d || !d.length >= 3) return;
65086         background.baseLayerSource().getVintage(center, d, function(err, result) {
65087             currVintage = (result && result.range) || t('info_panels.background.unknown');
65088             selection$$1.selectAll('.vintage')
65089                 .text(currVintage);
65090         });
65091     }
65092
65093
65094     var panel = function(selection$$1) {
65095         selection$$1.call(redraw);
65096
65097         context.map()
65098             .on('drawn.info-background', function() {
65099                 selection$$1.call(redraw);
65100             })
65101             .on('move.info-background', function() {
65102                 selection$$1.call(debouncedGetVintage);
65103             });
65104
65105     };
65106
65107     panel.off = function() {
65108         context.map()
65109             .on('drawn.info-background', null)
65110             .on('move.info-background', null);
65111     };
65112
65113     panel.id = 'background';
65114     panel.title = t('info_panels.background.title');
65115     panel.key = t('info_panels.background.key');
65116
65117
65118     return panel;
65119 }
65120
65121 function uiPanelHistory(context) {
65122
65123
65124     function displayTimestamp(entity) {
65125         if (!entity.timestamp) return t('info_panels.history.unknown');
65126
65127         var d = new Date(entity.timestamp);
65128         if (isNaN(d.getTime())) return t('info_panels.history.unknown');
65129
65130         return d.toLocaleString();
65131     }
65132
65133
65134     function displayUser(selection, entity) {
65135         if (!entity.user) {
65136             selection
65137                 .append('span')
65138                 .text(t('info_panels.history.unknown'));
65139             return;
65140         }
65141
65142         selection
65143             .append('span')
65144             .attr('class', 'user-name')
65145             .text(entity.user);
65146
65147         var links = selection
65148             .append('div')
65149             .attr('class', 'links');
65150
65151         links
65152             .append('a')
65153             .attr('class', 'user-osm-link')
65154             .attr('href', context.connection().userURL(entity.user))
65155             .attr('target', '_blank')
65156             .attr('tabindex', -1)
65157             .text('OSM');
65158
65159         links
65160             .append('a')
65161             .attr('class', 'user-hdyc-link')
65162             .attr('href', 'https://hdyc.neis-one.org/?' + entity.user)
65163             .attr('target', '_blank')
65164             .attr('tabindex', -1)
65165             .text('HDYC');
65166     }
65167
65168
65169     function displayChangeset(selection, entity) {
65170         if (!entity.changeset) {
65171             selection
65172                 .append('span')
65173                 .text(t('info_panels.history.unknown'));
65174             return;
65175         }
65176
65177         selection
65178             .append('span')
65179             .attr('class', 'changeset-id')
65180             .text(entity.changeset);
65181
65182         var links = selection
65183             .append('div')
65184             .attr('class', 'links');
65185
65186         links
65187             .append('a')
65188             .attr('class', 'changeset-osm-link')
65189             .attr('href', context.connection().changesetURL(entity.changeset))
65190             .attr('target', '_blank')
65191             .attr('tabindex', -1)
65192             .text('OSM');
65193
65194         links
65195             .append('a')
65196             .attr('class', 'changeset-osmcha-link')
65197             .attr('href', 'https://osmcha.mapbox.com/changesets/' + entity.changeset)
65198             .attr('target', '_blank')
65199             .attr('tabindex', -1)
65200             .text('OSMCha');
65201     }
65202
65203
65204     function redraw(selection) {
65205         var selected = lodash.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
65206             singular = selected.length === 1 ? selected[0] : null;
65207
65208         selection.html('');
65209
65210         selection
65211             .append('h4')
65212             .attr('class', 'history-heading')
65213             .text(singular || t('info_panels.history.selected', { n: selected.length }));
65214
65215         if (!singular) return;
65216
65217         var entity = context.entity(singular);
65218
65219         var list = selection
65220             .append('ul');
65221
65222         list
65223             .append('li')
65224             .text(t('info_panels.history.version') + ': ' + entity.version);
65225
65226         list
65227             .append('li')
65228             .text(t('info_panels.history.last_edit') + ': ' + displayTimestamp(entity));
65229
65230         list
65231             .append('li')
65232             .text(t('info_panels.history.edited_by') + ': ')
65233             .call(displayUser, entity);
65234
65235         list
65236             .append('li')
65237             .text(t('info_panels.history.changeset') + ': ')
65238             .call(displayChangeset, entity);
65239
65240         selection
65241             .append('a')
65242             .attr('class', 'view-history-on-osm')
65243             .attr('target', '_blank')
65244             .attr('tabindex', -1)
65245             .attr('href', context.connection().historyURL(entity))
65246             .call(svgIcon('#icon-out-link', 'inline'))
65247             .append('span')
65248             .text(t('info_panels.history.link_text'));
65249     }
65250
65251
65252     var panel = function(selection) {
65253         selection.call(redraw);
65254
65255         context.map()
65256             .on('drawn.info-history', function() {
65257                 selection.call(redraw);
65258             });
65259     };
65260
65261     panel.off = function() {
65262         context.map()
65263             .on('drawn.info-history', null);
65264     };
65265
65266     panel.id = 'history';
65267     panel.title = t('info_panels.history.title');
65268     panel.key = t('info_panels.history.key');
65269
65270
65271     return panel;
65272 }
65273
65274 function uiPanelLocation(context) {
65275     var currLocation = '';
65276     var OSM_PRECISION = 7;
65277
65278
65279     function wrap(x, min, max) {
65280         var d = max - min;
65281         return ((x - min) % d + d) % d + min;
65282     }
65283
65284
65285     function clamp(x, min, max) {
65286         return Math.max(min, Math.min(x, max));
65287     }
65288
65289
65290     function redraw(selection) {
65291         selection.html('');
65292
65293         var list = selection
65294             .append('ul');
65295
65296         // Mouse coordinates
65297         var coord = context.map().mouseCoordinates();
65298         if (coord.some(isNaN)) {
65299             coord = context.map().center();
65300         }
65301
65302         var coordStr =
65303             clamp(coord[1], -90, 90).toFixed(OSM_PRECISION) + ', ' +
65304             wrap(coord[0], -180, 180).toFixed(OSM_PRECISION);
65305
65306         list
65307             .append('li')
65308             .text(coordStr);
65309
65310         // Location Info
65311         selection
65312             .append('div')
65313             .attr('class', 'location-info')
65314             .text(currLocation || ' ');
65315
65316         debouncedGetLocation(selection, coord);
65317     }
65318
65319
65320     var debouncedGetLocation = lodash.debounce(getLocation, 250);
65321     function getLocation(selection, coord) {
65322         if (!services.geocoder) {
65323             currLocation = t('info_panels.location.unknown_location');
65324             selection.selectAll('.location-info')
65325                 .text(currLocation);
65326         } else {
65327             services.geocoder.reverse(coord, function(err, result) {
65328                 currLocation = result ? result.display_name : t('info_panels.location.unknown_location');
65329                 selection.selectAll('.location-info')
65330                     .text(currLocation);
65331             });
65332         }
65333     }
65334
65335
65336     var panel = function(selection) {
65337         selection.call(redraw);
65338
65339         context.surface()
65340             .on('mousemove.info-location', function() {
65341                 selection.call(redraw);
65342             });
65343     };
65344
65345     panel.off = function() {
65346         context.surface()
65347             .on('mousemove.info-location', null);
65348     };
65349
65350     panel.id = 'location';
65351     panel.title = t('info_panels.location.title');
65352     panel.key = t('info_panels.location.key');
65353
65354
65355     return panel;
65356 }
65357
65358 function uiPanelMeasurement(context) {
65359     var isImperial = (utilDetect().locale.toLowerCase() === 'en-us');
65360     var OSM_PRECISION = 7;
65361
65362
65363     function radiansToMeters(r) {
65364         // using WGS84 authalic radius (6371007.1809 m)
65365         return r * 6371007.1809;
65366     }
65367
65368     function steradiansToSqmeters(r) {
65369         // http://gis.stackexchange.com/a/124857/40446
65370         return r / (4 * Math.PI) * 510065621724000;
65371     }
65372
65373
65374     function toLineString(feature) {
65375         if (feature.type === 'LineString') return feature;
65376
65377         var result = { type: 'LineString', coordinates: [] };
65378         if (feature.type === 'Polygon') {
65379             result.coordinates = feature.coordinates[0];
65380         } else if (feature.type === 'MultiPolygon') {
65381             result.coordinates = feature.coordinates[0][0];
65382         }
65383
65384         return result;
65385     }
65386
65387
65388     function displayLength(m) {
65389         var d = m * (isImperial ? 3.28084 : 1),
65390             p, unit;
65391
65392         if (isImperial) {
65393             if (d >= 5280) {
65394                 d /= 5280;
65395                 unit = 'mi';
65396             } else {
65397                 unit = 'ft';
65398             }
65399         } else {
65400             if (d >= 1000) {
65401                 d /= 1000;
65402                 unit = 'km';
65403             } else {
65404                 unit = 'm';
65405             }
65406         }
65407
65408         // drop unnecessary precision
65409         p = d > 1000 ? 0 : d > 100 ? 1 : 2;
65410
65411         return String(d.toFixed(p)) + ' ' + unit;
65412     }
65413
65414
65415     function displayArea(m2) {
65416         var d = m2 * (isImperial ? 10.7639111056 : 1),
65417             d1, d2, p1, p2, unit1, unit2;
65418
65419         if (isImperial) {
65420             if (d >= 6969600) {     // > 0.25mi² show mi²
65421                 d1 = d / 27878400;
65422                 unit1 = 'mi²';
65423             } else {
65424                 d1 = d;
65425                 unit1 = 'ft²';
65426             }
65427
65428             if (d > 4356 && d < 43560000) {   // 0.1 - 1000 acres
65429                 d2 = d / 43560;
65430                 unit2 = 'ac';
65431             }
65432
65433         } else {
65434             if (d >= 250000) {    // > 0.25km² show km²
65435                 d1 = d / 1000000;
65436                 unit1 = 'km²';
65437             } else {
65438                 d1 = d;
65439                 unit1 = 'm²';
65440             }
65441
65442             if (d > 1000 && d < 10000000) {   // 0.1 - 1000 hectares
65443                 d2 = d / 10000;
65444                 unit2 = 'ha';
65445             }
65446         }
65447
65448         // drop unnecessary precision
65449         p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
65450         p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
65451
65452         return String(d1.toFixed(p1)) + ' ' + unit1 +
65453             (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
65454     }
65455
65456
65457     function redraw(selection$$1) {
65458         var resolver = context.graph(),
65459             selected = lodash.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
65460             singular = selected.length === 1 ? selected[0] : null,
65461             extent$$1 = geoExtent$$1(),
65462             entity;
65463
65464         selection$$1.html('');
65465
65466         selection$$1
65467             .append('h4')
65468             .attr('class', 'measurement-heading')
65469             .text(singular || t('info_panels.measurement.selected', { n: selected.length }));
65470
65471         if (!selected.length) return;
65472
65473         var center;
65474         for (var i = 0; i < selected.length; i++) {
65475             entity = context.entity(selected[i]);
65476             extent$$1._extend(entity.extent(resolver));
65477         }
65478         center = extent$$1.center();
65479
65480
65481         var list = selection$$1
65482             .append('ul');
65483
65484         // multiple features, just display extent center..
65485         if (!singular) {
65486             list
65487                 .append('li')
65488                 .text(t('info_panels.measurement.center') + ': ' +
65489                     center[1].toFixed(OSM_PRECISION) + ', ' + center[0].toFixed(OSM_PRECISION)
65490                 );
65491             return;
65492         }
65493
65494         // single feature, display details..
65495         if (!entity) return;
65496         var geometry = entity.geometry(resolver);
65497
65498         if (geometry === 'line' || geometry === 'area') {
65499             var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
65500                 feature = entity.asGeoJSON(resolver),
65501                 length = radiansToMeters(d3GeoLength(toLineString(feature))),
65502                 lengthLabel = t('info_panels.measurement.' + (closed ? 'perimeter' : 'length')),
65503                 centroid = d3GeoCentroid(feature);
65504
65505             list
65506                 .append('li')
65507                 .text(t('info_panels.measurement.geometry') + ': ' +
65508                     (closed ? t('info_panels.measurement.closed') + ' ' : '') + t('geometry.' + geometry) );
65509
65510             if (closed) {
65511                 var area$$1 = steradiansToSqmeters(entity.area(resolver));
65512                 list
65513                     .append('li')
65514                     .text(t('info_panels.measurement.area') + ': ' + displayArea(area$$1));
65515             }
65516
65517             list
65518                 .append('li')
65519                 .text(lengthLabel + ': ' + displayLength(length));
65520
65521             list
65522                 .append('li')
65523                 .text(t('info_panels.measurement.centroid') + ': ' +
65524                     centroid[1].toFixed(OSM_PRECISION) + ', ' + centroid[0].toFixed(OSM_PRECISION)
65525                 );
65526
65527
65528             var toggle  = isImperial ? 'imperial' : 'metric';
65529
65530             selection$$1
65531                 .append('a')
65532                 .text(t('info_panels.measurement.' + toggle))
65533                 .attr('href', '#')
65534                 .attr('class', 'button button-toggle-units')
65535                 .on('click', function() {
65536                     event.preventDefault();
65537                     isImperial = !isImperial;
65538                     selection$$1.call(redraw);
65539                 });
65540
65541         } else {
65542             var centerLabel = t('info_panels.measurement.' + (entity.type === 'node' ? 'location' : 'center'));
65543
65544             list
65545                 .append('li')
65546                 .text(t('info_panels.measurement.geometry') + ': ' + t('geometry.' + geometry));
65547
65548             list
65549                 .append('li')
65550                 .text(centerLabel + ': ' +
65551                     center[1].toFixed(OSM_PRECISION) + ', ' + center[0].toFixed(OSM_PRECISION)
65552                 );
65553         }
65554     }
65555
65556
65557     var panel = function(selection$$1) {
65558         selection$$1.call(redraw);
65559
65560         context.map()
65561             .on('drawn.info-measurement', function() {
65562                 selection$$1.call(redraw);
65563             });
65564     };
65565
65566     panel.off = function() {
65567         context.map()
65568             .on('drawn.info-measurement', null);
65569     };
65570
65571     panel.id = 'measurement';
65572     panel.title = t('info_panels.measurement.title');
65573     panel.key = t('info_panels.measurement.key');
65574
65575
65576     return panel;
65577 }
65578
65579 var uiInfoPanels = {
65580     background: uiPanelBackground,
65581     history: uiPanelHistory,
65582     location: uiPanelLocation,
65583     measurement: uiPanelMeasurement,
65584 };
65585
65586 function uiInfo(context) {
65587     var ids = Object.keys(uiInfoPanels),
65588         wasActive = ['measurement'],
65589         panels = {},
65590         active$$1 = {};
65591
65592     // create panels
65593     ids.forEach(function(k) {
65594         if (!panels[k]) {
65595             panels[k] = uiInfoPanels[k](context);
65596             active$$1[k] = false;
65597         }
65598     });
65599
65600
65601     function info(selection$$1) {
65602
65603         function redraw() {
65604             var activeids = ids.filter(function(k) { return active$$1[k]; }).sort();
65605
65606             var containers = infoPanels.selectAll('.panel-container')
65607                 .data(activeids, function(k) { return k; });
65608
65609             containers.exit()
65610                 .style('opacity', 1)
65611                 .transition()
65612                 .duration(200)
65613                 .style('opacity', 0)
65614                 .on('end', function(d) {
65615                     select(this)
65616                         .call(panels[d].off)
65617                         .remove();
65618                 });
65619
65620             var enter = containers.enter()
65621                 .append('div')
65622                 .attr('class', function(d) { return 'fillD2 panel-container panel-container-' + d; });
65623
65624             enter
65625                 .style('opacity', 0)
65626                 .transition()
65627                 .duration(200)
65628                 .style('opacity', 1);
65629
65630             var title = enter
65631                 .append('div')
65632                 .attr('class', 'panel-title fillD2');
65633
65634             title
65635                 .append('h3')
65636                 .text(function(d) { return panels[d].title; });
65637
65638             title
65639                 .append('button')
65640                 .attr('class', 'close')
65641                 .on('click', function (d) { toggle(d); })
65642                 .call(svgIcon('#icon-close'));
65643
65644             enter
65645                 .append('div')
65646                 .attr('class', function(d) { return 'panel-content panel-content-' + d; });
65647
65648
65649             // redraw the panels
65650             infoPanels.selectAll('.panel-content')
65651                 .each(function(d) {
65652                     select(this).call(panels[d]);
65653                 });
65654         }
65655
65656
65657         function toggle(which) {
65658             if (event) {
65659                 event.stopImmediatePropagation();
65660                 event.preventDefault();
65661             }
65662
65663             var activeids = ids.filter(function(k) { return active$$1[k]; });
65664
65665             if (which) {  // toggle one
65666                 active$$1[which] = !active$$1[which];
65667                 if (activeids.length === 1 && activeids[0] === which) {  // none active anymore
65668                     wasActive = [which];
65669                 }
65670             } else {      // toggle all
65671                 if (activeids.length) {
65672                     wasActive = activeids;
65673                     activeids.forEach(function(k) { active$$1[k] = false; });
65674                 } else {
65675                     wasActive.forEach(function(k) { active$$1[k] = true; });
65676                 }
65677             }
65678
65679             redraw();
65680         }
65681
65682
65683         var infoPanels = selection$$1.selectAll('.info-panels')
65684             .data([0]);
65685
65686         infoPanels = infoPanels.enter()
65687             .append('div')
65688             .attr('class', 'info-panels')
65689             .merge(infoPanels);
65690
65691         redraw();
65692
65693         var keybinding = d3keybinding('info')
65694             .on(uiCmd('⌘' + t('info_panels.key')), toggle);
65695
65696         ids.forEach(function(k) {
65697             var key = t('info_panels.' + k + '.key', { default: null });
65698             if (!key) return;
65699             keybinding
65700                 .on(uiCmd('⌘⇧' + key), function() { toggle(k); });
65701         });
65702
65703         select(document)
65704             .call(keybinding);
65705     }
65706
65707     return info;
65708 }
65709
65710 function uiMapData(context) {
65711     var key = t('map_data.key'),
65712         features = context.features().keys(),
65713         layers = context.layers(),
65714         fills = ['wireframe', 'partial', 'full'],
65715         fillDefault = context.storage('area-fill') || 'partial',
65716         fillSelected = fillDefault;
65717
65718
65719     function map_data(selection$$1) {
65720
65721         function showsFeature(d) {
65722             return context.features().enabled(d);
65723         }
65724
65725
65726         function autoHiddenFeature(d) {
65727             return context.features().autoHidden(d);
65728         }
65729
65730
65731         function clickFeature(d) {
65732             context.features().toggle(d);
65733             update();
65734         }
65735
65736
65737         function showsFill(d) {
65738             return fillSelected === d;
65739         }
65740
65741
65742         function setFill(d) {
65743             lodash.each(fills, function(opt) {
65744                 context.surface().classed('fill-' + opt, Boolean(opt === d));
65745             });
65746
65747             fillSelected = d;
65748             if (d !== 'wireframe') {
65749                 fillDefault = d;
65750                 context.storage('area-fill', d);
65751             }
65752             update();
65753         }
65754
65755
65756         function showsLayer(which) {
65757             var layer = layers.layer(which);
65758             if (layer) {
65759                 return layer.enabled();
65760             }
65761             return false;
65762         }
65763
65764
65765         function setLayer(which, enabled) {
65766             var layer = layers.layer(which);
65767             if (layer) {
65768                 layer.enabled(enabled);
65769                 update();
65770             }
65771         }
65772
65773
65774         function toggleLayer(which) {
65775             setLayer(which, !showsLayer(which));
65776         }
65777
65778
65779         function clickGpx() {
65780             toggleLayer('gpx');
65781         }
65782
65783
65784         function clickMapillaryImages() {
65785             toggleLayer('mapillary-images');
65786             if (!showsLayer('mapillary-images')) {
65787                 setLayer('mapillary-signs', false);
65788             }
65789         }
65790
65791
65792         function clickMapillarySigns() {
65793             toggleLayer('mapillary-signs');
65794         }
65795
65796
65797         function drawMapillaryItems(selection$$1) {
65798             var mapillaryImages = layers.layer('mapillary-images'),
65799                 mapillarySigns = layers.layer('mapillary-signs'),
65800                 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
65801                 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
65802                 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
65803                 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
65804
65805             var mapillaryList = selection$$1
65806                 .selectAll('.layer-list-mapillary')
65807                 .data([0]);
65808
65809             mapillaryList = mapillaryList.enter()
65810                 .append('ul')
65811                 .attr('class', 'layer-list layer-list-mapillary')
65812                 .merge(mapillaryList);
65813
65814
65815             var mapillaryImageLayerItem = mapillaryList
65816                 .selectAll('.list-item-mapillary-images')
65817                 .data(supportsMapillaryImages ? [0] : []);
65818
65819             mapillaryImageLayerItem.exit()
65820                 .remove();
65821
65822             var enterImages = mapillaryImageLayerItem.enter()
65823                 .append('li')
65824                 .attr('class', 'list-item-mapillary-images');
65825
65826             var labelImages = enterImages
65827                 .append('label')
65828                 .call(tooltip()
65829                     .title(t('mapillary_images.tooltip'))
65830                     .placement('top'));
65831
65832             labelImages
65833                 .append('input')
65834                 .attr('type', 'checkbox')
65835                 .on('change', clickMapillaryImages);
65836
65837             labelImages
65838                 .append('span')
65839                 .text(t('mapillary_images.title'));
65840
65841
65842             var mapillarySignLayerItem = mapillaryList
65843                 .selectAll('.list-item-mapillary-signs')
65844                 .data(supportsMapillarySigns ? [0] : []);
65845
65846             mapillarySignLayerItem.exit()
65847                 .remove();
65848
65849             var enterSigns = mapillarySignLayerItem.enter()
65850                 .append('li')
65851                 .attr('class', 'list-item-mapillary-signs');
65852
65853             var labelSigns = enterSigns
65854                 .append('label')
65855                 .call(tooltip()
65856                     .title(t('mapillary_signs.tooltip'))
65857                     .placement('top'));
65858
65859             labelSigns
65860                 .append('input')
65861                 .attr('type', 'checkbox')
65862                 .on('change', clickMapillarySigns);
65863
65864             labelSigns
65865                 .append('span')
65866                 .text(t('mapillary_signs.title'));
65867
65868
65869             // Updates
65870             mapillaryImageLayerItem = mapillaryImageLayerItem
65871                 .merge(enterImages);
65872
65873             mapillaryImageLayerItem
65874                 .classed('active', showsMapillaryImages)
65875                 .selectAll('input')
65876                 .property('checked', showsMapillaryImages);
65877
65878
65879             mapillarySignLayerItem = mapillarySignLayerItem
65880                 .merge(enterSigns);
65881
65882             mapillarySignLayerItem
65883                 .classed('active', showsMapillarySigns)
65884                 .selectAll('input')
65885                 .property('disabled', !showsMapillaryImages)
65886                 .property('checked', showsMapillarySigns);
65887
65888             mapillarySignLayerItem
65889                 .selectAll('label')
65890                 .classed('deemphasize', !showsMapillaryImages);
65891         }
65892
65893
65894         function drawGpxItem(selection$$1) {
65895             var gpx = layers.layer('gpx'),
65896                 hasGpx = gpx && gpx.hasGpx(),
65897                 showsGpx = hasGpx && gpx.enabled();
65898
65899             var gpxLayerItem = selection$$1
65900                 .selectAll('.layer-list-gpx')
65901                 .data(gpx ? [0] : []);
65902
65903             // Exit
65904             gpxLayerItem.exit()
65905                 .remove();
65906
65907             // Enter
65908             var enter = gpxLayerItem.enter()
65909                 .append('ul')
65910                 .attr('class', 'layer-list layer-list-gpx')
65911                 .append('li')
65912                 .classed('list-item-gpx', true);
65913
65914             enter
65915                 .append('button')
65916                 .attr('class', 'list-item-gpx-extent')
65917                 .call(tooltip()
65918                     .title(t('gpx.zoom'))
65919                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
65920                 .on('click', function() {
65921                     event.preventDefault();
65922                     event.stopPropagation();
65923                     gpx.fitZoom();
65924                 })
65925                 .call(svgIcon('#icon-search'));
65926
65927             enter
65928                 .append('button')
65929                 .attr('class', 'list-item-gpx-browse')
65930                 .call(tooltip()
65931                     .title(t('gpx.browse'))
65932                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
65933                 .on('click', function() {
65934                     select(document.createElement('input'))
65935                         .attr('type', 'file')
65936                         .on('change', function() {
65937                             gpx.files(event.target.files);
65938                         })
65939                         .node().click();
65940                 })
65941                 .call(svgIcon('#icon-geolocate'));
65942
65943             var labelGpx = enter
65944                 .append('label')
65945                 .call(tooltip().title(t('gpx.drag_drop')).placement('top'));
65946
65947             labelGpx
65948                 .append('input')
65949                 .attr('type', 'checkbox')
65950                 .on('change', clickGpx);
65951
65952             labelGpx
65953                 .append('span')
65954                 .text(t('gpx.local_layer'));
65955
65956
65957             // Update
65958             gpxLayerItem = gpxLayerItem
65959                 .merge(enter);
65960
65961             gpxLayerItem
65962                 .classed('active', showsGpx)
65963                 .selectAll('input')
65964                 .property('disabled', !hasGpx)
65965                 .property('checked', showsGpx);
65966
65967             gpxLayerItem
65968                 .selectAll('label')
65969                 .classed('deemphasize', !hasGpx);
65970         }
65971
65972
65973         function drawList(selection$$1, data, type, name, change, active$$1) {
65974             var items = selection$$1.selectAll('li')
65975                 .data(data);
65976
65977             // Exit
65978             items.exit()
65979                 .remove();
65980
65981             // Enter
65982             var enter = items.enter()
65983                 .append('li')
65984                 .attr('class', 'layer')
65985                 .call(tooltip()
65986                     .html(true)
65987                     .title(function(d) {
65988                         var tip = t(name + '.' + d + '.tooltip'),
65989                             key = (d === 'wireframe' ? t('area_fill.wireframe.key') : null);
65990
65991                         if (name === 'feature' && autoHiddenFeature(d)) {
65992                             tip += '<div>' + t('map_data.autohidden') + '</div>';
65993                         }
65994                         return uiTooltipHtml(tip, key);
65995                     })
65996                     .placement('top')
65997                 );
65998
65999             var label = enter
66000                 .append('label');
66001
66002             label
66003                 .append('input')
66004                 .attr('type', type)
66005                 .attr('name', name)
66006                 .on('change', change);
66007
66008             label
66009                 .append('span')
66010                 .text(function(d) { return t(name + '.' + d + '.description'); });
66011
66012             // Update
66013             items = items
66014                 .merge(enter);
66015
66016             items
66017                 .classed('active', active$$1)
66018                 .selectAll('input')
66019                 .property('checked', active$$1)
66020                 .property('indeterminate', function(d) {
66021                     return (name === 'feature' && autoHiddenFeature(d));
66022                 });
66023         }
66024
66025
66026         function update() {
66027             dataLayerContainer.call(drawMapillaryItems);
66028             dataLayerContainer.call(drawGpxItem);
66029
66030             fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
66031             featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
66032         }
66033
66034
66035         function hidePanel() {
66036             setVisible(false);
66037         }
66038
66039
66040         function togglePanel() {
66041             if (event) event.preventDefault();
66042             tooltipBehavior.hide(button);
66043             setVisible(!button.classed('active'));
66044         }
66045
66046
66047         function toggleWireframe() {
66048             if (event) {
66049                 event.preventDefault();
66050                 event.stopPropagation();
66051             }
66052             setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
66053             context.map().pan([0,0]);  // trigger a redraw
66054         }
66055
66056
66057         function setVisible(show) {
66058             if (show !== shown) {
66059                 button.classed('active', show);
66060                 shown = show;
66061
66062                 if (show) {
66063                     update();
66064                     selection$$1.on('mousedown.map_data-inside', function() {
66065                         return event.stopPropagation();
66066                     });
66067                     content.style('display', 'block')
66068                         .style('right', '-300px')
66069                         .transition()
66070                         .duration(200)
66071                         .style('right', '0px');
66072                 } else {
66073                     content.style('display', 'block')
66074                         .style('right', '0px')
66075                         .transition()
66076                         .duration(200)
66077                         .style('right', '-300px')
66078                         .on('end', function() {
66079                             select(this).style('display', 'none');
66080                         });
66081                     selection$$1.on('mousedown.map_data-inside', null);
66082                 }
66083             }
66084         }
66085
66086
66087         var content = selection$$1
66088                 .append('div')
66089                 .attr('class', 'fillL map-overlay col3 content hide'),
66090             tooltipBehavior = tooltip()
66091                 .placement((textDirection === 'rtl') ? 'right' : 'left')
66092                 .html(true)
66093                 .title(uiTooltipHtml(t('map_data.description'), key)),
66094             button = selection$$1
66095                 .append('button')
66096                 .attr('tabindex', -1)
66097                 .on('click', togglePanel)
66098                 .call(svgIcon('#icon-data', 'light'))
66099                 .call(tooltipBehavior),
66100             shown = false;
66101
66102         content
66103             .append('h4')
66104             .text(t('map_data.title'));
66105
66106
66107         // data layers
66108         content
66109             .append('a')
66110             .text(t('map_data.data_layers'))
66111             .attr('href', '#')
66112             .classed('hide-toggle', true)
66113             .classed('expanded', true)
66114             .on('click', function() {
66115                 var exp = select(this).classed('expanded');
66116                 dataLayerContainer.style('display', exp ? 'none' : 'block');
66117                 select(this).classed('expanded', !exp);
66118                 event.preventDefault();
66119             });
66120
66121         var dataLayerContainer = content
66122             .append('div')
66123             .attr('class', 'data-data-layers')
66124             .style('display', 'block');
66125
66126
66127         // area fills
66128         content
66129             .append('a')
66130             .text(t('map_data.fill_area'))
66131             .attr('href', '#')
66132             .classed('hide-toggle', true)
66133             .classed('expanded', false)
66134             .on('click', function() {
66135                 var exp = select(this).classed('expanded');
66136                 fillContainer.style('display', exp ? 'none' : 'block');
66137                 select(this).classed('expanded', !exp);
66138                 event.preventDefault();
66139             });
66140
66141         var fillContainer = content
66142             .append('div')
66143             .attr('class', 'data-area-fills')
66144             .style('display', 'none');
66145
66146         var fillList = fillContainer
66147             .append('ul')
66148             .attr('class', 'layer-list layer-fill-list');
66149
66150
66151         // feature filters
66152         content
66153             .append('a')
66154             .text(t('map_data.map_features'))
66155             .attr('href', '#')
66156             .classed('hide-toggle', true)
66157             .classed('expanded', false)
66158             .on('click', function() {
66159                 var exp = select(this).classed('expanded');
66160                 featureContainer.style('display', exp ? 'none' : 'block');
66161                 select(this).classed('expanded', !exp);
66162                 event.preventDefault();
66163             });
66164
66165         var featureContainer = content
66166             .append('div')
66167             .attr('class', 'data-feature-filters')
66168             .style('display', 'none');
66169
66170         var featureList = featureContainer
66171             .append('ul')
66172             .attr('class', 'layer-list layer-feature-list');
66173
66174
66175         context.features()
66176             .on('change.map_data-update', update);
66177
66178         setFill(fillDefault);
66179
66180         var keybinding = d3keybinding('features')
66181             .on(key, togglePanel)
66182             .on(t('area_fill.wireframe.key'), toggleWireframe)
66183             .on([t('background.key'), t('help.key')], hidePanel);
66184
66185         select(document)
66186             .call(keybinding);
66187
66188         context.surface().on('mousedown.map_data-outside', hidePanel);
66189         context.container().on('mousedown.map_data-outside', hidePanel);
66190     }
66191
66192
66193     return map_data;
66194 }
66195
66196 function uiModes(context) {
66197     var modes = [
66198         modeAddPoint$$1(context),
66199         modeAddLine$$1(context),
66200         modeAddArea$$1(context)
66201     ];
66202
66203
66204     function editable() {
66205         return context.editable() && context.mode().id !== 'save';
66206     }
66207
66208
66209     return function(selection$$1) {
66210         var buttons = selection$$1.selectAll('button.add-button')
66211             .data(modes);
66212
66213         buttons = buttons.enter()
66214             .append('button')
66215             .attr('tabindex', -1)
66216             .attr('class', function(mode) { return mode.id + ' add-button col4'; })
66217             .on('click.mode-buttons', function(mode) {
66218                 if (mode.id === context.mode().id) {
66219                     context.enter(modeBrowse(context));
66220                 } else {
66221                     context.enter(mode);
66222                 }
66223             })
66224             .call(tooltip()
66225                 .placement('bottom')
66226                 .html(true)
66227                 .title(function(mode) {
66228                     return uiTooltipHtml(mode.description, mode.key);
66229                 })
66230             );
66231
66232         context.map()
66233             .on('move.modes', lodash.debounce(update, 500));
66234
66235         context
66236             .on('enter.modes', update);
66237
66238         buttons
66239             .each(function(d) {
66240                 select(this)
66241                     .call(svgIcon('#icon-' + d.button, 'pre-text'));
66242             });
66243
66244         buttons
66245             .append('span')
66246             .attr('class', 'label')
66247             .text(function(mode) { return mode.title; });
66248
66249         context
66250             .on('enter.editor', function(entered) {
66251                 selection$$1.selectAll('button.add-button')
66252                     .classed('active', function(mode) { return entered.button === mode.button; });
66253                 context.container()
66254                     .classed('mode-' + entered.id, true);
66255             });
66256
66257         context
66258             .on('exit.editor', function(exited) {
66259                 context.container()
66260                     .classed('mode-' + exited.id, false);
66261             });
66262
66263         var keybinding = d3keybinding('mode-buttons');
66264
66265         modes.forEach(function(mode) {
66266             keybinding.on(mode.key, function() {
66267                 if (editable()) {
66268                     if (mode.id === context.mode().id) {
66269                         context.enter(modeBrowse(context));
66270                     } else {
66271                         context.enter(mode);
66272                     }
66273                 }
66274             });
66275         });
66276
66277         select(document)
66278             .call(keybinding);
66279
66280
66281         function update() {
66282             selection$$1.selectAll('button.add-button')
66283                 .property('disabled', !editable());
66284         }
66285     };
66286 }
66287
66288 function uiRestore(context) {
66289
66290     return function(selection) {
66291         if (!context.history().lock() || !context.history().restorableChanges())
66292             return;
66293
66294         var modalSelection = uiModal(selection, true);
66295
66296         modalSelection.select('.modal')
66297             .attr('class', 'modal fillL col6');
66298
66299         var introModal = modalSelection.select('.content');
66300
66301         introModal
66302             .attr('class','cf');
66303
66304         introModal
66305             .append('div')
66306             .attr('class', 'modal-section')
66307             .append('h3')
66308             .text(t('restore.heading'));
66309
66310         introModal
66311             .append('div')
66312             .attr('class','modal-section')
66313             .append('p')
66314             .text(t('restore.description'));
66315
66316         var buttonWrap = introModal
66317             .append('div')
66318             .attr('class', 'modal-actions cf');
66319
66320         var restore = buttonWrap
66321             .append('button')
66322             .attr('class', 'restore col6')
66323             .on('click', function() {
66324                 context.history().restore();
66325                 modalSelection.remove();
66326             });
66327
66328         restore
66329             .append('svg')
66330             .attr('class', 'logo logo-restore')
66331             .append('use')
66332             .attr('xlink:href', '#logo-restore');
66333
66334         restore
66335             .append('div')
66336             .text(t('restore.restore'));
66337
66338         var reset = buttonWrap
66339             .append('button')
66340             .attr('class', 'reset col6')
66341             .on('click', function() {
66342                 context.history().clearSaved();
66343                 modalSelection.remove();
66344             });
66345
66346         reset
66347             .append('svg')
66348             .attr('class', 'logo logo-reset')
66349             .append('use')
66350             .attr('xlink:href', '#logo-reset');
66351
66352         reset
66353             .append('div')
66354             .text(t('restore.reset'));
66355
66356         restore.node().focus();
66357     };
66358 }
66359
66360 function uiSave(context) {
66361     var history = context.history(),
66362         key = uiCmd('⌘S');
66363
66364
66365     function saving() {
66366         return context.mode().id === 'save';
66367     }
66368
66369
66370     function save() {
66371         event.preventDefault();
66372         if (!context.inIntro() && !saving() && history.hasChanges()) {
66373             context.enter(modeSave$$1(context));
66374         }
66375     }
66376
66377
66378     function getBackground(numChanges) {
66379         var step$$1;
66380         if (numChanges === 0) {
66381             return null;
66382         } else if (numChanges <= 50) {
66383             step$$1 = numChanges / 50;
66384             return interpolateRgb('#fff', '#ff8')(step$$1);  // white -> yellow
66385         } else {
66386             step$$1 = Math.min((numChanges - 50) / 50, 1.0);
66387             return interpolateRgb('#ff8', '#f88')(step$$1);  // yellow -> red
66388         }
66389     }
66390
66391
66392     return function(selection$$1) {
66393         var numChanges = 0;
66394
66395         function updateCount() {
66396             var _ = history.difference().summary().length;
66397             if (_ === numChanges) return;
66398             numChanges = _;
66399
66400             tooltipBehavior
66401                 .title(uiTooltipHtml(
66402                     t(numChanges > 0 ? 'save.help' : 'save.no_changes'), key)
66403                 );
66404
66405             var background = getBackground(numChanges);
66406
66407             button
66408                 .classed('disabled', numChanges === 0)
66409                 .classed('has-count', numChanges > 0)
66410                 .style('background', background);
66411
66412             button.select('span.count')
66413                 .text(numChanges)
66414                 .style('background', background)
66415                 .style('border-color', background);
66416         }
66417
66418
66419         var tooltipBehavior = tooltip()
66420             .placement('bottom')
66421             .html(true)
66422             .title(uiTooltipHtml(t('save.no_changes'), key));
66423
66424         var button = selection$$1
66425             .append('button')
66426             .attr('class', 'save col12 disabled')
66427             .attr('tabindex', -1)
66428             .on('click', save)
66429             .call(tooltipBehavior);
66430
66431         button
66432             .call(svgIcon('#icon-save', 'pre-text'))
66433             .append('span')
66434             .attr('class', 'label')
66435             .text(t('save.title'));
66436
66437         button
66438             .append('span')
66439             .attr('class', 'count')
66440             .text('0');
66441
66442         updateCount();
66443
66444
66445         var keybinding = d3keybinding('save')
66446             .on(key, save, true);
66447
66448         select(document)
66449             .call(keybinding);
66450
66451         context.history()
66452             .on('change.save', updateCount);
66453
66454         context
66455             .on('enter.save', function() {
66456                 button.property('disabled', saving());
66457                 if (saving()) button.call(tooltipBehavior.hide);
66458             });
66459     };
66460 }
66461
66462 function uiScale(context) {
66463     var projection = context.projection,
66464         isImperial = (utilDetect().locale.toLowerCase() === 'en-us'),
66465         maxLength = 180,
66466         tickHeight = 8;
66467
66468
66469     function scaleDefs(loc1, loc2) {
66470         var lat = (loc2[1] + loc1[1]) / 2,
66471             conversion = (isImperial ? 3.28084 : 1),
66472             dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
66473             scale = { dist: 0, px: 0, text: '' },
66474             buckets, i, val, dLon;
66475
66476         if (isImperial) {
66477             buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
66478         } else {
66479             buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
66480         }
66481
66482         // determine a user-friendly endpoint for the scale
66483         for (i = 0; i < buckets.length; i++) {
66484             val = buckets[i];
66485             if (dist >= val) {
66486                 scale.dist = Math.floor(dist / val) * val;
66487                 break;
66488             } else {
66489                 scale.dist = +dist.toFixed(2);
66490             }
66491         }
66492
66493         dLon = geoMetersToLon(scale.dist / conversion, lat);
66494         scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
66495
66496         if (isImperial) {
66497             if (scale.dist >= 5280) {
66498                 scale.dist /= 5280;
66499                 scale.text = String(scale.dist) + ' mi';
66500             } else {
66501                 scale.text = String(scale.dist) + ' ft';
66502             }
66503         } else {
66504             if (scale.dist >= 1000) {
66505                 scale.dist /= 1000;
66506                 scale.text = String(scale.dist) + ' km';
66507             } else {
66508                 scale.text = String(scale.dist) + ' m';
66509             }
66510         }
66511
66512         return scale;
66513     }
66514
66515
66516     function update(selection) {
66517         // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
66518         var dims = context.map().dimensions(),
66519             loc1 = projection.invert([0, dims[1]]),
66520             loc2 = projection.invert([maxLength, dims[1]]),
66521             scale = scaleDefs(loc1, loc2);
66522
66523         selection.select('#scale-path')
66524             .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
66525
66526         selection.select('#scale-textgroup')
66527             .attr('transform', 'translate(' + (scale.px + 8) + ',' + tickHeight + ')');
66528
66529         selection.select('#scale-text')
66530             .text(scale.text);
66531     }
66532
66533
66534     return function(selection) {
66535         function switchUnits() {
66536             isImperial = !isImperial;
66537             selection.call(update);
66538         }
66539
66540         var scalegroup = selection.append('svg')
66541             .attr('id', 'scale')
66542             .on('click', switchUnits)
66543             .append('g')
66544             .attr('transform', 'translate(10,11)');
66545
66546         scalegroup
66547             .append('path')
66548             .attr('id', 'scale-path');
66549
66550         scalegroup
66551             .append('g')
66552             .attr('id', 'scale-textgroup')
66553             .append('text')
66554             .attr('id', 'scale-text');
66555
66556         selection.call(update);
66557
66558         context.map().on('move.scale', function() {
66559             update(selection);
66560         });
66561     };
66562 }
66563
66564 var pair_1 = pair$1;
66565 function search(x, dims, r) {
66566   if (!dims) dims = 'NSEW';
66567   if (typeof x !== 'string') return { val: null, regex: r };
66568   r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
66569   var m = r.exec(x);
66570   if (!m) return { val: null, regex: r };
66571   else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
66572   else return {
66573     val: (((m[1]) ? parseFloat(m[1]) : 0) +
66574           ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
66575           ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
66576           ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
66577     regex: r,
66578     raw: m[0],
66579     dim: m[4]
66580   };
66581 }
66582
66583 function pair$1(x, dims) {
66584   x = x.trim();
66585   var one = search(x, dims);
66586   if (one.val === null) return null;
66587   var two = search(x, dims, one.regex);
66588   if (two.val === null) return null;
66589   // null if one/two are not contiguous.
66590   if (one.raw + two.raw !== x) return null;
66591   if (one.dim) {
66592     return swapdim(one.val, two.val, one.dim);
66593   } else {
66594     return [one.val, two.val];
66595   }
66596 }
66597
66598 function swapdim(a, b, dim) {
66599   if (dim === 'N' || dim === 'S') return [a, b];
66600   if (dim === 'W' || dim === 'E') return [b, a];
66601 }
66602
66603 function uiFeatureList(context) {
66604     var geocodeResults;
66605
66606
66607     function featureList(selection$$1) {
66608         var header = selection$$1
66609             .append('div')
66610             .attr('class', 'header fillL cf');
66611
66612         header.append('h3')
66613             .text(t('inspector.feature_list'));
66614
66615         var searchWrap = selection$$1
66616             .append('div')
66617             .attr('class', 'search-header');
66618
66619         var search = searchWrap
66620             .append('input')
66621             .attr('placeholder', t('inspector.search'))
66622             .attr('type', 'search')
66623             .call(utilNoAuto)
66624             .on('keypress', keypress)
66625             .on('input', inputevent);
66626
66627         searchWrap
66628             .call(svgIcon('#icon-search', 'pre-text'));
66629
66630         var listWrap = selection$$1
66631             .append('div')
66632             .attr('class', 'inspector-body');
66633
66634         var list = listWrap
66635             .append('div')
66636             .attr('class', 'feature-list cf');
66637
66638         context
66639             .on('exit.feature-list', clearSearch);
66640         context.map()
66641             .on('drawn.feature-list', mapDrawn);
66642
66643
66644         function keypress() {
66645             var q = search.property('value'),
66646                 items = list.selectAll('.feature-list-item');
66647             if (event.keyCode === 13 && q.length && items.size()) {
66648                 click(items.datum());
66649             }
66650         }
66651
66652
66653         function inputevent() {
66654             geocodeResults = undefined;
66655             drawList();
66656         }
66657
66658
66659         function clearSearch() {
66660             search.property('value', '');
66661             drawList();
66662         }
66663
66664
66665         function mapDrawn(e) {
66666             if (e.full) {
66667                 drawList();
66668             }
66669         }
66670
66671
66672         function features() {
66673             var entities = {},
66674                 result = [],
66675                 graph = context.graph(),
66676                 q = search.property('value').toLowerCase();
66677
66678             if (!q) return result;
66679
66680             var idMatch = q.match(/^([nwr])([0-9]+)$/);
66681
66682             if (idMatch) {
66683                 result.push({
66684                     id: idMatch[0],
66685                     geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
66686                     type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
66687                     name: idMatch[2]
66688                 });
66689             }
66690
66691             var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
66692
66693             if (locationMatch) {
66694                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
66695                 result.push({
66696                     id: -1,
66697                     geometry: 'point',
66698                     type: t('inspector.location'),
66699                     name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
66700                     location: loc
66701                 });
66702             }
66703
66704             function addEntity(entity) {
66705                 if (entity.id in entities || result.length > 200)
66706                     return;
66707
66708                 entities[entity.id] = true;
66709
66710                 var name = utilDisplayName(entity) || '';
66711                 if (name.toLowerCase().indexOf(q) >= 0) {
66712                     var matched = context.presets().match(entity, graph),
66713                         type = (matched && matched.name()) || utilDisplayType(entity.id);
66714                     result.push({
66715                         id: entity.id,
66716                         entity: entity,
66717                         geometry: context.geometry(entity.id),
66718                         type: type,
66719                         name: name
66720                     });
66721                 }
66722
66723                 graph.parentRelations(entity).forEach(function(parent) {
66724                     addEntity(parent);
66725                 });
66726             }
66727
66728             var visible = context.surface().selectAll('.point, .line, .area').nodes();
66729             for (var i = 0; i < visible.length && result.length <= 200; i++) {
66730                 addEntity(visible[i].__data__);
66731             }
66732
66733             (geocodeResults || []).forEach(function(d) {
66734                 // https://github.com/openstreetmap/iD/issues/1890
66735                 if (d.osm_type && d.osm_id) {
66736                     result.push({
66737                         id: osmEntity$$1.id.fromOSM(d.osm_type, d.osm_id),
66738                         geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
66739                         type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
66740                                                : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
66741                         name: d.display_name,
66742                         extent: new geoExtent$$1(
66743                             [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
66744                             [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
66745                     });
66746                 }
66747             });
66748
66749             return result;
66750         }
66751
66752
66753         function drawList() {
66754             var value = search.property('value'),
66755                 results = features();
66756
66757             list.classed('filtered', value.length);
66758
66759             var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
66760
66761             var resultsIndicator = list.selectAll('.no-results-item')
66762                 .data([0])
66763                 .enter().append('button')
66764                 .property('disabled', true)
66765                 .attr('class', 'no-results-item')
66766                 .call(svgIcon('#icon-alert', 'pre-text'));
66767
66768             resultsIndicator.append('span')
66769                 .attr('class', 'entity-name');
66770
66771             list.selectAll('.no-results-item .entity-name')
66772                 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
66773
66774             if (services.geocoder) {
66775               list.selectAll('.geocode-item')
66776                   .data([0])
66777                   .enter().append('button')
66778                   .attr('class', 'geocode-item')
66779                   .on('click', geocoderSearch)
66780                   .append('div')
66781                   .attr('class', 'label')
66782                   .append('span')
66783                   .attr('class', 'entity-name')
66784                   .text(t('geocoder.search'));
66785             }
66786
66787             list.selectAll('.no-results-item')
66788                 .style('display', (value.length && !results.length) ? 'block' : 'none');
66789
66790             list.selectAll('.geocode-item')
66791                 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
66792
66793             list.selectAll('.feature-list-item')
66794                 .data([-1])
66795                 .remove();
66796
66797             var items = list.selectAll('.feature-list-item')
66798                 .data(results, function(d) { return d.id; });
66799
66800             var enter = items.enter()
66801                 .insert('button', '.geocode-item')
66802                 .attr('class', 'feature-list-item')
66803                 .on('mouseover', mouseover)
66804                 .on('mouseout', mouseout)
66805                 .on('click', click);
66806
66807             var label = enter
66808                 .append('div')
66809                 .attr('class', 'label');
66810
66811             label.each(function(d) {
66812                 select(this)
66813                     .call(svgIcon('#icon-' + d.geometry, 'pre-text'));
66814             });
66815
66816             label.append('span')
66817                 .attr('class', 'entity-type')
66818                 .text(function(d) { return d.type; });
66819
66820             label.append('span')
66821                 .attr('class', 'entity-name')
66822                 .text(function(d) { return d.name; });
66823
66824             enter.style('opacity', 0)
66825                 .transition()
66826                 .style('opacity', 1);
66827
66828             items.order();
66829
66830             items.exit()
66831                 .remove();
66832         }
66833
66834
66835         function mouseover(d) {
66836             if (d.id === -1) return;
66837
66838             context.surface().selectAll(utilEntityOrMemberSelector([d.id], context.graph()))
66839                 .classed('hover', true);
66840         }
66841
66842
66843         function mouseout() {
66844             context.surface().selectAll('.hover')
66845                 .classed('hover', false);
66846         }
66847
66848
66849         function click(d) {
66850             event.preventDefault();
66851             if (d.location) {
66852                 context.map().centerZoom([d.location[1], d.location[0]], 20);
66853             }
66854             else if (d.entity) {
66855                 if (d.entity.type === 'node') {
66856                     context.map().center(d.entity.loc);
66857                 } else if (d.entity.type === 'way') {
66858                     var center = context.projection(context.map().center()),
66859                         edge = geoChooseEdge(context.childNodes(d.entity), center, context.projection);
66860                     context.map().center(edge.loc);
66861                 }
66862                 context.enter(modeSelect(context, [d.entity.id]));
66863             } else {
66864                 context.zoomToEntity(d.id);
66865             }
66866         }
66867
66868
66869         function geocoderSearch() {
66870             services.geocoder.search(search.property('value'), function (err, resp) {
66871                 geocodeResults = resp || [];
66872                 drawList();
66873             });
66874         }
66875     }
66876
66877
66878     return featureList;
66879 }
66880
66881 function uiPresetIcon() {
66882     var preset, geometry;
66883
66884
66885     function presetIcon(selection$$1) {
66886         selection$$1.each(render);
66887     }
66888
66889
66890     function getIcon(p, geom) {
66891         if (p.icon)
66892             return p.icon;
66893         else if (geom === 'line')
66894             return 'other-line';
66895         else if (geom === 'vertex')
66896             return p.isFallback() ? '' : 'poi-vertex';
66897         else
66898             return 'marker-stroked';
66899     }
66900
66901
66902     function render() {
66903         var selection$$1 = select(this),
66904             p = preset.apply(this, arguments),
66905             geom = geometry.apply(this, arguments),
66906             picon = getIcon(p, geom),
66907             isPoi = picon.match(/^poi-/) !== null,
66908             isMaki = dataFeatureIcons.indexOf(picon) !== -1,
66909             isFramed = (geom === 'area' || geom === 'verex');
66910
66911
66912         function tag_classes(p) {
66913             var s = '';
66914             for (var i in p.tags) {
66915                 s += ' tag-' + i;
66916                 if (p.tags[i] !== '*') {
66917                     s += ' tag-' + i + '-' + p.tags[i];
66918                 }
66919             }
66920             return s;
66921         }
66922
66923
66924         var fill = selection$$1.selectAll('.preset-icon-fill')
66925             .data([0]);
66926
66927         fill = fill.enter()
66928             .append('div')
66929             .merge(fill);
66930
66931         fill
66932             .attr('class', function() {
66933                 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
66934             });
66935
66936
66937         var areaFrame = selection$$1.selectAll('.preset-icon-frame')
66938             .data((geom === 'area') ? [0] : []);
66939
66940         areaFrame.exit()
66941             .remove();
66942
66943         areaFrame = areaFrame.enter()
66944             .append('div')
66945             .attr('class', 'preset-icon-frame')
66946             .call(svgIcon('#preset-icon-frame'));
66947
66948
66949         var icon = selection$$1.selectAll('.preset-icon')
66950             .data([0]);
66951
66952         icon = icon.enter()
66953             .append('div')
66954             .attr('class', 'preset-icon')
66955             .call(svgIcon(''))
66956             .merge(icon);
66957
66958         icon
66959             .attr('class', 'preset-icon preset-icon-' +
66960                 ((isMaki || isPoi) ? (isFramed ? '24' : '28') : (isFramed ? '44' : '60'))
66961             );
66962
66963         icon.selectAll('svg')
66964             .attr('class', function() {
66965                 return 'icon ' + picon + (isMaki || isPoi ? '' : tag_classes(p));
66966             });
66967
66968         icon.selectAll('use')
66969             .attr('href', '#' + picon + (isMaki ? '-15' : ''));
66970     }
66971
66972
66973     presetIcon.preset = function(_) {
66974         if (!arguments.length) return preset;
66975         preset = utilFunctor(_);
66976         return presetIcon;
66977     };
66978
66979
66980     presetIcon.geometry = function(_) {
66981         if (!arguments.length) return geometry;
66982         geometry = utilFunctor(_);
66983         return presetIcon;
66984     };
66985
66986     return presetIcon;
66987 }
66988
66989 function d3combobox() {
66990     var dispatch$$1 = dispatch('accept'),
66991         container = select(document.body),
66992         data = [],
66993         suggestions = [],
66994         minItems = 2,
66995         caseSensitive = false;
66996
66997     var fetcher = function(val, cb) {
66998         cb(data.filter(function(d) {
66999             return d.value
67000                 .toString()
67001                 .toLowerCase()
67002                 .indexOf(val.toLowerCase()) !== -1;
67003         }));
67004     };
67005
67006     var combobox = function(input, attachTo) {
67007         var idx = -1,
67008             wrapper = container
67009                 .selectAll('div.combobox')
67010                 .filter(function(d) { return d === input.node(); }),
67011             shown = !wrapper.empty();
67012
67013         input
67014             .classed('combobox-input', true)
67015             .on('focus.typeahead', focus)
67016             .on('blur.typeahead', blur)
67017             .on('keydown.typeahead', keydown)
67018             .on('keyup.typeahead', keyup)
67019             .on('input.typeahead', change)
67020             .each(function() {
67021                 var parent = this.parentNode,
67022                     sibling = this.nextSibling;
67023
67024                 var caret = select(parent).selectAll('.combobox-caret')
67025                     .filter(function(d) { return d === input.node(); })
67026                     .data([input.node()]);
67027
67028                 caret = caret.enter()
67029                   .insert('div', function() { return sibling; })
67030                     .attr('class', 'combobox-caret')
67031                   .merge(caret);
67032
67033                 caret
67034                     .on('mousedown', function () {
67035                         // prevent the form element from blurring. it blurs
67036                         // on mousedown
67037                         event.stopPropagation();
67038                         event.preventDefault();
67039                         if (!shown) {
67040                             input.node().focus();
67041                             fetch('', render);
67042                         } else {
67043                             hide();
67044                         }
67045                     });
67046             });
67047
67048         function focus() {
67049             fetch(value(), render);
67050         }
67051
67052         function blur() {
67053             window.setTimeout(hide, 150);
67054         }
67055
67056         function show() {
67057             if (!shown) {
67058                 wrapper = container
67059                     .insert('div', ':first-child')
67060                     .datum(input.node())
67061                     .attr('class', 'combobox')
67062                     .style('position', 'absolute')
67063                     .style('display', 'block')
67064                     .style('left', '0px')
67065                     .on('mousedown', function () {
67066                         // prevent moving focus out of the text field
67067                         event.preventDefault();
67068                     });
67069
67070                 select('body')
67071                     .on('scroll.combobox', render, true);
67072
67073                 shown = true;
67074             }
67075         }
67076
67077         function hide() {
67078             if (shown) {
67079                 idx = -1;
67080                 wrapper.remove();
67081
67082                 select('body')
67083                     .on('scroll.combobox', null);
67084
67085                 shown = false;
67086             }
67087         }
67088
67089         function keydown() {
67090            switch (event.keyCode) {
67091                // backspace, delete
67092                case 8:
67093                case 46:
67094                    input.on('input.typeahead', function() {
67095                        idx = -1;
67096                        render();
67097                        var start = input.property('selectionStart');
67098                        input.node().setSelectionRange(start, start);
67099                        input.on('input.typeahead', change);
67100                    });
67101                    break;
67102                // tab
67103                case 9:
67104                    wrapper.selectAll('a.selected').each(function (d) {
67105                        dispatch$$1.call('accept', this, d);
67106                    });
67107                    hide();
67108                    break;
67109                // return
67110                case 13:
67111                    event.preventDefault();
67112                    break;
67113                // up arrow
67114                case 38:
67115                    nav(-1);
67116                    event.preventDefault();
67117                    break;
67118                // down arrow
67119                case 40:
67120                    nav(+1);
67121                    event.preventDefault();
67122                    break;
67123            }
67124            event.stopPropagation();
67125         }
67126
67127         function keyup() {
67128             switch (event.keyCode) {
67129                 // escape
67130                 case 27:
67131                     hide();
67132                     break;
67133                 // return
67134                 case 13:
67135                     wrapper.selectAll('a.selected').each(function (d) {
67136                        dispatch$$1.call('accept', this, d);
67137                     });
67138                     hide();
67139                     break;
67140             }
67141         }
67142
67143         function change() {
67144             fetch(value(), function() {
67145                 if (input.property('selectionEnd') === input.property('value').length) {
67146                     autocomplete();
67147                 }
67148                 render();
67149             });
67150         }
67151
67152         function nav(dir) {
67153             if (!suggestions.length) return;
67154             idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
67155             input.property('value', suggestions[idx].value);
67156             render();
67157             ensureVisible();
67158         }
67159
67160         function value() {
67161             var value = input.property('value'),
67162                 start = input.property('selectionStart'),
67163                 end = input.property('selectionEnd');
67164
67165             if (start && end) {
67166                 value = value.substring(0, start);
67167             }
67168
67169             return value;
67170         }
67171
67172         function fetch(v, cb) {
67173             fetcher.call(input, v, function(_) {
67174                 suggestions = _;
67175                 cb();
67176             });
67177         }
67178
67179         function autocomplete() {
67180             var v = caseSensitive ? value() : value().toLowerCase();
67181             idx = -1;
67182             if (!v) return;
67183
67184             for (var i = 0; i < suggestions.length; i++) {
67185                 var suggestion = suggestions[i].value,
67186                     compare = caseSensitive ? suggestion : suggestion.toLowerCase();
67187
67188                 if (compare.indexOf(v) === 0) {
67189                     idx = i;
67190                     input.property('value', suggestion);
67191                     input.node().setSelectionRange(v.length, suggestion.length);
67192                     return;
67193                 }
67194             }
67195         }
67196
67197         function render() {
67198             if (suggestions.length >= minItems && document.activeElement === input.node()) {
67199                 show();
67200             } else {
67201                 hide();
67202                 return;
67203             }
67204
67205             var options = wrapper
67206                 .selectAll('a.combobox-option')
67207                 .data(suggestions, function(d) { return d.value; });
67208
67209             options.exit()
67210                 .remove();
67211
67212             options.enter()
67213                 .append('a')
67214                 .attr('class', 'combobox-option')
67215                 .text(function(d) { return d.value; })
67216                 .merge(options)
67217                 .attr('title', function(d) { return d.title; })
67218                 .classed('selected', function(d, i) { return i === idx; })
67219                 .on('mouseover', select$$1)
67220                 .on('click', accept)
67221                 .order();
67222
67223
67224             var node = attachTo ? attachTo.node() : input.node(),
67225                 rect = node.getBoundingClientRect();
67226
67227             wrapper
67228                 .style('left', rect.left + 'px')
67229                 .style('width', rect.width + 'px')
67230                 .style('top', rect.height + rect.top + 'px');
67231         }
67232
67233         function select$$1(d, i) {
67234             idx = i;
67235             render();
67236         }
67237
67238         function ensureVisible() {
67239             var node = wrapper.selectAll('a.selected').node();
67240             if (node) node.scrollIntoView();
67241         }
67242
67243         function accept(d) {
67244             if (!shown) return;
67245             input.property('value', d.value);
67246             utilTriggerEvent(input, 'change');
67247             dispatch$$1.call('accept', this, d);
67248             hide();
67249         }
67250     };
67251
67252     combobox.fetcher = function(_) {
67253         if (!arguments.length) return fetcher;
67254         fetcher = _;
67255         return combobox;
67256     };
67257
67258     combobox.data = function(_) {
67259         if (!arguments.length) return data;
67260         data = _;
67261         return combobox;
67262     };
67263
67264     combobox.minItems = function(_) {
67265         if (!arguments.length) return minItems;
67266         minItems = _;
67267         return combobox;
67268     };
67269
67270     combobox.caseSensitive = function(_) {
67271         if (!arguments.length) return caseSensitive;
67272         caseSensitive = _;
67273         return combobox;
67274     };
67275
67276     combobox.container = function(_) {
67277         if (!arguments.length) return container;
67278         container = _;
67279         return combobox;
67280     };
67281
67282     return utilRebind(combobox, dispatch$$1, 'on');
67283 }
67284
67285
67286 d3combobox.off = function(input) {
67287     input
67288         .on('focus.typeahead', null)
67289         .on('blur.typeahead', null)
67290         .on('keydown.typeahead', null)
67291         .on('keyup.typeahead', null)
67292         .on('input.typeahead', null)
67293         .each(function() {
67294             select(this.parentNode).selectAll('.combobox-caret')
67295                 .filter(function(d) { return d === input.node(); })
67296                 .on('mousedown', null);
67297         });
67298
67299     select('body')
67300         .on('scroll.combobox', null);
67301 };
67302
67303 function uiDisclosure() {
67304     var dispatch$$1 = dispatch('toggled'),
67305         title,
67306         expanded = false,
67307         content = function () {};
67308
67309
67310     var disclosure = function(selection$$1) {
67311         var hideToggle = selection$$1.selectAll('.hide-toggle')
67312             .data([0]);
67313
67314         hideToggle = hideToggle.enter()
67315             .append('a')
67316             .attr('href', '#')
67317             .attr('class', 'hide-toggle')
67318             .merge(hideToggle);
67319
67320         hideToggle
67321             .text(title)
67322             .on('click', toggle)
67323             .classed('expanded', expanded);
67324
67325
67326         var wrap = selection$$1.selectAll('div')
67327             .data([0]);
67328
67329         wrap = wrap.enter()
67330             .append('div')
67331             .merge(wrap);
67332
67333         wrap
67334             .classed('hide', !expanded)
67335             .call(content);
67336
67337
67338         function toggle() {
67339             expanded = !expanded;
67340             hideToggle.classed('expanded', expanded);
67341             wrap.call(uiToggle(expanded));
67342             dispatch$$1.call('toggled', this, expanded);
67343         }
67344     };
67345
67346
67347     disclosure.title = function(_) {
67348         if (!arguments.length) return title;
67349         title = _;
67350         return disclosure;
67351     };
67352
67353
67354     disclosure.expanded = function(_) {
67355         if (!arguments.length) return expanded;
67356         expanded = _;
67357         return disclosure;
67358     };
67359
67360
67361     disclosure.content = function(_) {
67362         if (!arguments.length) return content;
67363         content = _;
67364         return disclosure;
67365     };
67366
67367
67368     return utilRebind(disclosure, dispatch$$1, 'on');
67369 }
67370
67371 function uiRawMemberEditor(context) {
67372     var id,
67373         taginfo = services.taginfo;
67374
67375
67376     function selectMember(d) {
67377         event.preventDefault();
67378         context.enter(modeSelect(context, [d.id]));
67379     }
67380
67381
67382     function changeRole(d) {
67383         var role = select(this).property('value');
67384         var member = { id: d.id, type: d.type, role: role };
67385         context.perform(
67386             actionChangeMember(d.relation.id, member, d.index),
67387             t('operations.change_role.annotation')
67388         );
67389     }
67390
67391
67392     function deleteMember(d) {
67393         context.perform(
67394             actionDeleteMember(d.relation.id, d.index),
67395             t('operations.delete_member.annotation')
67396         );
67397
67398         if (!context.hasEntity(d.relation.id)) {
67399             context.enter(modeBrowse(context));
67400         }
67401     }
67402
67403
67404     function rawMemberEditor(selection$$1) {
67405         var entity = context.entity(id),
67406             memberships = [];
67407
67408         entity.members.slice(0, 1000).forEach(function(member, index) {
67409             memberships.push({
67410                 index: index,
67411                 id: member.id,
67412                 type: member.type,
67413                 role: member.role,
67414                 relation: entity,
67415                 member: context.hasEntity(member.id)
67416             });
67417         });
67418
67419         var gt = entity.members.length > 1000 ? '>' : '';
67420         selection$$1.call(uiDisclosure()
67421             .title(t('inspector.all_members') + ' (' + gt + memberships.length + ')')
67422             .expanded(true)
67423             .on('toggled', toggled)
67424             .content(content)
67425         );
67426
67427
67428         function toggled(expanded) {
67429             if (expanded) {
67430                 selection$$1.node().parentNode.scrollTop += 200;
67431             }
67432         }
67433
67434
67435         function content(wrap) {
67436             var list = wrap.selectAll('.member-list')
67437                 .data([0]);
67438
67439             list = list.enter()
67440                 .append('ul')
67441                 .attr('class', 'member-list')
67442                 .merge(list);
67443
67444
67445             var items = list.selectAll('li')
67446                 .data(memberships, function(d) {
67447                     return osmEntity$$1.key(d.relation) + ',' + d.index + ',' +
67448                         (d.member ? osmEntity$$1.key(d.member) : 'incomplete');
67449                 });
67450
67451             items.exit()
67452                 .each(unbind)
67453                 .remove();
67454
67455             var enter = items.enter()
67456                 .append('li')
67457                 .attr('class', 'member-row form-field')
67458                 .classed('member-incomplete', function(d) { return !d.member; });
67459
67460             enter
67461                 .each(function(d) {
67462                     if (d.member) {
67463                         var label = select(this).append('label')
67464                             .attr('class', 'form-label')
67465                             .append('a')
67466                             .attr('href', '#')
67467                             .on('click', selectMember);
67468
67469                         label.append('span')
67470                             .attr('class', 'member-entity-type')
67471                             .text(function(d) {
67472                                 var matched = context.presets().match(d.member, context.graph());
67473                                 return (matched && matched.name()) || utilDisplayType(d.member.id);
67474                             });
67475
67476                         label.append('span')
67477                             .attr('class', 'member-entity-name')
67478                             .text(function(d) { return utilDisplayName(d.member); });
67479
67480                     } else {
67481                         select(this).append('label')
67482                             .attr('class', 'form-label')
67483                             .text(t('inspector.incomplete', { id: d.id }));
67484                     }
67485                 });
67486
67487             enter
67488                 .append('input')
67489                 .attr('class', 'member-role')
67490                 .property('type', 'text')
67491                 .attr('maxlength', 255)
67492                 .attr('placeholder', t('inspector.role'))
67493                 .call(utilNoAuto)
67494                 .property('value', function(d) { return d.role; })
67495                 .on('change', changeRole);
67496
67497             enter
67498                 .append('button')
67499                 .attr('tabindex', -1)
67500                 .attr('class', 'remove button-input-action member-delete minor')
67501                 .on('click', deleteMember)
67502                 .call(svgIcon('#operation-delete'));
67503
67504             if (taginfo) {
67505                 enter.each(bindTypeahead);
67506             }
67507
67508
67509             function bindTypeahead(d) {
67510                 var row = select(this),
67511                     role = row.selectAll('input.member-role');
67512
67513                 function sort(value, data) {
67514                     var sameletter = [],
67515                         other = [];
67516                     for (var i = 0; i < data.length; i++) {
67517                         if (data[i].value.substring(0, value.length) === value) {
67518                             sameletter.push(data[i]);
67519                         } else {
67520                             other.push(data[i]);
67521                         }
67522                     }
67523                     return sameletter.concat(other);
67524                 }
67525
67526                 role.call(d3combobox()
67527                     .container(context.container())
67528                     .fetcher(function(role, callback) {
67529                         var rtype = entity.tags.type;
67530                         taginfo.roles({
67531                             debounce: true,
67532                             rtype: rtype || '',
67533                             geometry: context.geometry(d.member.id),
67534                             query: role
67535                         }, function(err, data) {
67536                             if (!err) callback(sort(role, data));
67537                         });
67538                     }));
67539             }
67540
67541
67542             function unbind() {
67543                 var row = select(this);
67544
67545                 row.selectAll('input.member-role')
67546                     .call(d3combobox.off);
67547             }
67548         }
67549     }
67550
67551
67552     rawMemberEditor.entityID = function(_) {
67553         if (!arguments.length) return id;
67554         id = _;
67555         return rawMemberEditor;
67556     };
67557
67558
67559     return rawMemberEditor;
67560 }
67561
67562 function uiRawMembershipEditor(context) {
67563     var taginfo = services.taginfo,
67564         id, showBlank;
67565
67566
67567     function selectRelation(d) {
67568         event.preventDefault();
67569         context.enter(modeSelect(context, [d.relation.id]));
67570     }
67571
67572
67573     function changeRole(d) {
67574         var role = select(this).property('value');
67575         context.perform(
67576             actionChangeMember(d.relation.id, lodash.extend({}, d.member, { role: role }), d.index),
67577             t('operations.change_role.annotation')
67578         );
67579     }
67580
67581
67582     function addMembership(d, role) {
67583         showBlank = false;
67584
67585         if (d.relation) {
67586             context.perform(
67587                 actionAddMember(d.relation.id, { id: id, type: context.entity(id).type, role: role }),
67588                 t('operations.add_member.annotation')
67589             );
67590
67591         } else {
67592             var relation = osmRelation();
67593             context.perform(
67594                 actionAddEntity(relation),
67595                 actionAddMember(relation.id, { id: id, type: context.entity(id).type, role: role }),
67596                 t('operations.add.annotation.relation')
67597             );
67598
67599             context.enter(modeSelect(context, [relation.id]));
67600         }
67601     }
67602
67603
67604     function deleteMembership(d) {
67605         context.perform(
67606             actionDeleteMember(d.relation.id, d.index),
67607             t('operations.delete_member.annotation')
67608         );
67609     }
67610
67611
67612     function relations(q) {
67613         var newRelation = {
67614                 relation: null,
67615                 value: t('inspector.new_relation')
67616             },
67617             result = [],
67618             graph = context.graph();
67619
67620         context.intersects(context.extent()).forEach(function(entity) {
67621             if (entity.type !== 'relation' || entity.id === id)
67622                 return;
67623
67624             var matched = context.presets().match(entity, graph),
67625                 presetName = (matched && matched.name()) || t('inspector.relation'),
67626                 entityName = utilDisplayName(entity) || '';
67627
67628             var value = presetName + ' ' + entityName;
67629             if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
67630                 return;
67631
67632             result.push({
67633                 relation: entity,
67634                 value: value
67635             });
67636         });
67637
67638         result.sort(function(a, b) {
67639             return osmRelation.creationOrder(a.relation, b.relation);
67640         });
67641
67642         // Dedupe identical names by appending relation id - see #2891
67643         var dupeGroups = lodash(result)
67644             .groupBy('value')
67645             .filter(function(v) { return v.length > 1; })
67646             .value();
67647
67648         dupeGroups.forEach(function(group) {
67649             group.forEach(function(obj) {
67650                 obj.value += ' ' + obj.relation.id;
67651             });
67652         });
67653
67654         result.unshift(newRelation);
67655         return result;
67656     }
67657
67658
67659     function rawMembershipEditor(selection$$1) {
67660         var entity = context.entity(id),
67661             parents = context.graph().parentRelations(entity),
67662             memberships = [];
67663
67664         parents.slice(0, 1000).forEach(function(relation) {
67665             relation.members.forEach(function(member, index) {
67666                 if (member.id === entity.id) {
67667                     memberships.push({ relation: relation, member: member, index: index });
67668                 }
67669             });
67670         });
67671
67672         var gt = parents.length > 1000 ? '>' : '';
67673         selection$$1.call(uiDisclosure()
67674             .title(t('inspector.all_relations') + ' (' + gt + memberships.length + ')')
67675             .expanded(true)
67676             .on('toggled', toggled)
67677             .content(content)
67678         );
67679
67680
67681         function toggled(expanded) {
67682             if (expanded) {
67683                 selection$$1.node().parentNode.scrollTop += 200;
67684             }
67685         }
67686
67687
67688         function content(wrap) {
67689             var list = wrap.selectAll('.member-list')
67690                 .data([0]);
67691
67692             list = list.enter()
67693                 .append('ul')
67694                 .attr('class', 'member-list')
67695                 .merge(list);
67696
67697
67698             var items = list.selectAll('li.member-row-normal')
67699                 .data(memberships, function(d) {
67700                     return osmEntity$$1.key(d.relation) + ',' + d.index;
67701                 });
67702
67703             items.exit()
67704                 .each(unbind)
67705                 .remove();
67706
67707             var enter = items.enter()
67708                 .append('li')
67709                 .attr('class', 'member-row member-row-normal form-field');
67710
67711             var label = enter
67712                 .append('label')
67713                 .attr('class', 'form-label')
67714                 .append('a')
67715                 .attr('href', '#')
67716                 .on('click', selectRelation);
67717
67718             label
67719                 .append('span')
67720                 .attr('class', 'member-entity-type')
67721                 .text(function(d) {
67722                     var matched = context.presets().match(d.relation, context.graph());
67723                     return (matched && matched.name()) || t('inspector.relation');
67724                 });
67725
67726             label
67727                 .append('span')
67728                 .attr('class', 'member-entity-name')
67729                 .text(function(d) { return utilDisplayName(d.relation); });
67730
67731             enter
67732                 .append('input')
67733                 .attr('class', 'member-role')
67734                 .property('type', 'text')
67735                 .attr('maxlength', 255)
67736                 .attr('placeholder', t('inspector.role'))
67737                 .call(utilNoAuto)
67738                 .property('value', function(d) { return d.member.role; })
67739                 .on('change', changeRole);
67740
67741             enter
67742                 .append('button')
67743                 .attr('tabindex', -1)
67744                 .attr('class', 'remove button-input-action member-delete minor')
67745                 .on('click', deleteMembership)
67746                 .call(svgIcon('#operation-delete'));
67747
67748             if (taginfo) {
67749                 enter.each(bindTypeahead);
67750             }
67751
67752
67753             var newrow = list.selectAll('.member-row-new')
67754                 .data(showBlank ? [0] : []);
67755
67756             newrow.exit()
67757                 .remove();
67758
67759             enter = newrow.enter()
67760                 .append('li')
67761                 .attr('class', 'member-row member-row-new form-field');
67762
67763             enter
67764                 .append('input')
67765                 .attr('type', 'text')
67766                 .attr('class', 'member-entity-input')
67767                 .call(utilNoAuto);
67768
67769             enter
67770                 .append('input')
67771                 .attr('class', 'member-role')
67772                 .property('type', 'text')
67773                 .attr('maxlength', 255)
67774                 .attr('placeholder', t('inspector.role'))
67775                 .call(utilNoAuto)
67776                 .on('change', changeRole);
67777
67778             enter
67779                 .append('button')
67780                 .attr('tabindex', -1)
67781                 .attr('class', 'remove button-input-action member-delete minor')
67782                 .on('click', deleteMembership)
67783                 .call(svgIcon('#operation-delete'));
67784
67785             newrow = newrow
67786                 .merge(enter);
67787
67788             newrow.selectAll('.member-entity-input')
67789                 .call(d3combobox()
67790                     .container(context.container())
67791                     .minItems(1)
67792                     .fetcher(function(value, callback) { callback(relations(value)); })
67793                     .on('accept', onAccept)
67794                 );
67795
67796
67797             var addrel = wrap.selectAll('.add-relation')
67798                 .data([0]);
67799
67800             addrel = addrel.enter()
67801                 .append('button')
67802                 .attr('class', 'add-relation')
67803                 .merge(addrel);
67804
67805             addrel
67806                 .call(svgIcon('#icon-plus', 'light'))
67807                 .on('click', function() {
67808                     showBlank = true;
67809                     content(wrap);
67810                     list.selectAll('.member-entity-input').node().focus();
67811                 });
67812
67813
67814             function onAccept(d) {
67815                 var role = list.selectAll('.member-row-new .member-role').property('value');
67816                 addMembership(d, role);
67817             }
67818
67819
67820             function bindTypeahead(d) {
67821                 var row = select(this),
67822                     role = row.selectAll('input.member-role');
67823
67824                 function sort(value, data) {
67825                     var sameletter = [],
67826                         other = [];
67827                     for (var i = 0; i < data.length; i++) {
67828                         if (data[i].value.substring(0, value.length) === value) {
67829                             sameletter.push(data[i]);
67830                         } else {
67831                             other.push(data[i]);
67832                         }
67833                     }
67834                     return sameletter.concat(other);
67835                 }
67836
67837                 role.call(d3combobox()
67838                     .container(context.container())
67839                     .fetcher(function(role, callback) {
67840                         var rtype = d.relation.tags.type;
67841                         taginfo.roles({
67842                             debounce: true,
67843                             rtype: rtype || '',
67844                             geometry: context.geometry(id),
67845                             query: role
67846                         }, function(err, data) {
67847                             if (!err) callback(sort(role, data));
67848                         });
67849                     }));
67850             }
67851
67852
67853             function unbind() {
67854                 var row = select(this);
67855
67856                 row.selectAll('input.member-role')
67857                     .call(d3combobox.off);
67858             }
67859         }
67860     }
67861
67862
67863     rawMembershipEditor.entityID = function(_) {
67864         if (!arguments.length) return id;
67865         id = _;
67866         return rawMembershipEditor;
67867     };
67868
67869
67870     return rawMembershipEditor;
67871 }
67872
67873 function uiTagReference(tag) {
67874     var taginfo = services.taginfo,
67875         tagReference = {},
67876         button,
67877         body,
67878         loaded,
67879         showing;
67880
67881
67882     function findLocal(data) {
67883         var locale = utilDetect().locale.toLowerCase(),
67884             localized;
67885
67886         if (locale !== 'pt-br') {  // see #3776, prefer 'pt' over 'pt-br'
67887             localized = lodash.find(data, function(d) {
67888                 return d.lang.toLowerCase() === locale;
67889             });
67890             if (localized) return localized;
67891         }
67892
67893         // try the non-regional version of a language, like
67894         // 'en' if the language is 'en-US'
67895         if (locale.indexOf('-') !== -1) {
67896             var first = locale.split('-')[0];
67897             localized = lodash.find(data, function(d) {
67898                 return d.lang.toLowerCase() === first;
67899             });
67900             if (localized) return localized;
67901         }
67902
67903         // finally fall back to english
67904         return lodash.find(data, function(d) {
67905             return d.lang.toLowerCase() === 'en';
67906         });
67907     }
67908
67909
67910     function load(param) {
67911         if (!taginfo) return;
67912
67913         button.classed('tag-reference-loading', true);
67914
67915         taginfo.docs(param, function show(err, data) {
67916             var docs;
67917             if (!err && data) {
67918                 docs = findLocal(data);
67919             }
67920
67921             body.html('');
67922
67923
67924             if (!docs || !docs.title) {
67925                 if (param.hasOwnProperty('value')) {
67926                     load(lodash.omit(param, 'value'));   // retry with key only
67927                 } else {
67928                     body.append('p').text(t('inspector.no_documentation_key'));
67929                     done();
67930                 }
67931                 return;
67932             }
67933
67934
67935             if (docs.image && docs.image.thumb_url_prefix) {
67936                 body
67937                     .append('img')
67938                     .attr('class', 'wiki-image')
67939                     .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
67940                     .on('load', function() { done(); })
67941                     .on('error', function() { select(this).remove(); done(); });
67942             } else {
67943                 done();
67944             }
67945
67946             body
67947                 .append('p')
67948                 .text(docs.description || t('inspector.documentation_redirect'));
67949
67950             body
67951                 .append('a')
67952                 .attr('target', '_blank')
67953                 .attr('tabindex', -1)
67954                 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
67955                 .call(svgIcon('#icon-out-link', 'inline'))
67956                 .append('span')
67957                 .text(t('inspector.reference'));
67958         });
67959     }
67960
67961
67962     function done() {
67963         loaded = true;
67964
67965         button.classed('tag-reference-loading', false);
67966
67967         body.transition()
67968             .duration(200)
67969             .style('max-height', '200px')
67970             .style('opacity', '1');
67971
67972         showing = true;
67973     }
67974
67975
67976     function hide(selection$$1) {
67977         selection$$1 = selection$$1 || body.transition().duration(200);
67978
67979         selection$$1
67980             .style('max-height', '0px')
67981             .style('opacity', '0');
67982
67983         showing = false;
67984     }
67985
67986
67987     tagReference.button = function(selection$$1) {
67988         button = selection$$1.selectAll('.tag-reference-button')
67989             .data([0]);
67990
67991         button = button.enter()
67992             .append('button')
67993             .attr('class', 'tag-reference-button')
67994             .attr('tabindex', -1)
67995             .call(svgIcon('#icon-inspect'))
67996             .merge(button);
67997
67998         button
67999             .on('click', function () {
68000                 event.stopPropagation();
68001                 event.preventDefault();
68002                 if (showing) {
68003                     hide();
68004                 } else if (loaded) {
68005                     done();
68006                 } else {
68007                     load(tag);
68008                 }
68009             });
68010     };
68011
68012
68013     tagReference.body = function(selection$$1) {
68014         body = selection$$1.selectAll('.tag-reference-body')
68015             .data([0]);
68016
68017         body = body.enter()
68018             .append('div')
68019             .attr('class', 'tag-reference-body cf')
68020             .style('max-height', '0')
68021             .style('opacity', '0')
68022             .merge(body);
68023
68024         if (showing === false) {
68025             hide(body);
68026         }
68027     };
68028
68029
68030     tagReference.showing = function(_) {
68031         if (!arguments.length) return showing;
68032         showing = _;
68033         return tagReference;
68034     };
68035
68036
68037     return tagReference;
68038 }
68039
68040 function uiRawTagEditor(context) {
68041     var taginfo = services.taginfo,
68042         dispatch$$1 = dispatch('change'),
68043         expandedPreference = (context.storage('raw_tag_editor.expanded') === 'true'),
68044         expandedCurrent = expandedPreference,
68045         updatePreference = true,
68046         readOnlyTags = [],
68047         showBlank = false,
68048         newRow,
68049         state,
68050         preset,
68051         tags,
68052         id;
68053
68054
68055     function rawTagEditor(selection$$1) {
68056         var count = Object.keys(tags).filter(function(d) { return d; }).length;
68057
68058         selection$$1.call(uiDisclosure()
68059             .title(t('inspector.all_tags') + ' (' + count + ')')
68060             .expanded(expandedCurrent)
68061             .on('toggled', toggled)
68062             .content(content)
68063         );
68064
68065         function toggled(expanded) {
68066             expandedCurrent = expanded;
68067             if (updatePreference) {
68068                 expandedPreference = expanded;
68069                 context.storage('raw_tag_editor.expanded', expanded);
68070             }
68071             if (expanded) {
68072                 selection$$1.node().parentNode.scrollTop += 200;
68073             }
68074         }
68075     }
68076
68077
68078     function content(wrap) {
68079         var entries$$1 = entries(tags);
68080
68081         if (!entries$$1.length || showBlank) {
68082             showBlank = false;
68083             entries$$1.push({key: '', value: ''});
68084             newRow = '';
68085         }
68086
68087         var list = wrap.selectAll('.tag-list')
68088             .data([0]);
68089
68090         list = list.enter()
68091             .append('ul')
68092             .attr('class', 'tag-list')
68093             .merge(list);
68094
68095         var newTag = wrap.selectAll('.add-tag')
68096             .data([0]);
68097
68098         newTag.enter()
68099             .append('button')
68100             .attr('class', 'add-tag')
68101             .on('click', addTag)
68102             .call(svgIcon('#icon-plus', 'light'));
68103
68104
68105         var items = list.selectAll('.tag-row')
68106             .data(entries$$1, function(d) { return d.key; });
68107
68108         items.exit()
68109             .each(unbind)
68110             .remove();
68111
68112         // Enter
68113
68114         var enter = items.enter()
68115             .append('li')
68116             .attr('class', 'tag-row cf')
68117             .classed('readonly', isReadOnly);
68118
68119         enter
68120             .append('div')
68121             .attr('class', 'key-wrap')
68122             .append('input')
68123             .property('type', 'text')
68124             .attr('class', 'key')
68125             .attr('maxlength', 255)
68126             .call(utilNoAuto)
68127             .on('blur', keyChange)
68128             .on('change', keyChange);
68129
68130         enter
68131             .append('div')
68132             .attr('class', 'input-wrap-position')
68133             .append('input')
68134             .property('type', 'text')
68135             .attr('class', 'value')
68136             .attr('maxlength', 255)
68137             .call(utilNoAuto)
68138             .on('blur', valueChange)
68139             .on('change', valueChange)
68140             .on('keydown.push-more', pushMore);
68141
68142         enter
68143             .append('button')
68144             .attr('tabindex', -1)
68145             .attr('class', 'remove minor')
68146             .call(svgIcon('#operation-delete'));
68147
68148
68149         // Update
68150
68151         items = items
68152             .merge(enter)
68153             .sort(function(a, b) {
68154                 return (a.key === newRow && b.key !== newRow) ? 1
68155                     : (a.key !== newRow && b.key === newRow) ? -1
68156                     : ascending(a.key, b.key);
68157             });
68158
68159         items
68160             .each(function(tag) {
68161                 var row = select(this),
68162                     key = row.select('input.key'),      // propagate bound data to child
68163                     value = row.select('input.value');  // propagate bound data to child
68164
68165                 if (id && taginfo) {
68166                     bindTypeahead(key, value);
68167                 }
68168
68169                 var isRelation = (id && context.entity(id).type === 'relation'),
68170                     reference;
68171
68172                 if (isRelation && tag.key === 'type') {
68173                     reference = uiTagReference({ rtype: tag.value }, context);
68174                 } else {
68175                     reference = uiTagReference({ key: tag.key, value: tag.value }, context);
68176                 }
68177
68178                 if (state === 'hover') {
68179                     reference.showing(false);
68180                 }
68181
68182                 row
68183                     .call(reference.button)
68184                     .call(reference.body);
68185             });
68186
68187         items.selectAll('input.key')
68188             .attr('title', function(d) { return d.key; })
68189             .call(utilGetSetValue, function(d) { return d.key; })
68190             .property('disabled', isReadOnly);
68191
68192         items.selectAll('input.value')
68193             .attr('title', function(d) { return d.value; })
68194             .call(utilGetSetValue, function(d) { return d.value; })
68195             .property('disabled', isReadOnly);
68196
68197         items.selectAll('button.remove')
68198             .on('click', removeTag);
68199
68200
68201
68202         function isReadOnly(d) {
68203             return readOnlyTags.indexOf(d.key) !== -1;
68204         }
68205
68206
68207         function pushMore() {
68208             if (event.keyCode === 9 && !event.shiftKey &&
68209                 list.selectAll('li:last-child input.value').node() === this) {
68210                 addTag();
68211             }
68212         }
68213
68214
68215         function bindTypeahead(key, value) {
68216             if (isReadOnly({ key: key })) return;
68217             var geometry = context.geometry(id);
68218
68219             key.call(d3combobox()
68220                 .container(context.container())
68221                 .fetcher(function(value, callback) {
68222                     taginfo.keys({
68223                         debounce: true,
68224                         geometry: geometry,
68225                         query: value
68226                     }, function(err, data) {
68227                         if (!err) callback(sort(value, data));
68228                     });
68229                 }));
68230
68231             value.call(d3combobox()
68232                 .container(context.container())
68233                 .fetcher(function(value, callback) {
68234                     taginfo.values({
68235                         debounce: true,
68236                         key: utilGetSetValue(key),
68237                         geometry: geometry,
68238                         query: value
68239                     }, function(err, data) {
68240                         if (!err) callback(sort(value, data));
68241                     });
68242                 }));
68243
68244
68245             function sort(value, data) {
68246                 var sameletter = [],
68247                     other = [];
68248                 for (var i = 0; i < data.length; i++) {
68249                     if (data[i].value.substring(0, value.length) === value) {
68250                         sameletter.push(data[i]);
68251                     } else {
68252                         other.push(data[i]);
68253                     }
68254                 }
68255                 return sameletter.concat(other);
68256             }
68257         }
68258
68259
68260         function unbind() {
68261             var row = select(this);
68262
68263             row.selectAll('input.key')
68264                 .call(d3combobox.off);
68265
68266             row.selectAll('input.value')
68267                 .call(d3combobox.off);
68268         }
68269
68270
68271         function keyChange(d) {
68272             var kOld = d.key,
68273                 kNew = this.value.trim(),
68274                 tag = {};
68275
68276
68277             if (isReadOnly({ key: kNew })) {
68278                 this.value = kOld;
68279                 return;
68280             }
68281
68282             if (kNew && kNew !== kOld) {
68283                 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
68284                     base = match[1],
68285                     suffix = +(match[2] || 1);
68286                 while (tags[kNew]) {  // rename key if already in use
68287                     kNew = base + '_' + suffix++;
68288                 }
68289             }
68290             tag[kOld] = undefined;
68291             tag[kNew] = d.value;
68292
68293             d.key = kNew; // Maintain DOM identity through the subsequent update.
68294
68295             if (newRow === kOld) {  // see if this row is still a new row
68296                 newRow = ((d.value === '' || kNew === '') ? kNew : undefined);
68297             }
68298
68299             this.value = kNew;
68300             dispatch$$1.call('change', this, tag);
68301         }
68302
68303
68304         function valueChange(d) {
68305             if (isReadOnly(d)) return;
68306             var tag = {};
68307             tag[d.key] = this.value;
68308
68309             if (newRow === d.key && d.key !== '' && d.value !== '') {   // not a new row anymore
68310                 newRow = undefined;
68311             }
68312
68313             dispatch$$1.call('change', this, tag);
68314         }
68315
68316
68317         function removeTag(d) {
68318             if (isReadOnly(d)) return;
68319             var tag = {};
68320             tag[d.key] = undefined;
68321             dispatch$$1.call('change', this, tag);
68322             select(this.parentNode).remove();
68323         }
68324
68325
68326         function addTag() {
68327             // Wrapped in a setTimeout in case it's being called from a blur
68328             // handler. Without the setTimeout, the call to `content` would
68329             // wipe out the pending value change.
68330             setTimeout(function() {
68331                 showBlank = true;
68332                 content(wrap);
68333                 list.selectAll('li:last-child input.key').node().focus();
68334             }, 0);
68335         }
68336     }
68337
68338
68339     rawTagEditor.state = function(_) {
68340         if (!arguments.length) return state;
68341         state = _;
68342         return rawTagEditor;
68343     };
68344
68345
68346     rawTagEditor.preset = function(_) {
68347         if (!arguments.length) return preset;
68348         preset = _;
68349         if (preset.isFallback()) {
68350             expandedCurrent = true;
68351             updatePreference = false;
68352         } else {
68353             expandedCurrent = expandedPreference;
68354             updatePreference = true;
68355         }
68356         return rawTagEditor;
68357     };
68358
68359
68360     rawTagEditor.tags = function(_) {
68361         if (!arguments.length) return tags;
68362         tags = _;
68363         return rawTagEditor;
68364     };
68365
68366
68367     rawTagEditor.entityID = function(_) {
68368         if (!arguments.length) return id;
68369         id = _;
68370         return rawTagEditor;
68371     };
68372
68373
68374     rawTagEditor.expanded = function(_) {
68375         if (!arguments.length) return expandedCurrent;
68376         expandedCurrent = _;
68377         updatePreference = false;
68378         return rawTagEditor;
68379     };
68380
68381
68382     rawTagEditor.readOnlyTags = function(_) {
68383         if (!arguments.length) return readOnlyTags;
68384         readOnlyTags = _;
68385         return rawTagEditor;
68386     };
68387
68388
68389     return utilRebind(rawTagEditor, dispatch$$1, 'on');
68390 }
68391
68392 function uiFieldCheck(field, context) {
68393     var dispatch$$1 = dispatch('change'),
68394         options = field.strings && field.strings.options,
68395         values$$1 = [],
68396         texts = [],
68397         input = select(null),
68398         text$$1 = select(null),
68399         label = select(null),
68400         reverser = select(null),
68401         impliedYes,
68402         entityId,
68403         value;
68404
68405
68406     if (options) {
68407         for (var k in options) {
68408             values$$1.push(k === 'undefined' ? undefined : k);
68409             texts.push(field.t('options.' + k, { 'default': options[k] }));
68410         }
68411     } else {
68412         values$$1 = [undefined, 'yes'];
68413         texts = [t('inspector.unknown'), t('inspector.check.yes')];
68414         if (field.type !== 'defaultCheck') {
68415             values$$1.push('no');
68416             texts.push(t('inspector.check.no'));
68417         }
68418     }
68419
68420
68421     // Checks tags to see whether an undefined value is "Assumed to be Yes"
68422     function checkImpliedYes() {
68423         impliedYes = (field.id === 'oneway_yes');
68424
68425         // hack: pretend `oneway` field is a `oneway_yes` field
68426         // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
68427         if (field.id === 'oneway') {
68428             var entity = context.entity(entityId);
68429             for (var key in entity.tags) {
68430                 if (key in osmOneWayTags && (entity.tags[key] in osmOneWayTags[key])) {
68431                     impliedYes = true;
68432                     texts[0] = t('presets.fields.oneway_yes.options.undefined');
68433                     break;
68434                 }
68435             }
68436         }
68437     }
68438
68439
68440     function reverserHidden() {
68441         if (!select('div.inspector-hover').empty()) return true;
68442         return !(value === 'yes' || (impliedYes && !value));
68443     }
68444
68445
68446     function reverserSetText(selection$$1) {
68447         var entity = context.hasEntity(entityId);
68448         if (reverserHidden() || !entity) return selection$$1;
68449
68450         var first = entity.first(),
68451             last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last(),
68452             pseudoDirection = first < last,
68453             icon = pseudoDirection ? '#icon-forward' : '#icon-backward';
68454
68455         selection$$1.selectAll('.reverser-span')
68456             .text(t('inspector.check.reverser'))
68457             .call(svgIcon(icon, 'inline'));
68458
68459         return selection$$1;
68460     }
68461
68462
68463     var check = function(selection$$1) {
68464         checkImpliedYes();
68465         selection$$1.classed('checkselect', 'true');
68466
68467         label = selection$$1.selectAll('.preset-input-wrap')
68468             .data([0]);
68469
68470         var enter = label.enter()
68471             .append('label')
68472             .attr('class', 'preset-input-wrap');
68473
68474         enter
68475             .append('input')
68476             .property('indeterminate', field.type !== 'defaultCheck')
68477             .attr('type', 'checkbox')
68478             .attr('id', 'preset-input-' + field.id);
68479
68480         enter
68481             .append('span')
68482             .text(texts[0])
68483             .attr('class', 'value');
68484
68485         if (field.type === 'onewayCheck') {
68486             enter
68487                 .append('a')
68488                 .attr('id', 'preset-input-' + field.id + '-reverser')
68489                 .attr('class', 'reverser button' + (reverserHidden() ? ' hide' : ''))
68490                 .attr('href', '#')
68491                 .append('span')
68492                 .attr('class', 'reverser-span');
68493         }
68494
68495         label = label.merge(enter);
68496         input = label.selectAll('input');
68497         text$$1 = label.selectAll('span.value');
68498
68499         input
68500             .on('click', function() {
68501                 var t$$1 = {};
68502                 t$$1[field.key] = values$$1[(values$$1.indexOf(value) + 1) % values$$1.length];
68503                 dispatch$$1.call('change', this, t$$1);
68504                 event.stopPropagation();
68505             });
68506
68507         if (field.type === 'onewayCheck') {
68508             reverser = label.selectAll('.reverser');
68509
68510             reverser
68511                 .call(reverserSetText)
68512                 .on('click', function() {
68513                     event.preventDefault();
68514                     event.stopPropagation();
68515                     context.perform(
68516                         actionReverse(entityId),
68517                         t('operations.reverse.annotation')
68518                     );
68519                     select(this)
68520                         .call(reverserSetText);
68521                 });
68522         }
68523     };
68524
68525
68526     check.entity = function(_) {
68527         if (!arguments.length) return context.hasEntity(entityId);
68528         entityId = _.id;
68529         return check;
68530     };
68531
68532
68533     check.tags = function(tags) {
68534         checkImpliedYes();
68535         value = tags[field.key] && tags[field.key].toLowerCase();
68536
68537         if (field.type === 'onewayCheck' && (value === '1' || value === '-1')) {
68538             value = 'yes';
68539         }
68540
68541         input
68542             .property('indeterminate', field.type !== 'defaultCheck' && !value)
68543             .property('checked', value === 'yes');
68544
68545         text$$1
68546             .text(texts[values$$1.indexOf(value)]);
68547
68548         label
68549             .classed('set', !!value);
68550
68551         if (field.type === 'onewayCheck') {
68552             reverser
68553                 .classed('hide', reverserHidden())
68554                 .call(reverserSetText);
68555         }
68556     };
68557
68558
68559     check.focus = function() {
68560         input.node().focus();
68561     };
68562
68563     return utilRebind(check, dispatch$$1, 'on');
68564 }
68565
68566 function uiFieldCombo(field, context) {
68567     var dispatch$$1 = dispatch('change'),
68568         nominatim = services.geocoder,
68569         taginfo = services.taginfo,
68570         isMulti = (field.type === 'multiCombo'),
68571         isNetwork = (field.type === 'networkCombo'),
68572         isSemi = (field.type === 'semiCombo'),
68573         optstrings = field.strings && field.strings.options,
68574         optarray = field.options,
68575         snake_case = (field.snake_case || (field.snake_case === undefined)),
68576         combobox = d3combobox()
68577             .container(context.container())
68578             .minItems(isMulti || isSemi ? 1 : 2),
68579         comboData = [],
68580         multiData = [],
68581         container,
68582         input,
68583         entity,
68584         country;
68585
68586     // ensure multiCombo field.key ends with a ':'
68587     if (isMulti && field.key.match(/:$/) === null) {
68588         field.key += ':';
68589     }
68590
68591
68592     function snake(s) {
68593         return s.replace(/\s+/g, '_');
68594     }
68595
68596     function unsnake(s) {
68597         return s.replace(/_+/g, ' ');
68598     }
68599
68600     function clean(s) {
68601         return s.split(';')
68602             .map(function(s) { return s.trim(); })
68603             .join(';');
68604     }
68605
68606
68607     // returns the tag value for a display value
68608     // (for multiCombo, dval should be the key suffix, not the entire key)
68609     function tagValue(dval) {
68610         dval = clean(dval || '');
68611
68612         if (optstrings) {
68613             var match = lodash.find(comboData, function(o) {
68614                 return o.key && clean(o.value) === dval;
68615             });
68616             if (match) {
68617                 return match.key;
68618             }
68619         }
68620
68621         if (field.type === 'typeCombo' && !dval) {
68622             return 'yes';
68623         }
68624
68625         return (snake_case ? snake(dval) : dval) || undefined;
68626     }
68627
68628
68629     // returns the display value for a tag value
68630     // (for multiCombo, tval should be the key suffix, not the entire key)
68631     function displayValue(tval) {
68632         tval = tval || '';
68633
68634         if (optstrings) {
68635             var match = lodash.find(comboData, function(o) { return o.key === tval && o.value; });
68636             if (match) {
68637                 return match.value;
68638             }
68639         }
68640
68641         if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
68642             return '';
68643         }
68644
68645         return snake_case ? unsnake(tval) : tval;
68646     }
68647
68648
68649     function objectDifference(a, b) {
68650         return lodash.reject(a, function(d1) {
68651             return lodash.some(b, function(d2) { return d1.value === d2.value; });
68652         });
68653     }
68654
68655
68656     function initCombo(selection$$1, attachTo) {
68657         if (optstrings) {
68658             selection$$1.attr('readonly', 'readonly');
68659             selection$$1.call(combobox, attachTo);
68660             setStaticValues(setPlaceholder);
68661
68662         } else if (optarray) {
68663             selection$$1.call(combobox, attachTo);
68664             setStaticValues(setPlaceholder);
68665
68666         } else if (taginfo) {
68667             selection$$1.call(combobox.fetcher(setTaginfoValues), attachTo);
68668             setTaginfoValues('', setPlaceholder);
68669         }
68670     }
68671
68672
68673     function setStaticValues(callback) {
68674         if (!(optstrings || optarray)) return;
68675
68676         if (optstrings) {
68677             comboData = Object.keys(optstrings).map(function(k) {
68678                 var v = field.t('options.' + k, { 'default': optstrings[k] });
68679                 return {
68680                     key: k,
68681                     value: v,
68682                     title: v
68683                 };
68684             });
68685
68686         } else if (optarray) {
68687             comboData = optarray.map(function(k) {
68688                 var v = snake_case ? unsnake(k) : k;
68689                 return {
68690                     key: k,
68691                     value: v,
68692                     title: v
68693                 };
68694             });
68695         }
68696
68697         combobox.data(objectDifference(comboData, multiData));
68698         if (callback) callback(comboData);
68699     }
68700
68701
68702     function setTaginfoValues(q, callback) {
68703         var fn = isMulti ? 'multikeys' : 'values';
68704         var query = (isMulti ? field.key : '') + q;
68705         var hasCountryPrefix = isNetwork && country && country.indexOf(q.toLowerCase()) === 0;
68706         if (hasCountryPrefix) {
68707             query = country + ':';
68708         }
68709
68710         taginfo[fn]({
68711             debounce: (q !== ''),
68712             key: field.key,
68713             geometry: context.geometry(entity.id),
68714             query: query
68715         }, function(err, data) {
68716             if (err) return;
68717             if (hasCountryPrefix) {
68718                 data = lodash.filter(data, function(d) {
68719                     return d.value.toLowerCase().indexOf(country + ':') === 0;
68720                 });
68721             }
68722
68723             comboData = lodash.map(data, function(d) {
68724                 var k = d.value;
68725                 if (isMulti) k = k.replace(field.key, '');
68726                 var v = snake_case ? unsnake(k) : k;
68727                 return {
68728                     key: k,
68729                     value: v,
68730                     title: isMulti ? v : d.title
68731                 };
68732             });
68733
68734             comboData = objectDifference(comboData, multiData);
68735             if (callback) callback(comboData);
68736         });
68737     }
68738
68739
68740     function setPlaceholder(d) {
68741         var ph;
68742
68743         if (isMulti || isSemi) {
68744             ph = field.placeholder() || t('inspector.add');
68745         } else {
68746             var vals = lodash.map(d, 'value').filter(function(s) { return s.length < 20; }),
68747                 placeholders = vals.length > 1 ? vals : lodash.map(d, 'key');
68748             ph = field.placeholder() || placeholders.slice(0, 3).join(', ');
68749         }
68750
68751         if (ph.match(/(…|\.\.\.)$/) === null) {
68752             ph += '…';
68753         }
68754
68755         container.selectAll('input')
68756             .attr('placeholder', ph);
68757     }
68758
68759
68760     function change() {
68761         var val = tagValue(utilGetSetValue(input)),
68762             t$$1 = {};
68763
68764         if (isMulti || isSemi) {
68765             if (!val) return;
68766             container.classed('active', false);
68767             utilGetSetValue(input, '');
68768             if (isMulti) {
68769                 field.keys.push(field.key + val);
68770                 t$$1[field.key + val] = 'yes';
68771             } else if (isSemi) {
68772                 var arr = multiData.map(function(d) { return d.key; });
68773                 arr.push(val);
68774                 t$$1[field.key] = lodash.compact(lodash.uniq(arr)).join(';');
68775             }
68776             window.setTimeout(function() { input.node().focus(); }, 10);
68777
68778         } else {
68779             t$$1[field.key] = val;
68780         }
68781
68782         dispatch$$1.call('change', this, t$$1);
68783     }
68784
68785
68786     function removeMultikey(d) {
68787         event.stopPropagation();
68788         var t$$1 = {};
68789         if (isMulti) {
68790             t$$1[d.key] = undefined;
68791         } else if (isSemi) {
68792             lodash.remove(multiData, function(md) { return md.key === d.key; });
68793             var arr = multiData.map(function(md) { return md.key; });
68794             arr = lodash.compact(lodash.uniq(arr));
68795             t$$1[field.key] = arr.length ? arr.join(';') : undefined;
68796         }
68797         dispatch$$1.call('change', this, t$$1);
68798     }
68799
68800
68801     function combo(selection$$1) {
68802         if (isMulti || isSemi) {
68803             container = selection$$1.selectAll('ul').data([0]);
68804
68805             container = container.enter()
68806                 .append('ul')
68807                 .attr('class', 'form-field-multicombo')
68808                 .on('click', function() {
68809                     window.setTimeout(function() { input.node().focus(); }, 10);
68810                 })
68811                 .merge(container);
68812
68813         } else {
68814             container = selection$$1;
68815         }
68816
68817         input = container.selectAll('input')
68818             .data([0]);
68819
68820         input = input.enter()
68821             .append('input')
68822             .attr('type', 'text')
68823             .attr('id', 'preset-input-' + field.id)
68824             .call(utilNoAuto)
68825             .call(initCombo, selection$$1)
68826             .merge(input);
68827
68828         if (isNetwork && nominatim && entity) {
68829             var center = entity.extent(context.graph()).center();
68830             nominatim.countryCode(center, function (err, code) {
68831                 country = code;
68832             });
68833         }
68834
68835         input
68836             .on('change', change)
68837             .on('blur', change);
68838
68839         if (isMulti || isSemi) {
68840             combobox
68841                 .on('accept', function() {
68842                     input.node().blur();
68843                     input.node().focus();
68844                 });
68845
68846             input
68847                 .on('focus', function() { container.classed('active', true); });
68848         }
68849     }
68850
68851
68852     combo.tags = function(tags) {
68853         if (isMulti || isSemi) {
68854             multiData = [];
68855
68856             if (isMulti) {
68857                 // Build multiData array containing keys already set..
68858                 Object.keys(tags).forEach(function(key) {
68859                     if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return;
68860
68861                     var suffix = key.substring(field.key.length);
68862                     multiData.push({
68863                         key: key,
68864                         value: displayValue(suffix)
68865                     });
68866                 });
68867
68868                 // Set keys for form-field modified (needed for undo and reset buttons)..
68869                 field.keys = lodash.map(multiData, 'key');
68870
68871             } else if (isSemi) {
68872                 var arr = lodash.compact(lodash.uniq((tags[field.key] || '').split(';')));
68873                 multiData = arr.map(function(key) {
68874                     return {
68875                         key: key,
68876                         value: displayValue(key)
68877                     };
68878                 });
68879             }
68880
68881             // Exclude existing multikeys from combo options..
68882             var available = objectDifference(comboData, multiData);
68883             combobox.data(available);
68884
68885             // Hide 'Add' button if this field uses fixed set of
68886             // translateable optstrings and they're all currently used..
68887             container.selectAll('.combobox-input, .combobox-caret')
68888                 .classed('hide', optstrings && !available.length);
68889
68890
68891             // Render chips
68892             var chips = container.selectAll('.chips')
68893                 .data(multiData);
68894
68895             chips.exit()
68896                 .remove();
68897
68898             var enter = chips.enter()
68899                 .insert('li', 'input')
68900                 .attr('class', 'chips');
68901
68902             enter.append('span');
68903             enter.append('a');
68904
68905             chips = chips.merge(enter);
68906
68907             chips.select('span')
68908                 .text(function(d) { return d.value; });
68909
68910             chips.select('a')
68911                 .on('click', removeMultikey)
68912                 .attr('class', 'remove')
68913                 .text('×');
68914
68915         } else {
68916             utilGetSetValue(input, displayValue(tags[field.key]));
68917         }
68918     };
68919
68920
68921     combo.focus = function() {
68922         input.node().focus();
68923     };
68924
68925
68926     combo.entity = function(_) {
68927         if (!arguments.length) return entity;
68928         entity = _;
68929         return combo;
68930     };
68931
68932
68933     return utilRebind(combo, dispatch$$1, 'on');
68934 }
68935
68936 function uiFieldText(field, context) {
68937     var dispatch$$1 = dispatch('change'),
68938         nominatim = services.geocoder,
68939         input,
68940         entity;
68941
68942
68943     function i(selection$$1) {
68944         var fieldId = 'preset-input-' + field.id;
68945
68946         input = selection$$1.selectAll('input')
68947             .data([0]);
68948
68949         input = input.enter()
68950             .append('input')
68951             .attr('type', field.type)
68952             .attr('id', fieldId)
68953             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
68954             .call(utilNoAuto)
68955             .merge(input);
68956
68957         input
68958             .on('input', change(true))
68959             .on('blur', change())
68960             .on('change', change());
68961
68962         if (field.type === 'tel' && nominatim && entity) {
68963             var center = entity.extent(context.graph()).center();
68964             nominatim.countryCode(center, function (err, countryCode) {
68965                 if (err || !dataPhoneFormats[countryCode]) return;
68966                 selection$$1.selectAll('#' + fieldId)
68967                     .attr('placeholder', dataPhoneFormats[countryCode]);
68968             });
68969
68970         } else if (field.type === 'number') {
68971             input.attr('type', 'text');
68972
68973             var spinControl = selection$$1.selectAll('.spin-control')
68974                 .data([0]);
68975
68976             var enter = spinControl.enter()
68977                 .append('div')
68978                 .attr('class', 'spin-control');
68979
68980             enter
68981                 .append('button')
68982                 .datum(-1)
68983                 .attr('class', 'decrement')
68984                 .attr('tabindex', -1);
68985
68986             enter
68987                 .append('button')
68988                 .datum(1)
68989                 .attr('class', 'increment')
68990                 .attr('tabindex', -1);
68991
68992             spinControl = spinControl
68993                 .merge(enter);
68994
68995             spinControl.selectAll('button')
68996                 .on('click', function(d) {
68997                     event.preventDefault();
68998                     var num = parseInt(input.node().value || 0, 10);
68999                     if (!isNaN(num)) input.node().value = num + d;
69000                     change()();
69001                 });
69002         }
69003     }
69004
69005
69006     function change(onInput) {
69007         return function() {
69008             var t$$1 = {};
69009             t$$1[field.key] = utilGetSetValue(input) || undefined;
69010             dispatch$$1.call('change', this, t$$1, onInput);
69011         };
69012     }
69013
69014
69015     i.entity = function(_) {
69016         if (!arguments.length) return entity;
69017         entity = _;
69018         return i;
69019     };
69020
69021
69022     i.tags = function(tags) {
69023         utilGetSetValue(input, tags[field.key] || '');
69024     };
69025
69026
69027     i.focus = function() {
69028         var node = input.node();
69029         if (node) node.focus();
69030     };
69031
69032     return utilRebind(i, dispatch$$1, 'on');
69033 }
69034
69035 function uiFieldAccess(field, context) {
69036     var dispatch$$1 = dispatch('change'),
69037         items;
69038
69039     function access(selection$$1) {
69040         var wrap = selection$$1.selectAll('.preset-input-wrap')
69041             .data([0]);
69042
69043         wrap = wrap.enter()
69044             .append('div')
69045             .attr('class', 'cf preset-input-wrap')
69046             .append('ul')
69047             .merge(wrap);
69048
69049         var list = wrap.selectAll('ul')
69050             .data([0]);
69051
69052         list = list.enter()
69053             .append('ul')
69054             .merge(list);
69055
69056
69057         items = list.selectAll('li')
69058             .data(field.keys);
69059
69060         // Enter
69061         var enter = items.enter()
69062             .append('li')
69063             .attr('class', function(d) { return 'cf preset-access-' + d; });
69064
69065         enter
69066             .append('span')
69067             .attr('class', 'col6 label preset-label-access')
69068             .attr('for', function(d) { return 'preset-input-access-' + d; })
69069             .text(function(d) { return field.t('types.' + d); });
69070
69071         enter
69072             .append('div')
69073             .attr('class', 'col6 preset-input-access-wrap')
69074             .append('input')
69075             .attr('type', 'text')
69076             .attr('class', 'preset-input-access')
69077             .attr('id', function(d) { return 'preset-input-access-' + d; })
69078             .call(utilNoAuto)
69079             .each(function(d) {
69080                 select(this)
69081                     .call(d3combobox()
69082                         .container(context.container())
69083                         .data(access.options(d))
69084                     );
69085             });
69086
69087
69088         // Update
69089         items = items.merge(enter);
69090
69091         wrap.selectAll('.preset-input-access')
69092             .on('change', change)
69093             .on('blur', change);
69094     }
69095
69096
69097     function change(d) {
69098         var tag = {};
69099         tag[d] = utilGetSetValue(select(this)) || undefined;
69100         dispatch$$1.call('change', this, tag);
69101     }
69102
69103
69104     access.options = function(type) {
69105         var options = ['no', 'permissive', 'private', 'destination'];
69106
69107         if (type !== 'access') {
69108             options.unshift('yes');
69109             options.push('designated');
69110
69111             if (type === 'bicycle') {
69112                 options.push('dismount');
69113             }
69114         }
69115
69116         return options.map(function(option) {
69117             return {
69118                 title: field.t('options.' + option + '.description'),
69119                 value: option
69120             };
69121         });
69122     };
69123
69124
69125     var placeholders = {
69126         footway: {
69127             foot: 'designated',
69128             motor_vehicle: 'no'
69129         },
69130         steps: {
69131             foot: 'yes',
69132             motor_vehicle: 'no',
69133             bicycle: 'no',
69134             horse: 'no'
69135         },
69136         pedestrian: {
69137             foot: 'yes',
69138             motor_vehicle: 'no'
69139         },
69140         cycleway: {
69141             motor_vehicle: 'no',
69142             bicycle: 'designated'
69143         },
69144         bridleway: {
69145             motor_vehicle: 'no',
69146             horse: 'designated'
69147         },
69148         path: {
69149             foot: 'yes',
69150             motor_vehicle: 'no',
69151             bicycle: 'yes',
69152             horse: 'yes'
69153         },
69154         motorway: {
69155             foot: 'no',
69156             motor_vehicle: 'yes',
69157             bicycle: 'no',
69158             horse: 'no'
69159         },
69160         trunk: {
69161             motor_vehicle: 'yes'
69162         },
69163         primary: {
69164             foot: 'yes',
69165             motor_vehicle: 'yes',
69166             bicycle: 'yes',
69167             horse: 'yes'
69168         },
69169         secondary: {
69170             foot: 'yes',
69171             motor_vehicle: 'yes',
69172             bicycle: 'yes',
69173             horse: 'yes'
69174         },
69175         tertiary: {
69176             foot: 'yes',
69177             motor_vehicle: 'yes',
69178             bicycle: 'yes',
69179             horse: 'yes'
69180         },
69181         residential: {
69182             foot: 'yes',
69183             motor_vehicle: 'yes',
69184             bicycle: 'yes',
69185             horse: 'yes'
69186         },
69187         unclassified: {
69188             foot: 'yes',
69189             motor_vehicle: 'yes',
69190             bicycle: 'yes',
69191             horse: 'yes'
69192         },
69193         service: {
69194             foot: 'yes',
69195             motor_vehicle: 'yes',
69196             bicycle: 'yes',
69197             horse: 'yes'
69198         },
69199         motorway_link: {
69200             foot: 'no',
69201             motor_vehicle: 'yes',
69202             bicycle: 'no',
69203             horse: 'no'
69204         },
69205         trunk_link: {
69206             motor_vehicle: 'yes'
69207         },
69208         primary_link: {
69209             foot: 'yes',
69210             motor_vehicle: 'yes',
69211             bicycle: 'yes',
69212             horse: 'yes'
69213         },
69214         secondary_link: {
69215             foot: 'yes',
69216             motor_vehicle: 'yes',
69217             bicycle: 'yes',
69218             horse: 'yes'
69219         },
69220         tertiary_link: {
69221             foot: 'yes',
69222             motor_vehicle: 'yes',
69223             bicycle: 'yes',
69224             horse: 'yes'
69225         }
69226     };
69227
69228
69229     access.tags = function(tags) {
69230         utilGetSetValue(items.selectAll('.preset-input-access'),
69231             function(d) { return tags[d] || ''; })
69232             .attr('placeholder', function() {
69233                 return tags.access ? tags.access : field.placeholder();
69234             });
69235
69236         items.selectAll('#preset-input-access-access')
69237             .attr('placeholder', 'yes');
69238
69239         lodash.forEach(placeholders[tags.highway], function(v, k) {
69240             items.selectAll('#preset-input-access-' + k)
69241                 .attr('placeholder', function() { return (tags.access || v); });
69242         });
69243     };
69244
69245
69246     access.focus = function() {
69247         items.selectAll('.preset-input-access')
69248             .node().focus();
69249     };
69250
69251
69252     return utilRebind(access, dispatch$$1, 'on');
69253 }
69254
69255 function uiFieldAddress(field, context) {
69256     var dispatch$$1 = dispatch('init', 'change'),
69257         nominatim = services.geocoder,
69258         wrap = select(null),
69259         isInitialized = false,
69260         entity;
69261
69262     function getNearStreets() {
69263         var extent$$1 = entity.extent(context.graph()),
69264             l = extent$$1.center(),
69265             box = geoExtent$$1(l).padByMeters(200);
69266
69267         var streets = context.intersects(box)
69268             .filter(isAddressable)
69269             .map(function(d) {
69270                 var loc = context.projection([
69271                     (extent$$1[0][0] + extent$$1[1][0]) / 2,
69272                     (extent$$1[0][1] + extent$$1[1][1]) / 2]),
69273                     choice = geoChooseEdge(context.childNodes(d), loc, context.projection);
69274                 return {
69275                     title: d.tags.name,
69276                     value: d.tags.name,
69277                     dist: choice.distance
69278                 };
69279             })
69280             .sort(function(a, b) {
69281                 return a.dist - b.dist;
69282             });
69283
69284         return lodash.uniqBy(streets, 'value');
69285
69286         function isAddressable(d) {
69287             return d.tags.highway && d.tags.name && d.type === 'way';
69288         }
69289     }
69290
69291
69292     function getNearCities() {
69293         var extent$$1 = entity.extent(context.graph()),
69294             l = extent$$1.center(),
69295             box = geoExtent$$1(l).padByMeters(200);
69296
69297         var cities = context.intersects(box)
69298             .filter(isAddressable)
69299             .map(function(d) {
69300                 return {
69301                     title: d.tags['addr:city'] || d.tags.name,
69302                     value: d.tags['addr:city'] || d.tags.name,
69303                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
69304                 };
69305             })
69306             .sort(function(a, b) {
69307                 return a.dist - b.dist;
69308             });
69309
69310         return lodash.uniqBy(cities, 'value');
69311
69312
69313         function isAddressable(d) {
69314             if (d.tags.name &&
69315                 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
69316                 return true;
69317
69318             if (d.tags.place && d.tags.name && (
69319                     d.tags.place === 'city' ||
69320                     d.tags.place === 'town' ||
69321                     d.tags.place === 'village'))
69322                 return true;
69323
69324             if (d.tags['addr:city']) return true;
69325
69326             return false;
69327         }
69328     }
69329
69330     function getNearValues(key) {
69331         var extent$$1 = entity.extent(context.graph()),
69332             l = extent$$1.center(),
69333             box = geoExtent$$1(l).padByMeters(200);
69334
69335         var results = context.intersects(box)
69336             .filter(function hasTag(d) {
69337                 return d.tags[key];
69338             })
69339             .map(function(d) {
69340                 return {
69341                     title: d.tags[key],
69342                     value: d.tags[key],
69343                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
69344                 };
69345             })
69346             .sort(function(a, b) {
69347                 return a.dist - b.dist;
69348             });
69349
69350         return lodash.uniqBy(results, 'value');
69351     }
69352
69353
69354     function initCallback(err, countryCode) {
69355         if (err) return;
69356
69357         var addressFormat = lodash.find(dataAddressFormats, function (a) {
69358             return a && a.countryCodes && lodash.includes(a.countryCodes, countryCode.toLowerCase());
69359         }) || lodash.first(dataAddressFormats);
69360
69361         var widths = addressFormat.widths || {
69362             housenumber: 1/3, street: 2/3,
69363             city: 2/3, state: 1/4, postcode: 1/3
69364         };
69365
69366         function row(r) {
69367             // Normalize widths.
69368             var total = lodash.reduce(r, function(sum$$1, field) {
69369                 return sum$$1 + (widths[field] || 0.5);
69370             }, 0);
69371
69372             return r.map(function (field) {
69373                 return {
69374                     id: field,
69375                     width: (widths[field] || 0.5) / total
69376                 };
69377             });
69378         }
69379
69380         wrap.selectAll('div.addr-row')
69381             .data(addressFormat.format)
69382             .enter()
69383             .append('div')
69384             .attr('class', 'addr-row')
69385             .selectAll('input')
69386             .data(row)
69387             .enter()
69388             .append('input')
69389             .property('type', 'text')
69390             .attr('placeholder', function (d) {
69391                 var localkey = d.id + '!' + countryCode.toLowerCase(),
69392                     tkey = field.strings.placeholders[localkey] ? localkey : d.id;
69393                 return field.t('placeholders.' + tkey);
69394             })
69395             .attr('class', function (d) { return 'addr-' + d.id; })
69396             .call(utilNoAuto)
69397             .style('width', function (d) { return d.width * 100 + '%'; });
69398
69399         // Update
69400
69401         // setup dropdowns for common address tags
69402         var dropdowns = addressFormat.dropdowns || [
69403             'city', 'county', 'country', 'district', 'hamlet',
69404             'neighbourhood', 'place', 'postcode', 'province',
69405             'quarter', 'state', 'street', 'subdistrict', 'suburb'
69406         ];
69407
69408         // If fields exist for any of these tags, create dropdowns to pick nearby values..
69409         dropdowns.forEach(function(tag) {
69410             var nearValues = (tag === 'street') ? getNearStreets
69411                     : (tag === 'city') ? getNearCities
69412                     : getNearValues;
69413
69414             wrap.selectAll('input.addr-' + tag)
69415                 .call(d3combobox()
69416                     .container(context.container())
69417                     .minItems(1)
69418                     .fetcher(function(value, callback) {
69419                         callback(nearValues('addr:' + tag));
69420                     })
69421                 );
69422         });
69423
69424         wrap.selectAll('input')
69425             .on('blur', change())
69426             .on('change', change());
69427
69428         wrap.selectAll('input:not(.combobox-input)')
69429             .on('input', change(true));
69430
69431         dispatch$$1.call('init');
69432         isInitialized = true;
69433     }
69434
69435
69436     function address(selection$$1) {
69437         isInitialized = false;
69438
69439         wrap = selection$$1.selectAll('.preset-input-wrap')
69440             .data([0]);
69441
69442         wrap = wrap.enter()
69443             .append('div')
69444             .attr('class', 'preset-input-wrap')
69445             .merge(wrap);
69446
69447         if (nominatim && entity) {
69448             var center = entity.extent(context.graph()).center();
69449             nominatim.countryCode(center, initCallback);
69450         }
69451     }
69452
69453
69454     function change(onInput) {
69455         return function() {
69456             var tags = {};
69457
69458             wrap.selectAll('input')
69459                 .each(function (field) {
69460                     tags['addr:' + field.id] = this.value || undefined;
69461                 });
69462
69463             dispatch$$1.call('change', this, tags, onInput);
69464         };
69465     }
69466
69467
69468     function updateTags(tags) {
69469         utilGetSetValue(wrap.selectAll('input'), function (field) {
69470             return tags['addr:' + field.id] || '';
69471         });
69472     }
69473
69474
69475     address.entity = function(_) {
69476         if (!arguments.length) return entity;
69477         entity = _;
69478         return address;
69479     };
69480
69481
69482     address.tags = function(tags) {
69483         if (isInitialized) {
69484             updateTags(tags);
69485         } else {
69486             dispatch$$1.on('init', function () {
69487                 dispatch$$1.on('init', null);
69488                 updateTags(tags);
69489             });
69490         }
69491     };
69492
69493
69494     address.focus = function() {
69495         var node = wrap.selectAll('input').node();
69496         if (node) node.focus();
69497     };
69498
69499
69500     return utilRebind(address, dispatch$$1, 'on');
69501 }
69502
69503 function uiFieldCycleway(field, context) {
69504     var dispatch$$1 = dispatch('change'),
69505         items = select(null);
69506
69507
69508     function cycleway(selection$$1) {
69509
69510         function stripcolon(s) {
69511             return s.replace(':', '');
69512         }
69513
69514
69515         var wrap = selection$$1.selectAll('.preset-input-wrap')
69516             .data([0]);
69517
69518         wrap = wrap.enter()
69519             .append('div')
69520             .attr('class', 'cf preset-input-wrap')
69521             .merge(wrap);
69522
69523
69524         var div = wrap.selectAll('ul')
69525             .data([0]);
69526
69527         div = div.enter()
69528             .append('ul')
69529             .merge(div);
69530
69531
69532         items = div.selectAll('li')
69533             .data(field.keys);
69534
69535         var enter = items.enter()
69536             .append('li')
69537             .attr('class', function(d) { return 'cf preset-cycleway-' + stripcolon(d); });
69538
69539         enter
69540             .append('span')
69541             .attr('class', 'col6 label preset-label-cycleway')
69542             .attr('for', function(d) { return 'preset-input-cycleway-' + stripcolon(d); })
69543             .text(function(d) { return field.t('types.' + d); });
69544
69545         enter
69546             .append('div')
69547             .attr('class', 'col6 preset-input-cycleway-wrap')
69548             .append('input')
69549             .attr('type', 'text')
69550             .attr('class', function(d) { return 'preset-input-cycleway preset-input-' + stripcolon(d); })
69551             .call(utilNoAuto)
69552             .each(function(d) {
69553                 select(this)
69554                     .call(d3combobox()
69555                         .container(context.container())
69556                         .data(cycleway.options(d))
69557                     );
69558             });
69559
69560
69561         // Update
69562         wrap.selectAll('.preset-input-cycleway')
69563             .on('change', change)
69564             .on('blur', change);
69565     }
69566
69567
69568     function change() {
69569         var left = utilGetSetValue(select('.preset-input-cyclewayleft')),
69570             right = utilGetSetValue(select('.preset-input-cyclewayright')),
69571             tag = {};
69572
69573         if (left === 'none' || left === '') { left = undefined; }
69574         if (right === 'none' || right === '') { right = undefined; }
69575
69576         // Always set both left and right as changing one can affect the other
69577         tag = {
69578             cycleway: undefined,
69579             'cycleway:left': left,
69580             'cycleway:right': right
69581         };
69582
69583         // If the left and right tags match, use the cycleway tag to tag both
69584         // sides the same way
69585         if (left === right) {
69586             tag = {
69587                 cycleway: left,
69588                 'cycleway:left': undefined,
69589                 'cycleway:right': undefined
69590             };
69591         }
69592
69593         dispatch$$1.call('change', this, tag);
69594     }
69595
69596
69597     cycleway.options = function() {
69598         return keys(field.strings.options).map(function(option) {
69599             return {
69600                 title: field.t('options.' + option + '.description'),
69601                 value: option
69602             };
69603         });
69604     };
69605
69606
69607     cycleway.tags = function(tags) {
69608         utilGetSetValue(items.selectAll('.preset-input-cycleway'), function(d) {
69609                 // If cycleway is set, always return that
69610                 if (tags.cycleway) {
69611                     return tags.cycleway;
69612                 }
69613                 return tags[d] || '';
69614             })
69615             .attr('placeholder', field.placeholder());
69616     };
69617
69618
69619     cycleway.focus = function() {
69620         items.selectAll('.preset-input-cycleway')
69621             .node().focus();
69622     };
69623
69624
69625     return utilRebind(cycleway, dispatch$$1, 'on');
69626 }
69627
69628 function uiFieldLanes(field, context) {
69629     var dispatch$$1 = dispatch('change'),
69630         LANE_WIDTH = 40,
69631         LANE_HEIGHT = 200,
69632         wayID,
69633         lanesData;
69634
69635     function lanes(selection$$1) {
69636         lanesData = context.entity(wayID).lanes();
69637
69638         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
69639             selection$$1.call(lanes.off);
69640             return;
69641         }
69642
69643         var wrap = selection$$1.selectAll('.preset-input-wrap')
69644             .data([0]);
69645
69646         wrap = wrap.enter()
69647             .append('div')
69648             .attr('class', 'preset-input-wrap')
69649             .merge(wrap);
69650
69651         var surface =  wrap.selectAll('.surface')
69652             .data([0]);
69653
69654         var d = utilGetDimensions(wrap);
69655         var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
69656
69657         surface = surface.enter()
69658             .append('svg')
69659             .attr('width', d[0])
69660             .attr('height', 300)
69661             .attr('class', 'surface')
69662             .merge(surface);
69663
69664
69665         var lanesSelection = surface.selectAll('.lanes')
69666             .data([0]);
69667
69668         lanesSelection = lanesSelection.enter()
69669             .append('g')
69670             .attr('class', 'lanes')
69671             .merge(lanesSelection);
69672
69673         lanesSelection
69674             .attr('transform', function () {
69675                 return 'translate(' + (freeSpace / 2) + ', 0)';
69676             });
69677
69678
69679         var lane = lanesSelection.selectAll('.lane')
69680            .data(lanesData.lanes);
69681
69682         lane.exit()
69683             .remove();
69684
69685         var enter = lane.enter()
69686             .append('g')
69687             .attr('class', 'lane');
69688
69689         enter
69690             .append('g')
69691             .append('rect')
69692             .attr('y', 50)
69693             .attr('width', LANE_WIDTH)
69694             .attr('height', LANE_HEIGHT);
69695
69696         enter
69697             .append('g')
69698             .attr('class', 'forward')
69699             .append('text')
69700             .attr('y', 40)
69701             .attr('x', 14)
69702             .text('▲');
69703
69704         enter
69705             .append('g')
69706             .attr('class', 'bothways')
69707             .append('text')
69708             .attr('y', 40)
69709             .attr('x', 14)
69710             .text('▲▼');
69711
69712         enter
69713             .append('g')
69714             .attr('class', 'backward')
69715             .append('text')
69716             .attr('y', 40)
69717             .attr('x', 14)
69718             .text('▼');
69719
69720
69721         lane = lane
69722             .merge(enter);
69723
69724         lane
69725             .attr('transform', function(d) {
69726                 return 'translate(' + (LANE_WIDTH * d.index * 1.5) + ', 0)';
69727             });
69728
69729         lane.select('.forward')
69730             .style('visibility', function(d) {
69731                 return d.direction === 'forward' ? 'visible' : 'hidden';
69732             });
69733
69734         lane.select('.bothways')
69735             .style('visibility', function(d) {
69736                 return d.direction === 'bothways' ? 'visible' : 'hidden';
69737             });
69738
69739         lane.select('.backward')
69740             .style('visibility', function(d) {
69741                 return d.direction === 'backward' ? 'visible' : 'hidden';
69742             });
69743     }
69744
69745
69746     lanes.entity = function(_) {
69747         if (!wayID || wayID !== _.id) {
69748             wayID = _.id;
69749         }
69750     };
69751
69752     lanes.tags = function() {};
69753     lanes.focus = function() {};
69754     lanes.off = function() {};
69755
69756     return utilRebind(lanes, dispatch$$1, 'on');
69757 }
69758
69759 function uiFieldLocalized(field, context) {
69760     var dispatch$$1 = dispatch('change', 'input'),
69761         wikipedia = services.wikipedia,
69762         input = select(null),
69763         localizedInputs = select(null),
69764         wikiTitles,
69765         entity;
69766
69767
69768     function localized(selection$$1) {
69769         input = selection$$1.selectAll('.localized-main')
69770             .data([0]);
69771
69772         input = input.enter()
69773             .append('input')
69774             .attr('type', 'text')
69775             .attr('id', 'preset-input-' + field.id)
69776             .attr('class', 'localized-main')
69777             .attr('placeholder', field.placeholder())
69778             .call(utilNoAuto)
69779             .merge(input);
69780
69781         if (field.id === 'name') {
69782             var preset = context.presets().match(entity, context.graph());
69783             input
69784                 .call(d3combobox()
69785                     .container(context.container())
69786                     .fetcher(utilSuggestNames(preset, dataSuggestions))
69787                 );
69788         }
69789
69790         input
69791             .on('input', change(true))
69792             .on('blur', change())
69793             .on('change', change());
69794
69795
69796         var translateButton = selection$$1.selectAll('.localized-add')
69797             .data([0]);
69798
69799         translateButton = translateButton.enter()
69800             .append('button')
69801             .attr('class', 'button-input-action localized-add minor')
69802             .attr('tabindex', -1)
69803             .call(svgIcon('#icon-plus'))
69804             .call(tooltip()
69805                 .title(t('translate.translate'))
69806                 .placement('left'))
69807             .merge(translateButton);
69808
69809         translateButton
69810             .on('click', addNew);
69811
69812
69813         localizedInputs = selection$$1.selectAll('.localized-wrap')
69814             .data([0]);
69815
69816         localizedInputs = localizedInputs.enter().append('div')
69817             .attr('class', 'localized-wrap')
69818             .merge(localizedInputs);
69819     }
69820
69821
69822     function addNew() {
69823         event.preventDefault();
69824         var data$$1 = localizedInputs.selectAll('div.entry').data();
69825         var defaultLang = utilDetect().locale.toLowerCase().split('-')[0];
69826         var langExists = lodash.find(data$$1, function(datum) { return datum.lang === defaultLang;});
69827         var isLangEn = defaultLang.indexOf('en') > -1;
69828         if (isLangEn || langExists) {
69829             defaultLang = '';
69830         }
69831         data$$1.push({ lang: defaultLang, value: '' });
69832         localizedInputs.call(render, data$$1);
69833     }
69834
69835
69836     function change(onInput) {
69837         return function() {
69838             var t$$1 = {};
69839             t$$1[field.key] = utilGetSetValue(select(this)) || undefined;
69840             dispatch$$1.call('change', this, t$$1, onInput);
69841         };
69842     }
69843
69844
69845     function key(lang) {
69846         return field.key + ':' + lang;
69847     }
69848
69849
69850     function changeLang(d) {
69851         var lang = utilGetSetValue(select(this)),
69852             t$$1 = {},
69853             language = lodash.find(dataWikipedia, function(d) {
69854                 return d[0].toLowerCase() === lang.toLowerCase() ||
69855                     d[1].toLowerCase() === lang.toLowerCase();
69856             });
69857
69858         if (language) lang = language[2];
69859
69860         if (d.lang && d.lang !== lang) {
69861             t$$1[key(d.lang)] = undefined;
69862         }
69863
69864         var value = utilGetSetValue(select(this.parentNode)
69865             .selectAll('.localized-value'));
69866
69867         if (lang && value) {
69868             t$$1[key(lang)] = value;
69869         } else if (lang && wikiTitles && wikiTitles[d.lang]) {
69870             t$$1[key(lang)] = wikiTitles[d.lang];
69871         }
69872
69873         d.lang = lang;
69874         dispatch$$1.call('change', this, t$$1);
69875     }
69876
69877
69878     function changeValue(d) {
69879         if (!d.lang) return;
69880         var t$$1 = {};
69881         t$$1[key(d.lang)] = utilGetSetValue(select(this)) || undefined;
69882         dispatch$$1.call('change', this, t$$1);
69883     }
69884
69885
69886     function fetcher(value, cb) {
69887         var v = value.toLowerCase();
69888
69889         cb(dataWikipedia.filter(function(d) {
69890             return d[0].toLowerCase().indexOf(v) >= 0 ||
69891             d[1].toLowerCase().indexOf(v) >= 0 ||
69892             d[2].toLowerCase().indexOf(v) >= 0;
69893         }).map(function(d) {
69894             return { value: d[1] };
69895         }));
69896     }
69897
69898
69899     function render(selection$$1, data$$1) {
69900         var wraps = selection$$1.selectAll('div.entry').
69901             data(data$$1, function(d) { return d.lang; });
69902
69903         wraps.exit()
69904             .transition()
69905             .duration(200)
69906             .style('max-height','0px')
69907             .style('opacity', '0')
69908             .style('top','-10px')
69909             .remove();
69910
69911         var innerWrap = wraps.enter()
69912             .insert('div', ':first-child');
69913
69914         innerWrap.attr('class', 'entry')
69915             .each(function() {
69916                 var wrap = select(this);
69917                 var langcombo = d3combobox()
69918                     .container(context.container())
69919                     .fetcher(fetcher)
69920                     .minItems(0);
69921
69922                 var label = wrap
69923                     .append('label')
69924                     .attr('class','form-label')
69925                     .text(t('translate.localized_translation_label'))
69926                     .attr('for','localized-lang');
69927
69928                 label
69929                     .append('button')
69930                     .attr('class', 'minor remove')
69931                     .on('click', function(d){
69932                         event.preventDefault();
69933                         var t$$1 = {};
69934                         t$$1[key(d.lang)] = undefined;
69935                         dispatch$$1.call('change', this, t$$1);
69936                         select(this.parentNode.parentNode)
69937                             .style('top','0')
69938                             .style('max-height','240px')
69939                             .transition()
69940                             .style('opacity', '0')
69941                             .style('max-height','0px')
69942                             .remove();
69943                     })
69944                     .call(svgIcon('#operation-delete'));
69945
69946                 wrap
69947                     .append('input')
69948                     .attr('class', 'localized-lang')
69949                     .attr('type', 'text')
69950                     .attr('placeholder',t('translate.localized_translation_language'))
69951                     .on('blur', changeLang)
69952                     .on('change', changeLang)
69953                     .call(langcombo);
69954
69955                 wrap
69956                     .append('input')
69957                     .on('blur', changeValue)
69958                     .on('change', changeValue)
69959                     .attr('type', 'text')
69960                     .attr('placeholder', t('translate.localized_translation_name'))
69961                     .attr('class', 'localized-value');
69962             });
69963
69964         innerWrap
69965             .style('margin-top', '0px')
69966             .style('max-height', '0px')
69967             .style('opacity', '0')
69968             .transition()
69969             .duration(200)
69970             .style('margin-top', '10px')
69971             .style('max-height', '240px')
69972             .style('opacity', '1')
69973             .on('end', function() {
69974                 select(this)
69975                     .style('max-height', '')
69976                     .style('overflow', 'visible');
69977             });
69978
69979
69980         var entry = selection$$1.selectAll('.entry');
69981
69982         utilGetSetValue(entry.select('.localized-lang'), function(d) {
69983                 var lang = lodash.find(dataWikipedia, function(lang) { return lang[2] === d.lang; });
69984                 return lang ? lang[1] : d.lang;
69985             });
69986
69987         utilGetSetValue(entry.select('.localized-value'),
69988             function(d) { return d.value; });
69989     }
69990
69991
69992     localized.tags = function(tags) {
69993         // Fetch translations from wikipedia
69994         if (tags.wikipedia && !wikiTitles) {
69995             wikiTitles = {};
69996             var wm = tags.wikipedia.match(/([^:]+):(.+)/);
69997             if (wm && wm[0] && wm[1]) {
69998                 wikipedia.translations(wm[1], wm[2], function(d) {
69999                     wikiTitles = d;
70000                 });
70001             }
70002         }
70003
70004         utilGetSetValue(input, tags[field.key] || '');
70005
70006         var postfixed = [], k, m;
70007         for (k in tags) {
70008             m = k.match(/^(.*):([a-zA-Z_-]+)$/);
70009             if (m && m[1] === field.key && m[2]) {
70010                 postfixed.push({ lang: m[2], value: tags[k] });
70011             }
70012         }
70013
70014         localizedInputs.call(render, postfixed.reverse());
70015     };
70016
70017
70018     localized.focus = function() {
70019         input.node().focus();
70020     };
70021
70022
70023     localized.entity = function(_) {
70024         if (!arguments.length) return entity;
70025         entity = _;
70026         return localized;
70027     };
70028
70029     return utilRebind(localized, dispatch$$1, 'on');
70030 }
70031
70032 function uiFieldMaxspeed(field, context) {
70033     var dispatch$$1 = dispatch('change'),
70034         entity,
70035         isImperial,
70036         unitInput = select(null),
70037         input = select(null),
70038         combobox;
70039
70040     var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
70041         imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
70042
70043
70044     function maxspeed(selection$$1) {
70045         combobox = d3combobox()
70046             .container(context.container());
70047
70048         var unitCombobox = d3combobox()
70049             .container(context.container())
70050             .data(['km/h', 'mph'].map(comboValues));
70051
70052         input = selection$$1.selectAll('#preset-input-' + field.id)
70053             .data([0]);
70054
70055         input = input.enter()
70056             .append('input')
70057             .attr('type', 'text')
70058             .attr('id', 'preset-input-' + field.id)
70059             .attr('placeholder', field.placeholder())
70060             .call(utilNoAuto)
70061             .call(combobox)
70062             .merge(input);
70063
70064         input
70065             .on('change', change)
70066             .on('blur', change);
70067
70068         var childNodes = context.graph().childNodes(context.entity(entity.id)),
70069             loc = childNodes[~~(childNodes.length/2)].loc;
70070
70071         isImperial = lodash.some(dataImperial.features, function(f) {
70072             return lodash.some(f.geometry.coordinates, function(d) {
70073                 return geoPointInPolygon(loc, d);
70074             });
70075         });
70076
70077         unitInput = selection$$1.selectAll('input.maxspeed-unit')
70078             .data([0]);
70079
70080         unitInput = unitInput.enter()
70081             .append('input')
70082             .attr('type', 'text')
70083             .attr('class', 'maxspeed-unit')
70084             .call(unitCombobox)
70085             .merge(unitInput);
70086
70087         unitInput
70088             .on('blur', changeUnits)
70089             .on('change', changeUnits);
70090
70091
70092         function changeUnits() {
70093             isImperial = utilGetSetValue(unitInput) === 'mph';
70094             utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
70095             setSuggestions();
70096             change();
70097         }
70098     }
70099
70100
70101     function setSuggestions() {
70102         combobox.data((isImperial ? imperialValues : metricValues).map(comboValues));
70103         utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
70104     }
70105
70106
70107     function comboValues(d) {
70108         return {
70109             value: d.toString(),
70110             title: d.toString()
70111         };
70112     }
70113
70114
70115     function change() {
70116         var tag = {},
70117             value = utilGetSetValue(input);
70118
70119         if (!value) {
70120             tag[field.key] = undefined;
70121         } else if (isNaN(value) || !isImperial) {
70122             tag[field.key] = value;
70123         } else {
70124             tag[field.key] = value + ' mph';
70125         }
70126
70127         dispatch$$1.call('change', this, tag);
70128     }
70129
70130
70131     maxspeed.tags = function(tags) {
70132         var value = tags[field.key];
70133
70134         if (value && value.indexOf('mph') >= 0) {
70135             value = parseInt(value, 10);
70136             isImperial = true;
70137         } else if (value) {
70138             isImperial = false;
70139         }
70140
70141         setSuggestions();
70142         utilGetSetValue(input, value || '');
70143     };
70144
70145
70146     maxspeed.focus = function() {
70147         input.node().focus();
70148     };
70149
70150
70151     maxspeed.entity = function(_) {
70152         entity = _;
70153     };
70154
70155
70156     return utilRebind(maxspeed, dispatch$$1, 'on');
70157 }
70158
70159 function uiFieldRadio(field, context) {
70160     var dispatch$$1 = dispatch('change'),
70161         taginfo = services.taginfo,
70162         placeholder = select(null),
70163         wrap = select(null),
70164         labels = select(null),
70165         radios = select(null),
70166         typeInput = select(null),
70167         layerInput = select(null),
70168         oldType = {},
70169         entity;
70170
70171
70172     function selectedKey() {
70173         var selector$$1 = '.form-field-structure .toggle-list label.active input',
70174             node = selectAll(selector$$1);
70175         return !node.empty() && node.datum();
70176     }
70177
70178     // returns the tag value for a display value
70179     function tagValue(dispVal) {
70180         dispVal = snake(clean(dispVal || ''));
70181         return dispVal.toLowerCase() || 'yes';
70182     }
70183
70184     // returns the display value for a tag value
70185     function displayValue(tagVal) {
70186         tagVal = tagVal || '';
70187         return tagVal.toLowerCase() === 'yes' ? '' : unsnake(tagVal);
70188     }
70189
70190     function snake(s) {
70191         return s.replace(/\s+/g, '_');
70192     }
70193
70194     function unsnake(s) {
70195         return s.replace(/_+/g, ' ');
70196     }
70197
70198     function clean(s) {
70199         return s.split(';')
70200             .map(function(s) { return s.trim(); })
70201             .join(';');
70202     }
70203
70204
70205     function radio(selection$$1) {
70206         selection$$1.classed('preset-radio', true);
70207
70208         wrap = selection$$1.selectAll('.preset-input-wrap')
70209             .data([0]);
70210
70211         var enter = wrap.enter()
70212             .append('div')
70213             .attr('class', 'preset-input-wrap toggle-list');
70214
70215         enter
70216             .append('span')
70217             .attr('class', 'placeholder');
70218
70219         wrap = wrap
70220             .merge(enter);
70221
70222
70223         placeholder = wrap.selectAll('.placeholder');
70224
70225         labels = wrap.selectAll('label')
70226             .data(field.options || field.keys);
70227
70228         enter = labels.enter()
70229             .append('label');
70230
70231         enter
70232             .append('input')
70233             .attr('type', 'radio')
70234             .attr('name', field.id)
70235             .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
70236             .attr('checked', false);
70237
70238         enter
70239             .append('span')
70240             .text(function(d) { return field.t('options.' + d, { 'default': d }); });
70241
70242         labels = labels
70243             .merge(enter);
70244
70245         radios = labels.selectAll('input')
70246             .on('change', changeRadio);
70247     }
70248
70249
70250     function structureExtras(selection$$1) {
70251         var selected = selectedKey();
70252
70253         var extrasWrap = selection$$1.selectAll('.structure-extras-wrap')
70254                 .data(selected ? [0] : []);
70255
70256         extrasWrap.exit()
70257             .remove();
70258
70259         extrasWrap = extrasWrap.enter()
70260             .append('div')
70261             .attr('class', 'structure-extras-wrap')
70262             .merge(extrasWrap);
70263
70264         var list = extrasWrap.selectAll('ul')
70265             .data([0]);
70266
70267         list = list.enter()
70268             .append('ul')
70269             .merge(list);
70270
70271
70272         // Type
70273         var typeItem = list.selectAll('.structure-type-item')
70274             .data([0]);
70275
70276         var typeEnter = typeItem.enter()
70277             .append('li')
70278             .attr('class', 'cf structure-type-item');
70279
70280         typeEnter
70281             .append('span')
70282             .attr('class', 'col6 label structure-label-type')
70283             .attr('for', 'structure-input-type')
70284             .text(t('inspector.radio.structure.type'));
70285
70286         typeEnter
70287             .append('div')
70288             .attr('class', 'col6 structure-input-type-wrap')
70289             .append('input')
70290             .attr('type', 'text')
70291             .attr('class', 'structure-input-type')
70292             .attr('placeholder', t('inspector.radio.structure.default'))
70293             .call(utilNoAuto);
70294
70295         typeItem = typeItem
70296             .merge(typeEnter);
70297
70298         typeInput = typeItem.selectAll('.structure-input-type');
70299
70300         if (taginfo) {
70301             typeInput
70302                 .call(d3combobox()
70303                     .container(context.container())
70304                     .fetcher(typeFetcher)
70305                 );
70306         }
70307
70308         typeInput
70309             .on('change', changeType)
70310             .on('blur', changeType);
70311
70312
70313         // Layer
70314         var showLayer = (selected === 'bridge' || selected === 'tunnel');
70315
70316         var layerItem = list.selectAll('.structure-layer-item')
70317             .data(showLayer ? [0] : []);
70318
70319         layerItem.exit()
70320             .remove();
70321
70322         var layerEnter = layerItem.enter()
70323             .append('li')
70324             .attr('class', 'cf structure-layer-item');
70325
70326         layerEnter
70327             .append('span')
70328             .attr('class', 'col6 label structure-label-layer')
70329             .attr('for', 'structure-input-layer')
70330             .text(t('inspector.radio.structure.layer'));
70331
70332         layerEnter
70333             .append('div')
70334             .attr('class', 'col6 structure-input-layer-wrap')
70335             .append('input')
70336             .attr('type', 'text')
70337             .attr('class', 'structure-input-layer')
70338             .attr('placeholder', '0')
70339             .call(utilNoAuto);
70340
70341         var spin = layerEnter
70342             .append('div')
70343             .attr('class', 'spin-control');
70344
70345         spin
70346             .append('button')
70347             .datum(-1)
70348             .attr('class', 'decrement')
70349             .attr('tabindex', -1);
70350
70351         spin
70352             .append('button')
70353             .datum(1)
70354             .attr('class', 'increment')
70355             .attr('tabindex', -1);
70356
70357         layerItem = layerItem
70358             .merge(layerEnter);
70359
70360         layerInput = layerItem.selectAll('.structure-input-layer')
70361             .on('change', changeLayer)
70362             .on('blur', changeLayer);
70363
70364         layerItem.selectAll('button')
70365             .on('click', function(d) {
70366                 event.preventDefault();
70367                 var num = parseInt(layerInput.node().value || 0, 10);
70368                 if (!isNaN(num)) layerInput.node().value = num + d;
70369                 changeLayer();
70370             });
70371
70372     }
70373
70374
70375     function typeFetcher(q, callback) {
70376         taginfo.values({
70377             debounce: true,
70378             key: selectedKey(),
70379             query: q
70380         }, function(err, data) {
70381             if (err) return;
70382             var comboData = data.map(function(d) {
70383                 return {
70384                     key: d.value,
70385                     value: unsnake(d.value),
70386                     title: d.title
70387                 };
70388             });
70389             if (callback) callback(comboData);
70390         });
70391     }
70392
70393
70394     function changeType() {
70395         var key = selectedKey(),
70396             t$$1 = {};
70397
70398         if (!key) return;
70399         var val = tagValue(utilGetSetValue(typeInput));
70400         t$$1[key] = val;
70401         if (val !== 'no') oldType[key] = val;
70402         dispatch$$1.call('change', this, t$$1);
70403     }
70404
70405
70406     function changeLayer() {
70407         // note: don't use utilGetSetValue here because we want 0 to be falsy.
70408         var t$$1 = { layer: layerInput.node().value || undefined };
70409         dispatch$$1.call('change', this, t$$1);
70410     }
70411
70412
70413     function changeRadio() {
70414         var t$$1 = {},
70415             activeKey;
70416
70417         if (field.key) {
70418             t$$1[field.key] = undefined;
70419         }
70420
70421         radios.each(function(d) {
70422             var active$$1 = select(this).property('checked');
70423             if (active$$1) activeKey = d;
70424
70425             if (field.key) {
70426                 if (active$$1) t$$1[field.key] = d;
70427             } else {
70428                 var val = oldType[activeKey] || 'yes';
70429                 t$$1[d] = active$$1 ? val : undefined;
70430             }
70431         });
70432
70433         if (field.type === 'structureRadio') {
70434             if (activeKey === 'bridge') {
70435                 t$$1.layer = '1';
70436             } else if (activeKey === 'tunnel') {
70437                 t$$1.layer = '-1';
70438             } else {
70439                 t$$1.layer = undefined;
70440             }
70441         }
70442
70443         dispatch$$1.call('change', this, t$$1);
70444     }
70445
70446
70447     radio.tags = function(tags) {
70448         function checked(d) {
70449             if (field.key) {
70450                 return tags[field.key] === d;
70451             } else {
70452                 return !!(tags[d] && tags[d].toLowerCase() !== 'no');
70453             }
70454         }
70455
70456         labels.classed('active', checked);
70457         radios.property('checked', checked);
70458
70459         var selection$$1 = radios.filter(function() { return this.checked; });
70460         var typeVal = '';
70461
70462         if (selection$$1.empty()) {
70463             placeholder.text(t('inspector.none'));
70464         } else {
70465             placeholder.text(selection$$1.attr('value'));
70466             typeVal = oldType[selection$$1.datum()] = tags[selection$$1.datum()];
70467         }
70468
70469         if (field.type === 'structureRadio') {
70470             wrap.call(structureExtras);
70471             utilGetSetValue(typeInput, displayValue(typeVal) || '');
70472             utilGetSetValue(layerInput, tags.layer || '');
70473         }
70474     };
70475
70476
70477     radio.focus = function() {
70478         radios.node().focus();
70479     };
70480
70481
70482     radio.entity = function(_) {
70483         if (!arguments.length) return entity;
70484         entity = _;
70485         oldType = {};
70486         return radio;
70487     };
70488
70489
70490     return utilRebind(radio, dispatch$$1, 'on');
70491 }
70492
70493 function uiFieldRestrictions(field, context) {
70494     var dispatch$$1 = dispatch('change'),
70495         breathe = behaviorBreathe(context),
70496         hover = behaviorHover(context),
70497         initialized = false,
70498         vertexID,
70499         fromNodeID;
70500
70501
70502     function restrictions(selection$$1) {
70503         // if form field is hidden or has detached from dom, clean up.
70504         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
70505             selection$$1.call(restrictions.off);
70506             return;
70507         }
70508
70509         var wrap = selection$$1.selectAll('.preset-input-wrap')
70510             .data([0]);
70511
70512         var enter = wrap.enter()
70513             .append('div')
70514             .attr('class', 'preset-input-wrap');
70515
70516         enter
70517             .append('div')
70518             .attr('class', 'restriction-help');
70519
70520
70521         var intersection = osmIntersection(context.graph(), vertexID),
70522             graph = intersection.graph,
70523             vertex = graph.entity(vertexID),
70524             filter = utilFunctor(true),
70525             extent$$1 = geoExtent$$1(),
70526             projection$$1 = geoRawMercator();
70527
70528         var d = utilGetDimensions(wrap.merge(enter)),
70529             c = [d[0] / 2, d[1] / 2],
70530             z = 24;
70531
70532         projection$$1
70533             .scale(256 * Math.pow(2, z) / (2 * Math.PI));
70534
70535         var s = projection$$1(vertex.loc);
70536
70537         projection$$1
70538             .translate([c[0] - s[0], c[1] - s[1]])
70539             .clipExtent([[0, 0], d]);
70540
70541         var drawLayers = svgLayers(projection$$1, context).only('osm').dimensions(d),
70542             drawVertices = svgVertices$$1(projection$$1, context),
70543             drawLines = svgLines$$1(projection$$1, context),
70544             drawTurns = svgTurns(projection$$1, context);
70545
70546         enter
70547             .call(drawLayers);
70548
70549         wrap = wrap
70550             .merge(enter);
70551
70552         var surface = wrap.selectAll('.surface');
70553
70554         if (!enter.empty()) {
70555             initialized = true;
70556             surface
70557                 .call(breathe)
70558                 .call(hover);
70559         }
70560
70561         surface
70562             .call(utilSetDimensions, d)
70563             .call(drawVertices, graph, [vertex], filter, extent$$1, z)
70564             .call(drawLines, graph, intersection.ways, filter)
70565             .call(drawTurns, graph, intersection.turns(fromNodeID));
70566
70567         surface
70568             .on('click.restrictions', click)
70569             .on('mouseover.restrictions', mouseover)
70570             .on('mouseout.restrictions', mouseout);
70571
70572         surface
70573             .selectAll('.selected')
70574             .classed('selected', false);
70575
70576         if (fromNodeID) {
70577             surface
70578                 .selectAll('.' + intersection.highways[fromNodeID].id)
70579                 .classed('selected', true);
70580         }
70581
70582         mouseout();
70583
70584         context.history()
70585             .on('change.restrictions', render);
70586
70587         select(window)
70588             .on('resize.restrictions', function() {
70589                 utilSetDimensions(wrap, null);
70590                 render();
70591             });
70592
70593
70594         function click() {
70595             surface
70596                 .call(breathe.off)
70597                 .call(breathe);
70598
70599             var datum = event.target.__data__;
70600             if (datum instanceof osmEntity$$1) {
70601                 fromNodeID = intersection.adjacentNodeId(datum.id);
70602                 render();
70603             } else if (datum instanceof osmTurn) {
70604                 if (datum.restriction) {
70605                     context.perform(
70606                         actionUnrestrictTurn(datum, projection$$1),
70607                         t('operations.restriction.annotation.delete')
70608                     );
70609                 } else {
70610                     context.perform(
70611                         actionRestrictTurn(datum, projection$$1),
70612                         t('operations.restriction.annotation.create')
70613                     );
70614                 }
70615             }
70616         }
70617
70618
70619         function mouseover() {
70620             var datum = event.target.__data__;
70621             if (datum instanceof osmTurn) {
70622                 var graph = context.graph(),
70623                     presets = context.presets(),
70624                     preset;
70625
70626                 if (datum.restriction) {
70627                     preset = presets.match(graph.entity(datum.restriction), graph);
70628                 } else {
70629                     preset = presets.item('type/restriction/' +
70630                         osmInferRestriction(
70631                             graph,
70632                             datum.from,
70633                             datum.via,
70634                             datum.to,
70635                             projection$$1
70636                         )
70637                     );
70638                 }
70639
70640                 wrap.selectAll('.restriction-help')
70641                     .text(t('operations.restriction.help.' +
70642                         (datum.restriction ? 'toggle_off' : 'toggle_on'),
70643                         { restriction: preset.name() })
70644                     );
70645             }
70646         }
70647
70648
70649         function mouseout() {
70650             wrap.selectAll('.restriction-help')
70651                 .text(t('operations.restriction.help.' +
70652                     (fromNodeID ? 'toggle' : 'select'))
70653                 );
70654         }
70655
70656
70657         function render() {
70658             if (context.hasEntity(vertexID)) {
70659                 restrictions(selection$$1);
70660             }
70661         }
70662     }
70663
70664
70665     restrictions.entity = function(_) {
70666         if (!vertexID || vertexID !== _.id) {
70667             fromNodeID = null;
70668             vertexID = _.id;
70669         }
70670     };
70671
70672
70673     restrictions.tags = function() {};
70674     restrictions.focus = function() {};
70675
70676
70677     restrictions.off = function(selection$$1) {
70678         if (!initialized) return;
70679
70680         selection$$1.selectAll('.surface')
70681             .call(hover.off)
70682             .call(breathe.off)
70683             .on('click.restrictions', null)
70684             .on('mouseover.restrictions', null)
70685             .on('mouseout.restrictions', null);
70686
70687         context.history()
70688             .on('change.restrictions', null);
70689
70690         select(window)
70691             .on('resize.restrictions', null);
70692     };
70693
70694
70695     return utilRebind(restrictions, dispatch$$1, 'on');
70696 }
70697
70698 function uiFieldTextarea(field) {
70699     var dispatch$$1 = dispatch('change'),
70700         input = select(null);
70701
70702
70703     function textarea(selection$$1) {
70704         input = selection$$1.selectAll('textarea')
70705             .data([0]);
70706
70707         input = input.enter()
70708             .append('textarea')
70709             .attr('id', 'preset-input-' + field.id)
70710             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
70711             .attr('maxlength', 255)
70712             .call(utilNoAuto)
70713             .on('input', change(true))
70714             .on('blur', change())
70715             .on('change', change())
70716             .merge(input);
70717     }
70718
70719
70720     function change(onInput) {
70721         return function() {
70722             var t$$1 = {};
70723             t$$1[field.key] = utilGetSetValue(input) || undefined;
70724             dispatch$$1.call('change', this, t$$1, onInput);
70725         };
70726     }
70727
70728
70729     textarea.tags = function(tags) {
70730         utilGetSetValue(input, tags[field.key] || '');
70731     };
70732
70733
70734     textarea.focus = function() {
70735         input.node().focus();
70736     };
70737
70738
70739     return utilRebind(textarea, dispatch$$1, 'on');
70740 }
70741
70742 function uiFieldWikipedia(field, context) {
70743     var dispatch$$1 = dispatch('change'),
70744         wikipedia = services.wikipedia,
70745         wikidata = services.wikidata,
70746         link$$1 = select(null),
70747         lang = select(null),
70748         title = select(null),
70749         wikiURL = '',
70750         entity;
70751
70752
70753     function wiki(selection$$1) {
70754         var langcombo = d3combobox()
70755             .container(context.container())
70756             .fetcher(function(value, cb) {
70757                 var v = value.toLowerCase();
70758
70759                 cb(dataWikipedia.filter(function(d) {
70760                     return d[0].toLowerCase().indexOf(v) >= 0 ||
70761                         d[1].toLowerCase().indexOf(v) >= 0 ||
70762                         d[2].toLowerCase().indexOf(v) >= 0;
70763                 }).map(function(d) {
70764                     return { value: d[1] };
70765                 }));
70766             });
70767
70768         var titlecombo = d3combobox()
70769             .container(context.container())
70770             .fetcher(function(value, cb) {
70771                 if (!value) {
70772                     value = context.entity(entity.id).tags.name || '';
70773                 }
70774
70775                 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
70776                 searchfn(language()[2], value, function(query, data$$1) {
70777                     cb(data$$1.map(function(d) {
70778                         return { value: d };
70779                     }));
70780                 });
70781             });
70782
70783
70784         lang = selection$$1.selectAll('input.wiki-lang')
70785             .data([0]);
70786
70787         lang = lang.enter()
70788             .append('input')
70789             .attr('type', 'text')
70790             .attr('class', 'wiki-lang')
70791             .attr('placeholder', t('translate.localized_translation_language'))
70792             .call(utilNoAuto)
70793             .merge(lang);
70794
70795         utilGetSetValue(lang, language()[1]);
70796
70797         lang
70798             .call(langcombo)
70799             .on('blur', changeLang)
70800             .on('change', changeLang);
70801
70802
70803         title = selection$$1.selectAll('input.wiki-title')
70804             .data([0]);
70805
70806         title = title.enter()
70807             .append('input')
70808             .attr('type', 'text')
70809             .attr('class', 'wiki-title')
70810             .attr('id', 'preset-input-' + field.id)
70811             .call(utilNoAuto)
70812             .merge(title);
70813
70814         title
70815             .call(titlecombo)
70816             .on('blur', blur)
70817             .on('change', change);
70818
70819
70820         link$$1 = selection$$1.selectAll('.wiki-link')
70821             .data([0]);
70822
70823         link$$1 = link$$1.enter()
70824             .append('button')
70825             .attr('class', 'button-input-action wiki-link minor')
70826             .attr('tabindex', -1)
70827             .call(svgIcon('#icon-out-link'))
70828             .merge(link$$1);
70829
70830         link$$1
70831             .on('click', function() {
70832                 event.preventDefault();
70833                 if (wikiURL) window.open(wikiURL, '_blank');
70834             });
70835     }
70836
70837
70838     function language() {
70839         var value = utilGetSetValue(lang).toLowerCase();
70840         var locale = utilDetect().locale.toLowerCase();
70841         var localeLanguage;
70842         return lodash.find(dataWikipedia, function(d) {
70843             if (d[2] === locale) localeLanguage = d;
70844             return d[0].toLowerCase() === value ||
70845                 d[1].toLowerCase() === value ||
70846                 d[2] === value;
70847         }) || localeLanguage || ['English', 'English', 'en'];
70848     }
70849
70850
70851     function changeLang() {
70852         utilGetSetValue(lang, language()[1]);
70853         change(true);
70854     }
70855
70856
70857     function blur() {
70858         change(true);
70859     }
70860
70861
70862     function change(skipWikidata) {
70863         var value = utilGetSetValue(title),
70864             m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
70865             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
70866             syncTags = {};
70867
70868         if (l) {
70869             // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
70870             value = decodeURIComponent(m[2]).replace(/_/g, ' ');
70871             if (m[3]) {
70872                 var anchor;
70873                 try {
70874                     // Best-effort `anchordecode:` implementation
70875                     anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
70876                 } catch (e) {
70877                     anchor = decodeURIComponent(m[3]);
70878                 }
70879                 value += '#' + anchor.replace(/_/g, ' ');
70880             }
70881             value = value.slice(0, 1).toUpperCase() + value.slice(1);
70882             utilGetSetValue(lang, l[1]);
70883             utilGetSetValue(title, value);
70884         }
70885
70886         if (value) {
70887             syncTags.wikipedia = language()[2] + ':' + value;
70888         } else {
70889             syncTags.wikipedia = undefined;
70890             syncTags.wikidata = undefined;
70891         }
70892
70893         dispatch$$1.call('change', this, syncTags);
70894
70895
70896         if (skipWikidata || !value || !language()[2]) return;
70897
70898         // attempt asynchronous update of wikidata tag..
70899         var initGraph = context.graph(),
70900             initEntityId = entity.id;
70901
70902         wikidata.itemsByTitle(language()[2], value, function(title, data$$1) {
70903             // If graph has changed, we can't apply this update.
70904             if (context.graph() !== initGraph) return;
70905
70906             if (!data$$1 || !Object.keys(data$$1).length) return;
70907
70908             var qids = Object.keys(data$$1);
70909             var value = qids && lodash.find(qids, function(id) { return id.match(/^Q\d+$/); });
70910             var currTags = lodash.clone(context.entity(initEntityId).tags);
70911
70912             currTags.wikidata = value;
70913
70914             // Coalesce the update of wikidata tag into the previous tag change
70915             context.overwrite(
70916                 actionChangeTags(initEntityId, currTags),
70917                 context.history().undoAnnotation()
70918             );
70919
70920             // do not dispatch.call('change') here, because entity_editor
70921             // changeTags() is not intended to be called asynchronously
70922         });
70923     }
70924
70925
70926     wiki.tags = function(tags) {
70927         var value = tags[field.key] || '',
70928             m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
70929             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
70930             anchor = m && m[3];
70931
70932         // value in correct format
70933         if (l) {
70934             utilGetSetValue(lang, l[1]);
70935             utilGetSetValue(title, m[2] + (anchor ? ('#' + anchor) : ''));
70936             if (anchor) {
70937                 try {
70938                     // Best-effort `anchorencode:` implementation
70939                     anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
70940                 } catch (e) {
70941                     anchor = anchor.replace(/ /g, '_');
70942                 }
70943             }
70944             wikiURL = 'https://' + m[1] + '.wikipedia.org/wiki/' +
70945                 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : '');
70946
70947         // unrecognized value format
70948         } else {
70949             utilGetSetValue(title, value);
70950             if (value && value !== '') {
70951                 utilGetSetValue(lang, '');
70952                 wikiURL = 'https://en.wikipedia.org/wiki/Special:Search?search=' + value;
70953             } else {
70954                 wikiURL = '';
70955             }
70956         }
70957     };
70958
70959
70960     wiki.entity = function(_) {
70961         if (!arguments.length) return entity;
70962         entity = _;
70963         return wiki;
70964     };
70965
70966
70967     wiki.focus = function() {
70968         title.node().focus();
70969     };
70970
70971
70972     return utilRebind(wiki, dispatch$$1, 'on');
70973 }
70974
70975 var uiFields = {
70976     access: uiFieldAccess,
70977     address: uiFieldAddress,
70978     check: uiFieldCheck,
70979     combo: uiFieldCombo,
70980     cycleway: uiFieldCycleway,
70981     defaultCheck: uiFieldCheck,
70982     email: uiFieldText,
70983     lanes: uiFieldLanes,
70984     localized: uiFieldLocalized,
70985     maxspeed: uiFieldMaxspeed,
70986     multiCombo: uiFieldCombo,
70987     networkCombo: uiFieldCombo,
70988     number: uiFieldText,
70989     onewayCheck: uiFieldCheck,
70990     radio: uiFieldRadio,
70991     restrictions: uiFieldRestrictions,
70992     semiCombo: uiFieldCombo,
70993     structureRadio: uiFieldRadio,
70994     tel: uiFieldText,
70995     text: uiFieldText,
70996     textarea: uiFieldTextarea,
70997     typeCombo: uiFieldCombo,
70998     url: uiFieldText,
70999     wikipedia: uiFieldWikipedia
71000 };
71001
71002 function uiPreset(context) {
71003     var dispatch$$1 = dispatch('change'),
71004         expandedPreference = (context.storage('preset_fields.expanded') !== 'false'),
71005         state,
71006         fieldsArr,
71007         preset,
71008         tags,
71009         id;
71010
71011
71012     // Field Constructor
71013     function UIField(field, entity, show) {
71014         field = lodash.clone(field);
71015
71016         field.input = uiFields[field.type](field, context)
71017             .on('change', function(t$$1, onInput) {
71018                 dispatch$$1.call('change', field, t$$1, onInput);
71019             });
71020
71021         if (field.input.entity) field.input.entity(entity);
71022
71023         field.keys = field.keys || [field.key];
71024
71025         field.show = show;
71026
71027         field.shown = function() {
71028             return field.id === 'name' || field.show || lodash.some(field.keys, function(key) { return !!tags[key]; });
71029         };
71030
71031         field.modified = function() {
71032             var original = context.graph().base().entities[entity.id];
71033             return lodash.some(field.keys, function(key) {
71034                 return original ? tags[key] !== original.tags[key] : tags[key];
71035             });
71036         };
71037
71038         field.revert = function() {
71039             var original = context.graph().base().entities[entity.id],
71040                 t$$1 = {};
71041             field.keys.forEach(function(key) {
71042                 t$$1[key] = original ? original.tags[key] : undefined;
71043             });
71044             return t$$1;
71045         };
71046
71047         field.present = function() {
71048             return lodash.some(field.keys, function(key) {
71049                 return tags[key];
71050             });
71051         };
71052
71053         field.remove = function() {
71054             var t$$1 = {};
71055             field.keys.forEach(function(key) {
71056                 t$$1[key] = undefined;
71057             });
71058             return t$$1;
71059         };
71060
71061         return field;
71062     }
71063
71064
71065     function fieldKey(field) {
71066         return field.id;
71067     }
71068
71069
71070     function presets(selection$$1) {
71071         selection$$1.call(uiDisclosure()
71072             .title(t('inspector.all_fields'))
71073             .expanded(expandedPreference)
71074             .on('toggled', toggled)
71075             .content(content)
71076         );
71077
71078         function toggled(expanded) {
71079             expandedPreference = expanded;
71080             context.storage('preset_fields.expanded', expanded);
71081         }
71082     }
71083
71084
71085     function content(selection$$1) {
71086         if (!fieldsArr) {
71087             var entity = context.entity(id),
71088                 geometry = context.geometry(id),
71089                 presets = context.presets();
71090
71091             fieldsArr = [];
71092
71093             if (presets.field('name')) {
71094                 fieldsArr.push(UIField(presets.field('name'), entity));
71095             }
71096
71097             preset.fields.forEach(function(field) {
71098                 if (field.matchGeometry(geometry)) {
71099                     fieldsArr.push(UIField(field, entity, true));
71100                 }
71101             });
71102
71103             if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) {
71104                 fieldsArr.push(UIField(presets.field('restrictions'), entity, true));
71105             }
71106
71107             presets.universal().forEach(function(field) {
71108                 if (preset.fields.indexOf(field) < 0) {
71109                     fieldsArr.push(UIField(field, entity));
71110                 }
71111             });
71112         }
71113
71114         var shown = fieldsArr.filter(function(field) { return field.shown(); }),
71115             notShown = fieldsArr.filter(function(field) { return !field.shown(); });
71116
71117
71118         var form = selection$$1.selectAll('.preset-form')
71119             .data([0]);
71120
71121         form = form.enter()
71122             .append('div')
71123             .attr('class', 'preset-form inspector-inner fillL3')
71124             .merge(form);
71125
71126
71127         var fields = form.selectAll('.form-field')
71128             .data(shown, fieldKey);
71129
71130         fields.exit()
71131             .remove();
71132
71133         // Enter
71134         var enter = fields.enter()
71135             .append('div')
71136             .attr('class', function(field) {
71137                 return 'form-field form-field-' + field.id;
71138             });
71139
71140         var label = enter
71141             .append('label')
71142             .attr('class', 'form-label')
71143             .attr('for', function(field) { return 'preset-input-' + field.id; })
71144             .text(function(field) { return field.label(); });
71145
71146         var wrap = label
71147             .append('div')
71148             .attr('class', 'form-label-button-wrap');
71149
71150         wrap.append('button')
71151             .attr('class', 'remove-icon')
71152             .attr('tabindex', -1)
71153             .call(svgIcon('#operation-delete'));
71154
71155         wrap.append('button')
71156             .attr('class', 'modified-icon')
71157             .attr('tabindex', -1)
71158             .call(
71159                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
71160             );
71161
71162
71163         // Update
71164         fields = fields
71165             .merge(enter);
71166
71167         fields.selectAll('.form-label-button-wrap .remove-icon')
71168             .on('click', remove);
71169
71170         fields.selectAll('.modified-icon')
71171             .on('click', revert);
71172
71173         fields
71174             .order()
71175             .classed('modified', function(field) { return field.modified(); })
71176             .classed('present', function(field) { return field.present(); })
71177             .each(function(field) {
71178                 var referenceKey = field.key;
71179                 if (field.type === 'multiCombo') {   // lookup key without the trailing ':'
71180                     referenceKey = referenceKey.replace(/:$/, '');
71181                 }
71182                 var reference = uiTagReference(field.reference || { key: referenceKey }, context);
71183
71184                 if (state === 'hover') {
71185                     reference.showing(false);
71186                 }
71187
71188                 select(this)
71189                     .call(field.input)
71190                     .selectAll('input')
71191                     .on('keydown', function() {
71192                         // if user presses enter, and combobox is not active, accept edits..
71193                         if (event.keyCode === 13 && select('.combobox').empty()) {
71194                             context.enter(modeBrowse(context));
71195                         }
71196                     });
71197
71198                 select(this)
71199                     .call(reference.body)
71200                     .select('.form-label-button-wrap')
71201                     .call(reference.button);
71202
71203                 field.input.tags(tags);
71204             });
71205
71206         notShown = notShown.map(function(field) {
71207             return {
71208                 title: field.label(),
71209                 value: field.label(),
71210                 field: field
71211             };
71212         });
71213
71214
71215         var more = selection$$1.selectAll('.more-fields')
71216             .data((notShown.length > 0) ? [0] : []);
71217
71218         more.exit()
71219             .remove();
71220
71221         more = more.enter()
71222             .append('div')
71223             .attr('class', 'more-fields')
71224             .append('label')
71225             .text(t('inspector.add_fields'))
71226             .merge(more);
71227
71228
71229         var input = more.selectAll('.value')
71230             .data([0]);
71231
71232         input.exit()
71233             .remove();
71234
71235         input = input.enter()
71236             .append('input')
71237             .attr('class', 'value')
71238             .attr('type', 'text')
71239             .call(utilNoAuto)
71240             .merge(input);
71241
71242         input
71243             .call(utilGetSetValue, '')
71244             .attr('placeholder', function() {
71245                 var placeholder = [];
71246                 for (var field in notShown) {
71247                     placeholder.push(notShown[field].title);
71248                 }
71249                 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
71250             })
71251             .call(d3combobox()
71252                 .container(context.container())
71253                 .data(notShown)
71254                 .minItems(1)
71255                 .on('accept', show)
71256             );
71257
71258
71259         function show(field) {
71260             field = field.field;
71261             field.show = true;
71262             content(selection$$1);
71263             field.input.focus();
71264         }
71265
71266
71267         function revert(field) {
71268             event.stopPropagation();
71269             event.preventDefault();
71270             dispatch$$1.call('change', field, field.revert());
71271         }
71272
71273
71274         function remove(field) {
71275             event.stopPropagation();
71276             event.preventDefault();
71277             dispatch$$1.call('change', field, field.remove());
71278         }
71279     }
71280
71281
71282     presets.preset = function(_) {
71283         if (!arguments.length) return preset;
71284         if (preset && preset.id === _.id) return presets;
71285         preset = _;
71286         fieldsArr = null;
71287         return presets;
71288     };
71289
71290
71291     presets.state = function(_) {
71292         if (!arguments.length) return state;
71293         state = _;
71294         return presets;
71295     };
71296
71297
71298     presets.tags = function(_) {
71299         if (!arguments.length) return tags;
71300         tags = _;
71301         // Don't reset fieldsArr here.
71302         return presets;
71303     };
71304
71305
71306     presets.entityID = function(_) {
71307         if (!arguments.length) return id;
71308         if (id === _) return presets;
71309         id = _;
71310         fieldsArr = null;
71311         return presets;
71312     };
71313
71314
71315     return utilRebind(presets, dispatch$$1, 'on');
71316 }
71317
71318 function uiEntityEditor(context) {
71319     var dispatch$$1 = dispatch('choose'),
71320         state = 'select',
71321         coalesceChanges = false,
71322         modified = false,
71323         base,
71324         id,
71325         activePreset,
71326         reference;
71327
71328     var presetEditor = uiPreset(context)
71329         .on('change', changeTags);
71330     var rawTagEditor = uiRawTagEditor(context)
71331         .on('change', changeTags);
71332
71333
71334     function entityEditor(selection$$1) {
71335         var entity = context.entity(id),
71336             tags = lodash.clone(entity.tags);
71337
71338         // Header
71339         var header = selection$$1.selectAll('.header')
71340             .data([0]);
71341
71342         // Enter
71343         var enter = header.enter()
71344             .append('div')
71345             .attr('class', 'header fillL cf');
71346
71347         enter
71348             .append('button')
71349             .attr('class', 'fl preset-reset preset-choose')
71350             .call(svgIcon((textDirection === 'rtl') ? '#icon-forward' : '#icon-backward'));
71351
71352         enter
71353             .append('button')
71354             .attr('class', 'fr preset-close')
71355             .on('click', function() { context.enter(modeBrowse(context)); })
71356             .call(svgIcon(modified ? '#icon-apply' : '#icon-close'));
71357
71358         enter
71359             .append('h3')
71360             .text(t('inspector.edit'));
71361
71362         // Update
71363         header = header
71364             .merge(enter);
71365
71366         header.selectAll('.preset-reset')
71367             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
71368
71369
71370         // Body
71371         var body = selection$$1.selectAll('.inspector-body')
71372             .data([0]);
71373
71374         // Enter
71375         enter = body.enter()
71376             .append('div')
71377             .attr('class', 'inspector-body');
71378
71379         enter
71380             .append('div')
71381             .attr('class', 'preset-list-item inspector-inner')
71382             .append('div')
71383             .attr('class', 'preset-list-button-wrap')
71384             .append('button')
71385             .attr('class', 'preset-list-button preset-reset')
71386             .call(tooltip().title(t('inspector.back_tooltip')).placement('bottom'))
71387             .append('div')
71388             .attr('class', 'label');
71389
71390         enter
71391             .append('div')
71392             .attr('class', 'inspector-border inspector-preset');
71393
71394         enter
71395             .append('div')
71396             .attr('class', 'inspector-border raw-tag-editor inspector-inner');
71397
71398         enter
71399             .append('div')
71400             .attr('class', 'inspector-border raw-member-editor inspector-inner');
71401
71402         enter
71403             .append('div')
71404             .attr('class', 'raw-membership-editor inspector-inner');
71405
71406         enter
71407             .append('input')
71408             .attr('type', 'text')
71409             .attr('class', 'key-trap');
71410
71411
71412         // Update
71413         body = body
71414             .merge(enter);
71415
71416         body.selectAll('.preset-list-button-wrap')
71417             .call(reference.button);
71418
71419         body.selectAll('.preset-list-item')
71420             .call(reference.body);
71421
71422         body.selectAll('.preset-reset')
71423             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
71424
71425         body.select('.preset-list-item button')
71426             .call(uiPresetIcon()
71427                 .geometry(context.geometry(id))
71428                 .preset(activePreset));
71429
71430         body.select('.preset-list-item .label')
71431             .text(activePreset.name());
71432
71433         body.select('.inspector-preset')
71434             .call(presetEditor
71435                 .preset(activePreset)
71436                 .entityID(id)
71437                 .tags(tags)
71438                 .state(state));
71439
71440         body.select('.raw-tag-editor')
71441             .call(rawTagEditor
71442                 .preset(activePreset)
71443                 .entityID(id)
71444                 .tags(tags)
71445                 .state(state));
71446
71447         if (entity.type === 'relation') {
71448             body.select('.raw-member-editor')
71449                 .style('display', 'block')
71450                 .call(uiRawMemberEditor(context)
71451                     .entityID(id));
71452         } else {
71453             body.select('.raw-member-editor')
71454                 .style('display', 'none');
71455         }
71456
71457         body.select('.raw-membership-editor')
71458             .call(uiRawMembershipEditor(context)
71459                 .entityID(id));
71460
71461         body.select('.key-trap')
71462             .on('keydown.key-trap', function() {
71463                 // On tabbing, send focus back to the first field on the inspector-body
71464                 // (probably the `name` field) #4159
71465                 if (event.keyCode === 9 && !event.shiftKey) {
71466                     event.preventDefault();
71467                     body.select('input').node().focus();
71468                 }
71469             });
71470
71471         context.history()
71472             .on('change.entity-editor', historyChanged);
71473
71474
71475         function historyChanged() {
71476             if (state === 'hide') return;
71477
71478             var entity = context.hasEntity(id),
71479                 graph = context.graph();
71480             if (!entity) return;
71481
71482             entityEditor.preset(context.presets().match(entity, graph));
71483             entityEditor.modified(base !== graph);
71484             entityEditor(selection$$1);
71485         }
71486     }
71487
71488
71489     function clean(o) {
71490
71491         function cleanVal(k, v) {
71492             function keepSpaces(k) {
71493                 return k.match(/_hours|_times/) !== null;
71494             }
71495
71496             var blacklist = ['description', 'note', 'fixme'];
71497             if (lodash.some(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
71498
71499             var cleaned = v.split(';')
71500                 .map(function(s) { return s.trim(); })
71501                 .join(keepSpaces(k) ? '; ' : ';');
71502
71503             // The code below is not intended to validate websites and emails.
71504             // It is only intended to prevent obvious copy-paste errors. (#2323)
71505             // clean website- and email-like tags
71506             if (k.indexOf('website') !== -1 ||
71507                 k.indexOf('email') !== -1 ||
71508                 cleaned.indexOf('http') === 0) {
71509                 cleaned = cleaned
71510                     .replace(/[\u200B-\u200F\uFEFF]/g, '');  // strip LRM and other zero width chars
71511
71512             }
71513
71514             return cleaned;
71515         }
71516
71517         var out = {}, k, v;
71518         for (k in o) {
71519             if (k && (v = o[k]) !== undefined) {
71520                 out[k] = cleanVal(k, v);
71521             }
71522         }
71523         return out;
71524     }
71525
71526
71527     // Tag changes that fire on input can all get coalesced into a single
71528     // history operation when the user leaves the field.  #2342
71529     function changeTags(changed, onInput) {
71530         var entity = context.entity(id),
71531             annotation = t('operations.change_tags.annotation'),
71532             tags = lodash.clone(entity.tags);
71533
71534         lodash.forEach(changed, function(v, k) {
71535             if (v !== undefined || tags.hasOwnProperty(k)) {
71536                 tags[k] = v;
71537             }
71538         });
71539
71540         if (!onInput) {
71541             tags = clean(tags);
71542         }
71543
71544         if (!lodash.isEqual(entity.tags, tags)) {
71545             if (coalesceChanges) {
71546                 context.overwrite(actionChangeTags(id, tags), annotation);
71547             } else {
71548                 context.perform(actionChangeTags(id, tags), annotation);
71549                 coalesceChanges = !!onInput;
71550             }
71551         }
71552     }
71553
71554
71555     entityEditor.modified = function(_) {
71556         if (!arguments.length) return modified;
71557         modified = _;
71558         selectAll('button.preset-close use')
71559             .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
71560     };
71561
71562
71563     entityEditor.state = function(_) {
71564         if (!arguments.length) return state;
71565         state = _;
71566         return entityEditor;
71567     };
71568
71569
71570     entityEditor.entityID = function(_) {
71571         if (!arguments.length) return id;
71572         id = _;
71573         base = context.graph();
71574         entityEditor.preset(context.presets().match(context.entity(id), base));
71575         entityEditor.modified(false);
71576         coalesceChanges = false;
71577         return entityEditor;
71578     };
71579
71580
71581     entityEditor.preset = function(_) {
71582         if (!arguments.length) return activePreset;
71583         if (_ !== activePreset) {
71584             activePreset = _;
71585             reference = uiTagReference(activePreset.reference(context.geometry(id)), context)
71586                 .showing(false);
71587         }
71588         return entityEditor;
71589     };
71590
71591
71592     return utilRebind(entityEditor, dispatch$$1, 'on');
71593 }
71594
71595 function uiPresetList(context) {
71596     var dispatch$$1 = dispatch('choose'),
71597         id,
71598         currentPreset,
71599         autofocus = false;
71600
71601
71602     function presetList(selection$$1) {
71603         var entity = context.entity(id),
71604             geometry = context.geometry(id);
71605
71606         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
71607         if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
71608             geometry = 'point';
71609         }
71610
71611         var presets = context.presets().matchGeometry(geometry);
71612
71613         selection$$1.html('');
71614
71615         var messagewrap = selection$$1
71616             .append('div')
71617             .attr('class', 'header fillL cf');
71618
71619         var message = messagewrap
71620             .append('h3')
71621             .text(t('inspector.choose'));
71622
71623         if (context.entity(id).isUsed(context.graph())) {
71624             messagewrap
71625                 .append('button')
71626                 .attr('class', 'preset-choose')
71627                 .on('click', function() { dispatch$$1.call('choose', this, currentPreset); })
71628                 .call(svgIcon((textDirection === 'rtl') ? '#icon-backward' : '#icon-forward'));
71629         } else {
71630             messagewrap
71631                 .append('button')
71632                 .attr('class', 'close')
71633                 .on('click', function() {
71634                     context.enter(modeBrowse(context));
71635                 })
71636                 .call(svgIcon('#icon-close'));
71637         }
71638
71639         function keydown() {
71640             // hack to let delete shortcut work when search is autofocused
71641             if (search.property('value').length === 0 &&
71642                 (event.keyCode === d3keybinding.keyCodes['⌫'] ||
71643                  event.keyCode === d3keybinding.keyCodes['⌦'])) {
71644                 event.preventDefault();
71645                 event.stopPropagation();
71646                 operationDelete([id], context)();
71647             } else if (search.property('value').length === 0 &&
71648                 (event.ctrlKey || event.metaKey) &&
71649                 event.keyCode === d3keybinding.keyCodes.z) {
71650                 event.preventDefault();
71651                 event.stopPropagation();
71652                 context.undo();
71653             } else if (!event.ctrlKey && !event.metaKey) {
71654                 select(this).on('keydown', null);
71655             }
71656         }
71657
71658         function keypress() {
71659             // enter
71660             var value = search.property('value');
71661             if (event.keyCode === 13 && value.length) {
71662                 list.selectAll('.preset-list-item:first-child').datum().choose();
71663             }
71664         }
71665
71666         function inputevent() {
71667             var value = search.property('value');
71668             list.classed('filtered', value.length);
71669             if (value.length) {
71670                 var results = presets.search(value, geometry);
71671                 message.text(t('inspector.results', {
71672                     n: results.collection.length,
71673                     search: value
71674                 }));
71675                 list.call(drawList, results);
71676             } else {
71677                 list.call(drawList, context.presets().defaults(geometry, 36));
71678                 message.text(t('inspector.choose'));
71679             }
71680         }
71681
71682         var searchWrap = selection$$1
71683             .append('div')
71684             .attr('class', 'search-header');
71685
71686         var search = searchWrap
71687             .append('input')
71688             .attr('class', 'preset-search-input')
71689             .attr('placeholder', t('inspector.search'))
71690             .attr('type', 'search')
71691             .call(utilNoAuto)
71692             .on('keydown', keydown)
71693             .on('keypress', keypress)
71694             .on('input', inputevent);
71695
71696         searchWrap
71697             .call(svgIcon('#icon-search', 'pre-text'));
71698
71699         if (autofocus) {
71700             search.node().focus();
71701         }
71702
71703         var listWrap = selection$$1
71704             .append('div')
71705             .attr('class', 'inspector-body');
71706
71707         var list = listWrap
71708             .append('div')
71709             .attr('class', 'preset-list fillL cf')
71710             .call(drawList, context.presets().defaults(geometry, 36));
71711     }
71712
71713
71714     function drawList(list, presets) {
71715         var collection = presets.collection.map(function(preset) {
71716             return preset.members ? CategoryItem(preset) : PresetItem(preset);
71717         });
71718
71719         var items = list.selectAll('.preset-list-item')
71720             .data(collection, function(d) { return d.preset.id; });
71721
71722         items.order();
71723
71724         items.exit()
71725             .remove();
71726
71727         items.enter()
71728             .append('div')
71729             .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
71730             .classed('current', function(item) { return item.preset === currentPreset; })
71731             .each(function(item) { select(this).call(item); })
71732             .style('opacity', 0)
71733             .transition()
71734             .style('opacity', 1);
71735     }
71736
71737
71738     function CategoryItem(preset) {
71739         var box, sublist, shown = false;
71740
71741         function item(selection$$1) {
71742             var wrap = selection$$1.append('div')
71743                 .attr('class', 'preset-list-button-wrap category col12');
71744
71745             var button = wrap
71746                 .append('button')
71747                 .attr('class', 'preset-list-button')
71748                 .classed('expanded', false)
71749                 .call(uiPresetIcon()
71750                     .geometry(context.geometry(id))
71751                     .preset(preset))
71752                 .on('click', function() {
71753                     var isExpanded = select(this).classed('expanded');
71754                     var iconName = isExpanded ?
71755                         (textDirection === 'rtl' ? '#icon-backward' : '#icon-forward') : '#icon-down';
71756                     select(this)
71757                         .classed('expanded', !isExpanded);
71758                     select(this).selectAll('div.label svg.icon use')
71759                         .attr('href', iconName);
71760                     item.choose();
71761                 });
71762
71763             var label = button
71764                 .append('div')
71765                 .attr('class', 'label');
71766
71767             label
71768                 .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'))
71769                 .append('span')
71770                 .html(function() { return preset.name() + '&hellip;'; });
71771
71772             box = selection$$1.append('div')
71773                 .attr('class', 'subgrid col12')
71774                 .style('max-height', '0px')
71775                 .style('opacity', 0);
71776
71777             box.append('div')
71778                 .attr('class', 'arrow');
71779
71780             sublist = box.append('div')
71781                 .attr('class', 'preset-list fillL3 cf fl');
71782         }
71783
71784
71785         item.choose = function() {
71786             if (!box || !sublist) return;
71787
71788             if (shown) {
71789                 shown = false;
71790                 box.transition()
71791                     .duration(200)
71792                     .style('opacity', '0')
71793                     .style('max-height', '0px')
71794                     .style('padding-bottom', '0px');
71795             } else {
71796                 shown = true;
71797                 sublist.call(drawList, preset.members);
71798                 box.transition()
71799                     .duration(200)
71800                     .style('opacity', '1')
71801                     .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
71802                     .style('padding-bottom', '20px');
71803             }
71804         };
71805
71806         item.preset = preset;
71807
71808         return item;
71809     }
71810
71811
71812     function PresetItem(preset) {
71813         function item(selection$$1) {
71814             var wrap = selection$$1.append('div')
71815                 .attr('class', 'preset-list-button-wrap col12');
71816
71817             wrap.append('button')
71818                 .attr('class', 'preset-list-button')
71819                 .call(uiPresetIcon()
71820                     .geometry(context.geometry(id))
71821                     .preset(preset))
71822                 .on('click', item.choose)
71823                 .append('div')
71824                 .attr('class', 'label')
71825                 .text(preset.name());
71826
71827             wrap.call(item.reference.button);
71828             selection$$1.call(item.reference.body);
71829         }
71830
71831         item.choose = function() {
71832             context.presets().choose(preset);
71833
71834             context.perform(
71835                 actionChangePreset(id, currentPreset, preset),
71836                 t('operations.change_tags.annotation')
71837             );
71838
71839             dispatch$$1.call('choose', this, preset);
71840         };
71841
71842         item.help = function() {
71843             event.stopPropagation();
71844             item.reference.toggle();
71845         };
71846
71847         item.preset = preset;
71848         item.reference = uiTagReference(preset.reference(context.geometry(id)), context);
71849
71850         return item;
71851     }
71852
71853
71854     presetList.autofocus = function(_) {
71855         if (!arguments.length) return autofocus;
71856         autofocus = _;
71857         return presetList;
71858     };
71859
71860
71861     presetList.entityID = function(_) {
71862         if (!arguments.length) return id;
71863         id = _;
71864         presetList.preset(context.presets().match(context.entity(id), context.graph()));
71865         return presetList;
71866     };
71867
71868
71869     presetList.preset = function(_) {
71870         if (!arguments.length) return currentPreset;
71871         currentPreset = _;
71872         return presetList;
71873     };
71874
71875
71876     return utilRebind(presetList, dispatch$$1, 'on');
71877 }
71878
71879 function uiViewOnOSM(context) {
71880     var id;
71881
71882     function viewOnOSM(selection) {
71883         var entity = context.entity(id);
71884
71885         selection.style('display', entity.isNew() ? 'none' : null);
71886
71887         var link = selection.selectAll('.view-on-osm')
71888             .data([0]);
71889
71890         var enter = link.enter()
71891             .append('a')
71892             .attr('class', 'view-on-osm')
71893             .attr('target', '_blank')
71894             .call(svgIcon('#icon-out-link', 'inline'));
71895
71896         enter
71897             .append('span')
71898             .text(t('inspector.view_on_osm'));
71899
71900         link
71901             .merge(enter)
71902             .attr('href', context.connection().entityURL(entity));
71903     }
71904
71905
71906     viewOnOSM.entityID = function(_) {
71907         if (!arguments.length) return id;
71908         id = _;
71909         return viewOnOSM;
71910     };
71911
71912     return viewOnOSM;
71913 }
71914
71915 function uiInspector(context) {
71916     var presetList = uiPresetList(context),
71917         entityEditor = uiEntityEditor(context),
71918         state = 'select',
71919         entityID,
71920         newFeature = false;
71921
71922
71923     function inspector(selection$$1) {
71924         presetList
71925             .entityID(entityID)
71926             .autofocus(newFeature)
71927             .on('choose', setPreset);
71928
71929         entityEditor
71930             .state(state)
71931             .entityID(entityID)
71932             .on('choose', showList);
71933
71934         var wrap = selection$$1.selectAll('.panewrap')
71935             .data([0]);
71936
71937         var enter = wrap.enter()
71938             .append('div')
71939             .attr('class', 'panewrap');
71940
71941         enter
71942             .append('div')
71943             .attr('class', 'preset-list-pane pane');
71944
71945         enter
71946             .append('div')
71947             .attr('class', 'entity-editor-pane pane');
71948
71949         wrap = wrap.merge(enter);
71950         var presetPane = wrap.selectAll('.preset-list-pane');
71951         var editorPane = wrap.selectAll('.entity-editor-pane');
71952
71953         var graph = context.graph(),
71954             entity = context.entity(entityID),
71955             showEditor = state === 'hover' ||
71956                 entity.isUsed(graph) ||
71957                 entity.isHighwayIntersection(graph);
71958
71959         if (showEditor) {
71960             wrap.style('right', '0%');
71961             editorPane.call(entityEditor);
71962         } else {
71963             wrap.style('right', '-100%');
71964             presetPane.call(presetList);
71965         }
71966
71967         var footer = selection$$1.selectAll('.footer')
71968             .data([0]);
71969
71970         footer = footer.enter()
71971             .append('div')
71972             .attr('class', 'footer')
71973             .merge(footer);
71974
71975         footer
71976             .call(uiViewOnOSM(context).entityID(entityID));
71977
71978
71979         function showList(preset) {
71980             wrap.transition()
71981                 .styleTween('right', function() { return interpolateValue('0%', '-100%'); });
71982
71983             presetPane
71984                 .call(presetList.preset(preset).autofocus(true));
71985         }
71986
71987
71988         function setPreset(preset) {
71989             wrap.transition()
71990                 .styleTween('right', function() { return interpolateValue('-100%', '0%'); });
71991
71992             editorPane
71993                 .call(entityEditor.preset(preset));
71994         }
71995     }
71996
71997
71998     inspector.state = function(_) {
71999         if (!arguments.length) return state;
72000         state = _;
72001         entityEditor.state(state);
72002         return inspector;
72003     };
72004
72005
72006     inspector.entityID = function(_) {
72007         if (!arguments.length) return entityID;
72008         entityID = _;
72009         return inspector;
72010     };
72011
72012
72013     inspector.newFeature = function(_) {
72014         if (!arguments.length) return newFeature;
72015         newFeature = _;
72016         return inspector;
72017     };
72018
72019
72020     return inspector;
72021 }
72022
72023 function uiNotice(context) {
72024
72025     return function(selection) {
72026         var div = selection
72027             .append('div')
72028             .attr('class', 'notice');
72029
72030         var button = div
72031             .append('button')
72032             .attr('class', 'zoom-to notice')
72033             .on('click', function() { context.map().zoom(context.minEditableZoom()); });
72034
72035         button
72036             .call(svgIcon('#icon-plus', 'pre-text'))
72037             .append('span')
72038             .attr('class', 'label')
72039             .text(t('zoom_in_edit'));
72040
72041
72042         function disableTooHigh() {
72043             div.style('display', context.editable() ? 'none' : 'block');
72044         }
72045
72046         context.map()
72047             .on('move.notice', lodash.debounce(disableTooHigh, 500));
72048
72049         disableTooHigh();
72050     };
72051 }
72052
72053 function uiSidebar(context) {
72054     var inspector = uiInspector(context),
72055         current;
72056
72057
72058     function sidebar(selection) {
72059         var featureListWrap = selection
72060             .append('div')
72061             .attr('class', 'feature-list-pane')
72062             .call(uiFeatureList(context));
72063
72064         selection
72065             .call(uiNotice(context));
72066
72067         var inspectorWrap = selection
72068             .append('div')
72069             .attr('class', 'inspector-hidden inspector-wrap fr');
72070
72071
72072         function hover(id) {
72073             if (!current && context.hasEntity(id)) {
72074                 featureListWrap
72075                     .classed('inspector-hidden', true);
72076
72077                 inspectorWrap
72078                     .classed('inspector-hidden', false)
72079                     .classed('inspector-hover', true);
72080
72081                 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
72082                     inspector
72083                         .state('hover')
72084                         .entityID(id);
72085
72086                     inspectorWrap
72087                         .call(inspector);
72088                 }
72089
72090             } else if (!current) {
72091                 featureListWrap
72092                     .classed('inspector-hidden', false);
72093                 inspectorWrap
72094                     .classed('inspector-hidden', true);
72095                 inspector
72096                     .state('hide');
72097             }
72098         }
72099
72100
72101         sidebar.hover = lodash.throttle(hover, 200);
72102
72103
72104         sidebar.select = function(id, newFeature) {
72105             if (!current && id) {
72106                 featureListWrap
72107                     .classed('inspector-hidden', true);
72108
72109                 inspectorWrap
72110                     .classed('inspector-hidden', false)
72111                     .classed('inspector-hover', false);
72112
72113                 if (inspector.entityID() !== id || inspector.state() !== 'select') {
72114                     inspector
72115                         .state('select')
72116                         .entityID(id)
72117                         .newFeature(newFeature);
72118
72119                     inspectorWrap
72120                         .call(inspector);
72121                 }
72122
72123             } else if (!current) {
72124                 featureListWrap
72125                     .classed('inspector-hidden', false);
72126                 inspectorWrap
72127                     .classed('inspector-hidden', true);
72128                 inspector
72129                     .state('hide');
72130             }
72131         };
72132
72133
72134         sidebar.show = function(component) {
72135             featureListWrap
72136                 .classed('inspector-hidden', true);
72137             inspectorWrap
72138                 .classed('inspector-hidden', true);
72139
72140             if (current) current.remove();
72141             current = selection
72142                 .append('div')
72143                 .attr('class', 'sidebar-component')
72144                 .call(component);
72145         };
72146
72147
72148         sidebar.hide = function() {
72149             featureListWrap
72150                 .classed('inspector-hidden', false);
72151             inspectorWrap
72152                 .classed('inspector-hidden', true);
72153
72154             if (current) current.remove();
72155             current = null;
72156         };
72157     }
72158
72159
72160     sidebar.hover = function() {};
72161     sidebar.hover.cancel = function() {};
72162     sidebar.select = function() {};
72163     sidebar.show = function() {};
72164     sidebar.hide = function() {};
72165
72166     return sidebar;
72167 }
72168
72169 function uiSpinner(context) {
72170     var connection = context.connection();
72171
72172
72173     return function(selection) {
72174         var img = selection
72175             .append('img')
72176             .attr('src', context.imagePath('loader-black.gif'))
72177             .style('opacity', 0);
72178
72179         connection
72180             .on('loading.spinner', function() {
72181                 img.transition()
72182                     .style('opacity', 1);
72183             });
72184
72185         connection
72186             .on('loaded.spinner', function() {
72187                 img.transition()
72188                     .style('opacity', 0);
72189             });
72190     };
72191 }
72192
72193 function uiSplash(context) {
72194
72195     return function(selection) {
72196         if (context.storage('sawSplash'))
72197              return;
72198
72199         context.storage('sawSplash', true);
72200
72201         var modalSelection = uiModal(selection);
72202
72203         modalSelection.select('.modal')
72204             .attr('class', 'modal-splash modal col6');
72205
72206         var introModal = modalSelection.select('.content')
72207             .append('div')
72208             .attr('class', 'fillL');
72209
72210         introModal
72211             .append('div')
72212             .attr('class','modal-section cf')
72213             .append('h3').text(t('splash.welcome'));
72214
72215         introModal
72216             .append('div')
72217             .attr('class','modal-section')
72218             .append('p')
72219             .html(t('splash.text', {
72220                 version: context.version,
72221                 website: '<a href="http://ideditor.com/">ideditor.com</a>',
72222                 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
72223             }));
72224
72225         var buttonWrap = introModal
72226             .append('div')
72227             .attr('class', 'modal-actions cf');
72228
72229         var walkthrough = buttonWrap
72230             .append('button')
72231             .attr('class', 'walkthrough col6')
72232             .on('click', function() {
72233                 context.container().call(uiIntro(context));
72234                 modalSelection.close();
72235             });
72236
72237         walkthrough
72238             .append('svg')
72239             .attr('class', 'logo logo-walkthrough')
72240             .append('use')
72241             .attr('xlink:href', '#logo-walkthrough');
72242
72243         walkthrough
72244             .append('div')
72245             .text(t('splash.walkthrough'));
72246
72247         var startEditing = buttonWrap
72248             .append('button')
72249             .attr('class', 'start-editing col6')
72250             .on('click', modalSelection.close);
72251
72252         startEditing
72253             .append('svg')
72254             .attr('class', 'logo logo-features')
72255             .append('use')
72256             .attr('xlink:href', '#logo-features');
72257
72258         startEditing
72259             .append('div')
72260             .text(t('splash.start'));
72261
72262
72263         modalSelection.select('button.close')
72264             .attr('class','hide');
72265
72266     };
72267 }
72268
72269 function uiStatus(context) {
72270     var connection = context.connection();
72271
72272     return function(selection$$1) {
72273
72274         function update() {
72275             connection.status(function(err, apiStatus) {
72276                 selection$$1.html('');
72277
72278                 if (err) {
72279                     if (apiStatus === 'rateLimited') {
72280                         selection$$1
72281                             .text(t('status.rateLimit'))
72282                             .append('a')
72283                             .attr('class', 'api-status-login')
72284                             .attr('target', '_blank')
72285                             .call(svgIcon('#icon-out-link', 'inline'))
72286                             .append('span')
72287                             .text(t('login'))
72288                             .on('click.login', function() {
72289                                 event.preventDefault();
72290                                 connection.authenticate();
72291                             });
72292                     } else {
72293                         // TODO: nice messages for different error types
72294                         selection$$1.text(t('status.error'));
72295                     }
72296
72297                 } else if (apiStatus === 'readonly') {
72298                     selection$$1.text(t('status.readonly'));
72299                 } else if (apiStatus === 'offline') {
72300                     selection$$1.text(t('status.offline'));
72301                 }
72302
72303                 selection$$1.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
72304             });
72305         }
72306
72307         connection
72308             .on('change', function() { update(selection$$1); });
72309
72310         window.setInterval(update, 90000);
72311         update(selection$$1);
72312     };
72313 }
72314
72315 function uiUndoRedo(context) {
72316     var commands = [{
72317         id: 'undo',
72318         cmd: uiCmd('⌘Z'),
72319         action: function() { if (!saving()) context.undo(); },
72320         annotation: function() { return context.history().undoAnnotation(); }
72321     }, {
72322         id: 'redo',
72323         cmd: uiCmd('⌘⇧Z'),
72324         action: function() { if (!saving()) context.redo(); },
72325         annotation: function() { return context.history().redoAnnotation(); }
72326     }];
72327
72328
72329     function saving() {
72330         return context.mode().id === 'save';
72331     }
72332
72333
72334     return function(selection$$1) {
72335         var tooltipBehavior = tooltip()
72336             .placement('bottom')
72337             .html(true)
72338             .title(function (d) {
72339                 return uiTooltipHtml(d.annotation() ?
72340                     t(d.id + '.tooltip', {action: d.annotation()}) :
72341                     t(d.id + '.nothing'), d.cmd);
72342             });
72343
72344         var buttons = selection$$1.selectAll('button')
72345             .data(commands)
72346             .enter()
72347             .append('button')
72348             .attr('class', function(d) { return 'col6 disabled ' + d.id + '-button'; })
72349             .on('click', function(d) { return d.action(); })
72350             .call(tooltipBehavior);
72351
72352         buttons.each(function(d) {
72353             var iconName = d.id;
72354             if (textDirection === 'rtl') {
72355                 if (iconName === 'undo') {
72356                     iconName = 'redo';
72357                 } else if (iconName === 'redo') {
72358                     iconName = 'undo';
72359                 }
72360             }
72361             select(this)
72362                 .call(svgIcon('#icon-' + iconName));
72363         });
72364
72365         var keybinding = d3keybinding('undo')
72366             .on(commands[0].cmd, function() { event.preventDefault(); commands[0].action(); })
72367             .on(commands[1].cmd, function() { event.preventDefault(); commands[1].action(); });
72368
72369         select(document)
72370             .call(keybinding);
72371
72372         context.history()
72373             .on('change.undo_redo', update);
72374
72375         context
72376             .on('enter.undo_redo', update);
72377
72378         function update() {
72379             buttons
72380                 .property('disabled', saving())
72381                 .classed('disabled', function(d) { return !d.annotation(); })
72382                 .each(function() {
72383                     var selection$$1 = select(this);
72384                     if (selection$$1.property('tooltipVisible')) {
72385                         selection$$1.call(tooltipBehavior.show);
72386                     }
72387                 });
72388         }
72389     };
72390 }
72391
72392 // these are module variables so they are preserved through a ui.restart()
72393 var sawVersion = null;
72394 var isNewVersion = false;
72395 var isNewUser = false;
72396
72397
72398 function uiVersion(context) {
72399
72400     var currVersion = context.version,
72401         matchedVersion = currVersion.match(/\d\.\d\.\d.*/);
72402
72403     if (sawVersion === null && matchedVersion !== null) {
72404         isNewVersion = (context.storage('sawVersion') !== currVersion);
72405         isNewUser = !context.storage('sawSplash');
72406         context.storage('sawVersion', currVersion);
72407         sawVersion = currVersion;
72408     }
72409
72410     return function(selection) {
72411         selection
72412             .append('a')
72413             .attr('target', '_blank')
72414             .attr('tabindex', -1)
72415             .attr('href', 'https://github.com/openstreetmap/iD')
72416             .text(currVersion);
72417
72418         // only show new version indicator to users that have used iD before
72419         if (isNewVersion && !isNewUser) {
72420             selection
72421                 .append('div')
72422                 .attr('class', 'badge')
72423                 .append('a')
72424                 .attr('target', '_blank')
72425                 .attr('tabindex', -1)
72426                 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CHANGELOG.md#whats-new')
72427                 .call(svgIcon('#gift-11'))
72428                 .call(tooltip()
72429                     .title(t('version.whats_new', { version: currVersion }))
72430                     .placement('top')
72431                 );
72432         }
72433     };
72434 }
72435
72436 function uiZoom(context) {
72437     var zooms = [{
72438         id: 'zoom-in',
72439         icon: 'plus',
72440         title: t('zoom.in'),
72441         action: context.zoomIn,
72442         key: '+'
72443     }, {
72444         id: 'zoom-out',
72445         icon: 'minus',
72446         title: t('zoom.out'),
72447         action: context.zoomOut,
72448         key: '-'
72449     }];
72450
72451
72452     function zoomIn() {
72453         event.preventDefault();
72454         context.zoomIn();
72455     }
72456
72457
72458     function zoomOut() {
72459         event.preventDefault();
72460         context.zoomOut();
72461     }
72462
72463
72464     function zoomInFurther() {
72465         event.preventDefault();
72466         context.zoomInFurther();
72467     }
72468
72469
72470     function zoomOutFurther() {
72471         event.preventDefault();
72472         context.zoomOutFurther();
72473     }
72474
72475
72476     return function(selection$$1) {
72477         var button = selection$$1.selectAll('button')
72478             .data(zooms)
72479             .enter()
72480             .append('button')
72481             .attr('tabindex', -1)
72482             .attr('class', function(d) { return d.id; })
72483             .on('click.editor', function(d) { d.action(); })
72484             .call(tooltip()
72485                 .placement((textDirection === 'rtl') ? 'right' : 'left')
72486                 .html(true)
72487                 .title(function(d) {
72488                     return uiTooltipHtml(d.title, d.key);
72489                 })
72490             );
72491
72492         button.each(function(d) {
72493             select(this)
72494                 .call(svgIcon('#icon-' + d.icon, 'light'));
72495         });
72496
72497         var keybinding = d3keybinding('zoom');
72498
72499        lodash.each(['plus', 'ffplus', '=', 'ffequals'], function(key) {
72500             keybinding.on([key], zoomIn);
72501             keybinding.on([uiCmd('⌘' + key)], zoomInFurther);
72502         });
72503
72504         lodash.each(['_', '-', 'ffminus', 'dash'], function(key) {
72505             keybinding.on([key], zoomOut);
72506             keybinding.on([uiCmd('⌘' + key)], zoomOutFurther);
72507         });
72508
72509         select(document)
72510             .call(keybinding);
72511     };
72512 }
72513
72514 function uiInit(context) {
72515     var uiInitCounter = 0;
72516
72517
72518     function render(container) {
72519         container
72520             .attr('dir', textDirection);
72521
72522         var map = context.map();
72523
72524         var hash = behaviorHash(context);
72525         hash();
72526
72527         if (!hash.hadHash) {
72528             map.centerZoom([0, 0], 2);
72529         }
72530
72531         container
72532             .append('svg')
72533             .attr('id', 'defs')
72534             .call(svgDefs(context));
72535
72536         container
72537             .append('div')
72538             .attr('id', 'sidebar')
72539             .attr('class', 'col4')
72540             .call(ui.sidebar);
72541
72542         var content = container
72543             .append('div')
72544             .attr('id', 'content')
72545             .attr('class', 'active');
72546
72547         var bar = content
72548             .append('div')
72549             .attr('id', 'bar')
72550             .attr('class', 'fillD');
72551
72552         content
72553             .append('div')
72554             .attr('id', 'map')
72555             .attr('dir', 'ltr')
72556             .call(map);
72557
72558         content
72559             .call(uiMapInMap(context))
72560             .call(uiInfo(context));
72561
72562         bar
72563             .append('div')
72564             .attr('class', 'spacer col4');
72565
72566         var limiter = bar.append('div')
72567             .attr('class', 'limiter');
72568
72569         limiter
72570             .append('div')
72571             .attr('class', 'button-wrap joined col3')
72572             .call(uiModes(context), limiter);
72573
72574         limiter
72575             .append('div')
72576             .attr('class', 'button-wrap joined col1')
72577             .call(uiUndoRedo(context));
72578
72579         limiter
72580             .append('div')
72581             .attr('class', 'button-wrap col1')
72582             .call(uiSave(context));
72583
72584         bar
72585             .append('div')
72586             .attr('class', 'full-screen')
72587             .call(uiFullScreen(context));
72588
72589         bar
72590             .append('div')
72591             .attr('class', 'spinner')
72592             .call(uiSpinner(context));
72593
72594
72595         var controls = bar
72596             .append('div')
72597             .attr('class', 'map-controls');
72598
72599         controls
72600             .append('div')
72601             .attr('class', 'map-control zoombuttons')
72602             .call(uiZoom(context));
72603
72604         controls
72605             .append('div')
72606             .attr('class', 'map-control geolocate-control')
72607             .call(uiGeolocate(context));
72608
72609         controls
72610             .append('div')
72611             .attr('class', 'map-control background-control')
72612             .call(uiBackground(context));
72613
72614         controls
72615             .append('div')
72616             .attr('class', 'map-control map-data-control')
72617             .call(uiMapData(context));
72618
72619         controls
72620             .append('div')
72621             .attr('class', 'map-control help-control')
72622             .call(uiHelp(context));
72623
72624
72625         var about = content
72626             .append('div')
72627             .attr('id', 'about');
72628
72629         about
72630             .append('div')
72631             .attr('id', 'attrib')
72632             .attr('dir', 'ltr')
72633             .call(uiAttribution(context));
72634
72635         about
72636             .append('div')
72637             .attr('class', 'api-status')
72638             .call(uiStatus(context));
72639
72640
72641         var footer = about
72642             .append('div')
72643             .attr('id', 'footer')
72644             .attr('class', 'fillD');
72645
72646         footer
72647             .append('div')
72648             .attr('id', 'flash-wrap')
72649             .attr('class', 'footer-hide');
72650
72651         var footerWrap = footer
72652             .append('div')
72653             .attr('id', 'footer-wrap')
72654             .attr('class', 'footer-show');
72655
72656         footerWrap
72657             .append('div')
72658             .attr('id', 'scale-block')
72659             .call(uiScale(context));
72660
72661         var aboutList = footerWrap
72662             .append('div')
72663             .attr('id', 'info-block')
72664             .append('ul')
72665             .attr('id', 'about-list');
72666
72667         if (!context.embed()) {
72668             aboutList
72669                 .call(uiAccount(context));
72670         }
72671
72672         aboutList
72673             .append('li')
72674             .attr('class', 'version')
72675             .call(uiVersion(context));
72676
72677         var issueLinks = aboutList
72678             .append('li');
72679
72680         issueLinks
72681             .append('a')
72682             .attr('target', '_blank')
72683             .attr('tabindex', -1)
72684             .attr('href', 'https://github.com/openstreetmap/iD/issues')
72685             .call(svgIcon('#icon-bug', 'light'))
72686             .call(tooltip().title(t('report_a_bug')).placement('top'));
72687
72688         issueLinks
72689             .append('a')
72690             .attr('target', '_blank')
72691             .attr('tabindex', -1)
72692             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
72693             .call(svgIcon('#icon-translate', 'light'))
72694             .call(tooltip().title(t('help_translate')).placement('top'));
72695
72696         aboutList
72697             .append('li')
72698             .attr('class', 'feature-warning')
72699             .attr('tabindex', -1)
72700             .call(uiFeatureInfo(context));
72701
72702         aboutList
72703             .append('li')
72704             .attr('class', 'user-list')
72705             .attr('tabindex', -1)
72706             .call(uiContributors(context));
72707
72708
72709         window.onbeforeunload = function() {
72710             return context.save();
72711         };
72712
72713         window.onunload = function() {
72714             context.history().unlock();
72715         };
72716
72717         var mapDimensions = map.dimensions();
72718
72719
72720         function onResize() {
72721             mapDimensions = utilGetDimensions(content, true);
72722             map.dimensions(mapDimensions);
72723         }
72724
72725         select(window)
72726             .on('resize.editor', onResize);
72727
72728         onResize();
72729
72730         function pan(d) {
72731             return function() {
72732                 event.preventDefault();
72733                 context.pan(d, 100);
72734             };
72735         }
72736
72737
72738         // pan amount
72739         var pa = 10;
72740
72741         var keybinding = d3keybinding('main')
72742             .on('⌫', function() { event.preventDefault(); })
72743             .on('←', pan([pa, 0]))
72744             .on('↑', pan([0, pa]))
72745             .on('→', pan([-pa, 0]))
72746             .on('↓', pan([0, -pa]))
72747             .on(['⇧←', uiCmd('⌘←')], pan([mapDimensions[0], 0]))
72748             .on(['⇧↑', uiCmd('⌘↑')], pan([0, mapDimensions[1]]))
72749             .on(['⇧→', uiCmd('⌘→')], pan([-mapDimensions[0], 0]))
72750             .on(['⇧↓', uiCmd('⌘↓')], pan([0, -mapDimensions[1]]));
72751
72752         select(document)
72753             .call(keybinding);
72754
72755         context.enter(modeBrowse(context));
72756
72757         if (!uiInitCounter++) {
72758             if (!hash.startWalkthrough) {
72759                 context.container()
72760                     .call(uiSplash(context))
72761                     .call(uiRestore(context));
72762             }
72763
72764             context.container()
72765                 .call(uiShortcuts(context));
72766         }
72767
72768         var authenticating = uiLoading(context)
72769             .message(t('loading_auth'))
72770             .blocking(true);
72771
72772         context.connection()
72773             .on('authLoading.ui', function() {
72774                 context.container()
72775                     .call(authenticating);
72776             })
72777             .on('authDone.ui', function() {
72778                 authenticating.close();
72779             });
72780
72781         uiInitCounter++;
72782
72783         if (hash.startWalkthrough) {
72784             hash.startWalkthrough = false;
72785             context.container().call(uiIntro(context));
72786         }
72787     }
72788
72789
72790     var renderCallback;
72791
72792     function ui(node, callback) {
72793         renderCallback = callback;
72794         var container = select(node);
72795         context.container(container);
72796         context.loadLocale(function(err) {
72797             if (!err) {
72798                 render(container);
72799             }
72800             if (callback) {
72801                 callback(err);
72802             }
72803         });
72804     }
72805
72806
72807     ui.restart = function(arg) {
72808         context.locale(arg);
72809         context.loadLocale(function(err) {
72810             if (!err) {
72811                 context.container().selectAll('*').remove();
72812                 render(context.container());
72813                 if (renderCallback) renderCallback();
72814             }
72815         });
72816     };
72817
72818
72819     ui.sidebar = uiSidebar(context);
72820
72821     return ui;
72822 }
72823
72824 var changeset;
72825 var readOnlyTags = ['created_by', 'imagery_used', 'host', 'locale'];
72826
72827
72828 function uiCommit(context) {
72829     var dispatch$$1 = dispatch('cancel', 'save');
72830
72831
72832     function commit(selection$$1) {
72833         if (!changeset) {
72834             var detected = utilDetect(),
72835                 tags = {
72836                     created_by: ('iD ' + context.version).substr(0, 255),
72837                     imagery_used: context.history().imageryUsed().join(';').substr(0, 255),
72838                     host: detected.host.substr(0, 255),
72839                     locale: detected.locale.substr(0, 255)
72840                 };
72841
72842             changeset = new osmChangeset({ tags: tags });
72843         }
72844
72845
72846         var changes = context.history().changes(),
72847             summary = context.history().difference().summary(),
72848             rawTagEditor = uiRawTagEditor(context).on('change', changeTags),
72849             comment = context.storage('comment') || '',
72850             commentDate = +context.storage('commentDate') || 0,
72851             currDate = Date.now(),
72852             cutoff = 2 * 86400 * 1000;   // 2 days
72853
72854         // expire the stored comment if it is too old - #3947
72855         if (commentDate > currDate || currDate - commentDate > cutoff) {
72856             comment = '';
72857         }
72858
72859         selection$$1
72860             .append('div')
72861             .attr('class', 'header fillL')
72862             .append('h3')
72863             .text(t('commit.title'));
72864
72865         var body = selection$$1
72866             .append('div')
72867             .attr('class', 'body');
72868
72869         var commentSection = body
72870             .append('div')
72871             .attr('class', 'modal-section form-field commit-form');
72872
72873         commentSection
72874             .append('label')
72875             .attr('class', 'form-label')
72876             .text(t('commit.message_label'));
72877
72878         var commentField = commentSection
72879             .append('textarea')
72880             .attr('class', 'commit-form-comment')
72881             .attr('placeholder', t('commit.description_placeholder'))
72882             .attr('maxlength', 255)
72883             .property('value', comment)
72884             .on('input.save', change(true))
72885             .on('change.save', change())
72886             .on('blur.save', function() {
72887                 context.storage('comment', this.value);
72888                 context.storage('commentDate', Date.now());
72889             });
72890
72891
72892         commentField.node().select();
72893
72894         context.connection().userChangesets(function (err, changesets) {
72895             if (err) return;
72896
72897             var comments = changesets.map(function(changeset) {
72898                 return {
72899                     title: changeset.tags.comment,
72900                     value: changeset.tags.comment
72901                 };
72902             });
72903
72904             commentField
72905                 .call(d3combobox()
72906                     .container(context.container())
72907                     .caseSensitive(true)
72908                     .data(lodash.uniqBy(comments, 'title'))
72909                 );
72910         });
72911
72912         var clippyArea = commentSection.append('div')
72913             .attr('class', 'clippy-area');
72914
72915         var changeSetInfo = commentSection.append('div')
72916             .attr('class', 'changeset-info');
72917
72918         changeSetInfo.append('a')
72919             .attr('target', '_blank')
72920             .attr('tabindex', -1)
72921             .call(svgIcon('#icon-out-link', 'inline'))
72922             .attr('href', t('commit.about_changeset_comments_link'))
72923             .append('span')
72924             .text(t('commit.about_changeset_comments'));
72925
72926
72927         // Warnings
72928         var warnings = body.selectAll('div.warning-section')
72929             .data([context.history().validate(changes)]);
72930
72931         warnings = warnings.enter()
72932             .append('div')
72933             .attr('class', 'modal-section warning-section fillL2')
72934             .style('display', function(d) { return lodash.isEmpty(d) ? 'none' : null; })
72935             .style('background', '#ffb')
72936             .merge(warnings);
72937
72938         warnings
72939             .append('h3')
72940             .text(t('commit.warnings'));
72941
72942         warnings
72943             .append('ul')
72944             .attr('class', 'changeset-list');
72945
72946         var warningLi = warnings.select('ul').selectAll('li')
72947             .data(function(d) { return d; });
72948
72949         warningLi = warningLi.enter()
72950             .append('li')
72951             .on('mouseover', mouseover)
72952             .on('mouseout', mouseout)
72953             .on('click', warningClick)
72954             .merge(warningLi);
72955
72956         warningLi
72957             .call(svgIcon('#icon-alert', 'pre-text'));
72958
72959         warningLi
72960             .append('strong')
72961             .text(function(d) { return d.message; });
72962
72963         warningLi.filter(function(d) { return d.tooltip; })
72964             .call(tooltip()
72965                 .title(function(d) { return d.tooltip; })
72966                 .placement('top')
72967             );
72968
72969
72970         // Upload Explanation
72971         var saveSection = body
72972             .append('div')
72973             .attr('class','modal-section save-section fillL cf');
72974
72975         var prose = saveSection
72976             .append('p')
72977             .attr('class', 'commit-info')
72978             .html(t('commit.upload_explanation'));
72979
72980
72981         context.connection().userDetails(function(err, user) {
72982             if (err) return;
72983
72984             var userLink = select(document.createElement('div'));
72985
72986             if (user.image_url) {
72987                 userLink
72988                     .append('img')
72989                     .attr('src', user.image_url)
72990                     .attr('class', 'icon pre-text user-icon');
72991             }
72992
72993             userLink
72994                 .append('a')
72995                 .attr('class','user-info')
72996                 .text(user.display_name)
72997                 .attr('href', context.connection().userURL(user.display_name))
72998                 .attr('tabindex', -1)
72999                 .attr('target', '_blank');
73000
73001             prose
73002                 .html(t('commit.upload_explanation_with_user', { user: userLink.html() }));
73003         });
73004
73005
73006         // Buttons
73007         var buttonSection = saveSection
73008             .append('div')
73009             .attr('class', 'buttons fillL cf');
73010
73011         var cancelButton = buttonSection
73012             .append('button')
73013             .attr('class', 'secondary-action col5 button cancel-button')
73014             .on('click.cancel', function() {
73015                 dispatch$$1.call('cancel');
73016             });
73017
73018         cancelButton
73019             .append('span')
73020             .attr('class', 'label')
73021             .text(t('commit.cancel'));
73022
73023         var saveButton = buttonSection
73024             .append('button')
73025             .attr('class', 'action col5 button save-button')
73026             .attr('disabled', function() {
73027                 var n = select('.commit-form textarea').node();
73028                 return (n && n.value.length) ? null : true;
73029             })
73030             .on('click.save', function() {
73031                 dispatch$$1.call('save', this, changeset);
73032             });
73033
73034         saveButton
73035             .append('span')
73036             .attr('class', 'label')
73037             .text(t('commit.save'));
73038
73039
73040         // Raw Tag Editor
73041         var tagSection = body
73042             .append('div')
73043             .attr('class', 'modal-section tag-section raw-tag-editor');
73044
73045
73046         // Changes
73047         var changeSection = body
73048             .append('div')
73049             .attr('class', 'commit-section modal-section fillL2');
73050
73051         changeSection.append('h3')
73052             .text(t('commit.changes', { count: summary.length }));
73053
73054         var li = changeSection
73055             .append('ul')
73056             .attr('class', 'changeset-list')
73057             .selectAll('li')
73058             .data(summary);
73059
73060         li = li.enter()
73061             .append('li')
73062             .on('mouseover', mouseover)
73063             .on('mouseout', mouseout)
73064             .on('click', zoomToEntity)
73065             .merge(li);
73066
73067         li.each(function(d) {
73068             select(this)
73069                 .call(svgIcon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
73070         });
73071
73072         li.append('span')
73073             .attr('class', 'change-type')
73074             .text(function(d) { return t('commit.' + d.changeType) + ' '; });
73075
73076         li.append('strong')
73077             .attr('class', 'entity-type')
73078             .text(function(d) {
73079                 var matched = context.presets().match(d.entity, d.graph);
73080                 return (matched && matched.name()) || utilDisplayType(d.entity.id);
73081             });
73082
73083         li.append('span')
73084             .attr('class', 'entity-name')
73085             .text(function(d) {
73086                 var name = utilDisplayName(d.entity) || '',
73087                     string = '';
73088                 if (name !== '') string += ':';
73089                 return string += ' ' + name;
73090             });
73091
73092         li.style('opacity', 0)
73093             .transition()
73094             .style('opacity', 1);
73095
73096
73097         // Call change() off the bat, in case a changeset
73098         // comment is recovered from localStorage
73099         utilTriggerEvent(commentField, 'input');
73100
73101
73102         function mouseover(d) {
73103             if (d.entity) {
73104                 context.surface().selectAll(
73105                     utilEntityOrMemberSelector([d.entity.id], context.graph())
73106                 ).classed('hover', true);
73107             }
73108         }
73109
73110
73111         function mouseout() {
73112             context.surface().selectAll('.hover')
73113                 .classed('hover', false);
73114         }
73115
73116
73117         function warningClick(d) {
73118             if (d.entity) {
73119                 context.map().zoomTo(d.entity);
73120                 context.enter(modeSelect(context, [d.entity.id]));
73121             }
73122         }
73123
73124
73125         function zoomToEntity(change) {
73126             var entity = change.entity;
73127             if (change.changeType !== 'deleted' &&
73128                 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
73129                 context.map().zoomTo(entity);
73130                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
73131                     .classed('hover', true);
73132             }
73133         }
73134
73135
73136         function checkComment(comment) {
73137             // Save button disabled if there is no comment..
73138             selectAll('.save-section .save-button')
73139                 .attr('disabled', (comment.length ? null : true));
73140
73141             // Warn if comment mentions Google..
73142             var googleWarning = clippyArea
73143                .html('')
73144                .selectAll('a')
73145                .data(comment.match(/google/i) ? [true] : []);
73146
73147             googleWarning.exit()
73148                 .remove();
73149
73150             googleWarning.enter()
73151                .append('a')
73152                .attr('target', '_blank')
73153                .attr('tabindex', -1)
73154                .call(svgIcon('#icon-alert', 'inline'))
73155                .attr('href', t('commit.google_warning_link'))
73156                .append('span')
73157                .text(t('commit.google_warning'));
73158         }
73159
73160
73161         function change(onInput) {
73162             return function() {
73163                 var comment = commentField.property('value').trim();
73164                 if (!onInput) {
73165                     commentField.property('value', comment);
73166                 }
73167
73168                 checkComment(comment);
73169
73170                 var changeset = updateChangeset({ comment: comment });
73171                 var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
73172
73173                 tagSection
73174                     .call(rawTagEditor
73175                         .expanded(expanded)
73176                         .readOnlyTags(readOnlyTags)
73177                         .tags(lodash.clone(changeset.tags))
73178                     );
73179             };
73180         }
73181
73182
73183         function changeTags(changed) {
73184             if (changed.hasOwnProperty('comment')) {
73185                 if (changed.comment === undefined) {
73186                     changed.comment = '';
73187                 }
73188                 changed.comment = changed.comment.trim();
73189                 commentField.property('value', changed.comment);
73190             }
73191             updateChangeset(changed);
73192             utilTriggerEvent(commentField, 'input');
73193         }
73194
73195
73196         function updateChangeset(changed) {
73197             var tags = lodash.clone(changeset.tags);
73198
73199             lodash.forEach(changed, function(v, k) {
73200                 k = k.trim().substr(0, 255);
73201                 if (readOnlyTags.indexOf(k) !== -1) return;
73202
73203                 if (k !== '' && v !== undefined) {
73204                     tags[k] = v.trim().substr(0, 255);
73205                 } else {
73206                     delete tags[k];
73207                 }
73208             });
73209
73210             if (!lodash.isEqual(changeset.tags, tags)) {
73211                 changeset = changeset.update({ tags: tags });
73212             }
73213
73214             return changeset;
73215         }
73216
73217     }
73218
73219
73220     commit.reset = function() {
73221         changeset = null;
73222     };
73223
73224
73225     return utilRebind(commit, dispatch$$1, 'on');
73226 }
73227
73228 function uiConfirm(selection) {
73229     var modalSelection = uiModal(selection);
73230
73231     modalSelection.select('.modal')
73232         .classed('modal-alert', true);
73233
73234     var section = modalSelection.select('.content');
73235
73236     section.append('div')
73237         .attr('class', 'modal-section header');
73238
73239     section.append('div')
73240         .attr('class', 'modal-section message-text');
73241
73242     var buttons = section.append('div')
73243         .attr('class', 'modal-section buttons cf');
73244
73245
73246     modalSelection.okButton = function() {
73247         buttons
73248             .append('button')
73249             .attr('class', 'action col4')
73250             .on('click.confirm', function() {
73251                 modalSelection.remove();
73252             })
73253             .text(t('confirm.okay'));
73254
73255         return modalSelection;
73256     };
73257
73258
73259     return modalSelection;
73260 }
73261
73262 function uiConflicts(context) {
73263     var dispatch$$1 = dispatch('download', 'cancel', 'save'),
73264         list;
73265
73266
73267     function conflicts(selection$$1) {
73268         var header = selection$$1
73269             .append('div')
73270             .attr('class', 'header fillL');
73271
73272         header
73273             .append('button')
73274             .attr('class', 'fr')
73275             .on('click', function() { dispatch$$1.call('cancel'); })
73276             .call(svgIcon('#icon-close'));
73277
73278         header
73279             .append('h3')
73280             .text(t('save.conflict.header'));
73281
73282         var body = selection$$1
73283             .append('div')
73284             .attr('class', 'body fillL');
73285
73286         body
73287             .append('div')
73288             .attr('class', 'conflicts-help')
73289             .text(t('save.conflict.help'))
73290             .append('a')
73291             .attr('class', 'conflicts-download')
73292             .text(t('save.conflict.download_changes'))
73293             .on('click.download', function() { dispatch$$1.call('download'); });
73294
73295         body
73296             .append('div')
73297             .attr('class', 'conflict-container fillL3')
73298             .call(showConflict, 0);
73299
73300         body
73301             .append('div')
73302             .attr('class', 'conflicts-done')
73303             .attr('opacity', 0)
73304             .style('display', 'none')
73305             .text(t('save.conflict.done'));
73306
73307         var buttons = body
73308             .append('div')
73309             .attr('class','buttons col12 joined conflicts-buttons');
73310
73311         buttons
73312             .append('button')
73313             .attr('disabled', list.length > 1)
73314             .attr('class', 'action conflicts-button col6')
73315             .text(t('save.title'))
73316             .on('click.try_again', function() { dispatch$$1.call('save'); });
73317
73318         buttons
73319             .append('button')
73320             .attr('class', 'secondary-action conflicts-button col6')
73321             .text(t('confirm.cancel'))
73322             .on('click.cancel', function() { dispatch$$1.call('cancel'); });
73323     }
73324
73325
73326     function showConflict(selection$$1, index) {
73327         if (index < 0 || index >= list.length) return;
73328
73329         var parent = select(selection$$1.node().parentNode);
73330
73331         // enable save button if this is the last conflict being reviewed..
73332         if (index === list.length - 1) {
73333             window.setTimeout(function() {
73334                 parent.select('.conflicts-button')
73335                     .attr('disabled', null);
73336
73337                 parent.select('.conflicts-done')
73338                     .transition()
73339                     .attr('opacity', 1)
73340                     .style('display', 'block');
73341             }, 250);
73342         }
73343
73344         var item = selection$$1
73345             .selectAll('.conflict')
73346             .data([list[index]]);
73347
73348         var enter = item.enter()
73349             .append('div')
73350             .attr('class', 'conflict');
73351
73352         enter
73353             .append('h4')
73354             .attr('class', 'conflict-count')
73355             .text(t('save.conflict.count', { num: index + 1, total: list.length }));
73356
73357         enter
73358             .append('a')
73359             .attr('class', 'conflict-description')
73360             .attr('href', '#')
73361             .text(function(d) { return d.name; })
73362             .on('click', function(d) {
73363                 zoomToEntity(d.id);
73364                 event.preventDefault();
73365             });
73366
73367         var details = enter
73368             .append('div')
73369             .attr('class', 'conflict-detail-container');
73370
73371         details
73372             .append('ul')
73373             .attr('class', 'conflict-detail-list')
73374             .selectAll('li')
73375             .data(function(d) { return d.details || []; })
73376             .enter()
73377             .append('li')
73378             .attr('class', 'conflict-detail-item')
73379             .html(function(d) { return d; });
73380
73381         details
73382             .append('div')
73383             .attr('class', 'conflict-choices')
73384             .call(addChoices);
73385
73386         details
73387             .append('div')
73388             .attr('class', 'conflict-nav-buttons joined cf')
73389             .selectAll('button')
73390             .data(['previous', 'next'])
73391             .enter()
73392             .append('button')
73393             .text(function(d) { return t('save.conflict.' + d); })
73394             .attr('class', 'conflict-nav-button action col6')
73395             .attr('disabled', function(d, i) {
73396                 return (i === 0 && index === 0) ||
73397                     (i === 1 && index === list.length - 1) || null;
73398             })
73399             .on('click', function(d, i) {
73400                 var container = parent.select('.conflict-container'),
73401                 sign = (i === 0 ? -1 : 1);
73402
73403                 container
73404                     .selectAll('.conflict')
73405                     .remove();
73406
73407                 container
73408                     .call(showConflict, index + sign);
73409
73410                 event.preventDefault();
73411             });
73412
73413         item.exit()
73414             .remove();
73415     }
73416
73417
73418     function addChoices(selection$$1) {
73419         var choices = selection$$1
73420             .append('ul')
73421             .attr('class', 'layer-list')
73422             .selectAll('li')
73423             .data(function(d) { return d.choices || []; });
73424
73425         var enter = choices.enter()
73426             .append('li')
73427             .attr('class', 'layer');
73428
73429         var label = enter
73430             .append('label');
73431
73432         label
73433             .append('input')
73434             .attr('type', 'radio')
73435             .attr('name', function(d) { return d.id; })
73436             .on('change', function(d, i) {
73437                 var ul = this.parentNode.parentNode.parentNode;
73438                 ul.__data__.chosen = i;
73439                 choose(ul, d);
73440             });
73441
73442         label
73443             .append('span')
73444             .text(function(d) { return d.text; });
73445
73446         choices
73447             .each(function(d, i) {
73448                 var ul = this.parentNode;
73449                 if (ul.__data__.chosen === i) choose(ul, d);
73450             });
73451     }
73452
73453
73454     function choose(ul, datum) {
73455         if (event) event.preventDefault();
73456
73457         select(ul)
73458             .selectAll('li')
73459             .classed('active', function(d) { return d === datum; })
73460             .selectAll('input')
73461             .property('checked', function(d) { return d === datum; });
73462
73463         var extent$$1 = geoExtent$$1(),
73464             entity;
73465
73466         entity = context.graph().hasEntity(datum.id);
73467         if (entity) extent$$1._extend(entity.extent(context.graph()));
73468
73469         datum.action();
73470
73471         entity = context.graph().hasEntity(datum.id);
73472         if (entity) extent$$1._extend(entity.extent(context.graph()));
73473
73474         zoomToEntity(datum.id, extent$$1);
73475     }
73476
73477
73478     function zoomToEntity(id, extent$$1) {
73479         context.surface().selectAll('.hover')
73480             .classed('hover', false);
73481
73482         var entity = context.graph().hasEntity(id);
73483         if (entity) {
73484             if (extent$$1) {
73485                 context.map().trimmedExtent(extent$$1);
73486             } else {
73487                 context.map().zoomTo(entity);
73488             }
73489             context.surface().selectAll(
73490                 utilEntityOrMemberSelector([entity.id], context.graph()))
73491                 .classed('hover', true);
73492         }
73493     }
73494
73495
73496     // The conflict list should be an array of objects like:
73497     // {
73498     //     id: id,
73499     //     name: entityName(local),
73500     //     details: merge.conflicts(),
73501     //     chosen: 1,
73502     //     choices: [
73503     //         choice(id, keepMine, forceLocal),
73504     //         choice(id, keepTheirs, forceRemote)
73505     //     ]
73506     // }
73507     conflicts.list = function(_) {
73508         if (!arguments.length) return list;
73509         list = _;
73510         return conflicts;
73511     };
73512
73513
73514     return utilRebind(conflicts, dispatch$$1, 'on');
73515 }
73516
73517 function uiEditMenu(context, operations) {
73518     var menu,
73519         center = [0, 0],
73520         offset = [0, 0],
73521         tooltip;
73522
73523     var p = 8,               // top padding
73524         m = 4,               // top margin
73525         h = 15,              // height of icon
73526         vpBottomMargin = 45, // viewport bottom margin
73527         vpSideMargin = 35,   // viewport side margin
73528         buttonWidth = 44,
73529         buttonHeight = (2 * p + h),
73530         menuWidth = buttonWidth,
73531         menuHeight = (2 * m) + operations.length * buttonHeight,
73532         menuSideMargin = 10,
73533         tooltipWidth = 200,
73534         tooltipHeight = 200;  // a reasonable guess, real height depends on tooltip contents
73535
73536
73537     var editMenu = function (selection$$1) {
73538         if (!operations.length) return;
73539
73540         selection$$1.node().parentNode.focus();
73541
73542         var isRTL = textDirection === 'rtl',
73543             viewport = context.surfaceRect();
73544
73545         if (!isRTL && (center[0] + menuSideMargin + menuWidth) > (viewport.width - vpSideMargin)) {
73546             // menu is going left-to-right and near right viewport edge, go left instead
73547             isRTL = true;
73548         } else if (isRTL && (center[0] - menuSideMargin - menuWidth) < vpSideMargin) {
73549             // menu is going right-to-left and near left viewport edge, go right instead
73550             isRTL = false;
73551         }
73552
73553         offset[0] = (isRTL ? -1 * (menuSideMargin + menuWidth) : menuSideMargin);
73554
73555         if (center[1] + menuHeight > (viewport.height - vpBottomMargin)) {
73556             // menu is near bottom viewport edge, shift upwards
73557             offset[1] = -1 * (center[1] + menuHeight - viewport.height + vpBottomMargin);
73558         }
73559
73560         var origin = [ center[0] + offset[0], center[1] + offset[1] ];
73561
73562         menu = selection$$1
73563             .append('g')
73564             .attr('class', 'edit-menu')
73565             .attr('transform', 'translate(' + origin + ')')
73566             .attr('opacity', 0);
73567
73568         menu
73569             .transition()
73570             .attr('opacity', 1);
73571
73572         menu
73573             .append('rect')
73574             .attr('class', 'edit-menu-background')
73575             .attr('x', 4)
73576             .attr('rx', 4)
73577             .attr('ry', 4)
73578             .attr('width', menuWidth)
73579             .attr('height', menuHeight)
73580             .attr('stroke-linecap', 'round');
73581
73582
73583         var button = menu.selectAll('.edit-menu-item')
73584             .data(operations)
73585             .enter()
73586             .append('g')
73587             .attr('class', function (d) { return 'edit-menu-item edit-menu-item-' + d.id; })
73588             .classed('disabled', function (d) { return d.disabled(); })
73589             .attr('transform', function (d, i) {
73590                 return 'translate(' + geoRoundCoords([
73591                     0,
73592                     m + i * buttonHeight
73593                 ]).join(',') + ')';
73594             });
73595
73596         button
73597             .append('rect')
73598             .attr('x', 4)
73599             .attr('width', buttonWidth)
73600             .attr('height', buttonHeight)
73601             .on('click', click)
73602             .on('mousedown', mousedown)
73603             .on('mouseover', mouseover)
73604             .on('mouseout', mouseout);
73605
73606         button
73607             .append('use')
73608             .attr('width', '20')
73609             .attr('height', '20')
73610             .attr('transform', function () {
73611                 return 'translate(' + [2 * p, 5] + ')';
73612             })
73613             .attr('xlink:href', function (d) { return '#operation-' + d.id; });
73614
73615         tooltip = select(document.body)
73616             .append('div')
73617             .attr('class', 'tooltip-inner edit-menu-tooltip');
73618
73619
73620         function click(operation) {
73621             event.stopPropagation();
73622             if (operation.disabled()) return;
73623             operation();
73624             editMenu.close();
73625         }
73626
73627         function mousedown() {
73628             event.stopPropagation();  // https://github.com/openstreetmap/iD/issues/1869
73629         }
73630
73631         function mouseover(d, i) {
73632             var tipX, tipY;
73633
73634             if (!isRTL) {
73635                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
73636             } else {
73637                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
73638             }
73639
73640             if (tipX + tooltipWidth > viewport.right) {
73641                 // tip is going left-to-right and near right viewport edge, go left instead
73642                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
73643             } else if (tipX < viewport.left) {
73644                 // tip is going right-to-left and near left viewport edge, go right instead
73645                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
73646             }
73647
73648             tipY = viewport.top + origin[1] + (i * buttonHeight);
73649             if (tipY + tooltipHeight > viewport.bottom) {
73650                 // tip is near bottom viewport edge, shift upwards
73651                 tipY -= tipY + tooltipHeight - viewport.bottom;
73652             }
73653
73654             tooltip
73655                 .style('left', tipX + 'px')
73656                 .style('top', tipY + 'px')
73657                 .style('display', 'block')
73658                 .html(uiTooltipHtml(d.tooltip(), d.keys[0], d.title));
73659         }
73660
73661         function mouseout() {
73662             tooltip.style('display', 'none');
73663         }
73664     };
73665
73666
73667     editMenu.close = function () {
73668         if (menu) {
73669             menu
73670                 .style('pointer-events', 'none')
73671                 .transition()
73672                 .attr('opacity', 0)
73673                 .remove();
73674         }
73675
73676         if (tooltip) {
73677             tooltip.remove();
73678         }
73679     };
73680
73681
73682     editMenu.center = function (_) {
73683         if (!arguments.length) return center;
73684         center = _;
73685         return editMenu;
73686     };
73687
73688
73689     return editMenu;
73690 }
73691
73692 var timer$1;
73693
73694 function uiFlash(showDuration) {
73695     showDuration = showDuration || 1500;
73696
73697     if (timer$1) {
73698         timer$1.stop();
73699     }
73700
73701     select('#footer-wrap')
73702         .attr('class', 'footer-hide');
73703     select('#flash-wrap')
73704         .attr('class', 'footer-show');
73705
73706     var content = select('#flash-wrap').selectAll('.content')
73707         .data([0]);
73708
73709     content = content.enter()
73710         .append('div')
73711         .attr('class', 'content')
73712         .merge(content);
73713
73714     timer$1 = timeout$1(function() {
73715         timer$1 = null;
73716         select('#footer-wrap')
73717             .attr('class', 'footer-show');
73718         select('#flash-wrap')
73719             .attr('class', 'footer-hide');
73720     }, showDuration);
73721
73722
73723     return content;
73724 }
73725
73726 function uiLasso(context) {
73727     var group, polygon;
73728
73729     lasso.coordinates = [];
73730
73731     function lasso(selection$$1) {
73732         context.container()
73733             .classed('lasso', true);
73734
73735         group = selection$$1
73736             .append('g')
73737             .attr('class', 'lasso hide');
73738
73739         polygon = group
73740             .append('path')
73741             .attr('class', 'lasso-path');
73742
73743         group
73744             .call(uiToggle(true));
73745     }
73746
73747
73748     function draw() {
73749         if (polygon) {
73750             polygon.data([lasso.coordinates])
73751                 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
73752         }
73753     }
73754
73755
73756     lasso.extent = function () {
73757         return lasso.coordinates.reduce(function(extent$$1, point) {
73758             return extent$$1.extend(geoExtent$$1(point));
73759         }, geoExtent$$1());
73760     };
73761
73762
73763     lasso.p = function(_) {
73764         if (!arguments.length) return lasso;
73765         lasso.coordinates.push(_);
73766         draw();
73767         return lasso;
73768     };
73769
73770
73771     lasso.close = function() {
73772         if (group) {
73773             group.call(uiToggle(false, function() {
73774                 select(this).remove();
73775             }));
73776         }
73777         context.container().classed('lasso', false);
73778     };
73779
73780
73781     return lasso;
73782 }
73783
73784 function uiRadialMenu(context, operations) {
73785     var menu,
73786         center = [0, 0],
73787         tooltip;
73788
73789
73790     var radialMenu = function(selection$$1) {
73791         if (!operations.length) return;
73792
73793         selection$$1.node().parentNode.focus();
73794
73795         function click(operation) {
73796             event.stopPropagation();
73797             if (operation.disabled()) return;
73798             operation();
73799             radialMenu.close();
73800         }
73801
73802         menu = selection$$1
73803             .append('g')
73804             .attr('class', 'radial-menu')
73805             .attr('transform', 'translate(' + center + ')')
73806             .attr('opacity', 0);
73807
73808         menu
73809             .transition()
73810             .attr('opacity', 1);
73811
73812         var r = 50,
73813             a = Math.PI / 4,
73814             a0 = -Math.PI / 4,
73815             a1 = a0 + (operations.length - 1) * a;
73816
73817         menu
73818             .append('path')
73819             .attr('class', 'radial-menu-background')
73820             .attr('d', 'M' + r * Math.sin(a0) + ',' +
73821                              r * Math.cos(a0) +
73822                       ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
73823                              (r * Math.sin(a1) + 1e-3) + ',' +
73824                              (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
73825             .attr('stroke-width', 50)
73826             .attr('stroke-linecap', 'round');
73827
73828         var button = menu.selectAll()
73829             .data(operations)
73830             .enter()
73831             .append('g')
73832             .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
73833             .classed('disabled', function(d) { return d.disabled(); })
73834             .attr('transform', function(d, i) {
73835                 return 'translate(' + geoRoundCoords([
73836                         r * Math.sin(a0 + i * a),
73837                         r * Math.cos(a0 + i * a)]).join(',') + ')';
73838             });
73839
73840         button
73841             .append('circle')
73842             .attr('r', 15)
73843             .on('click', click)
73844             .on('mousedown', mousedown)
73845             .on('mouseover', mouseover)
73846             .on('mouseout', mouseout);
73847
73848         button
73849             .append('use')
73850             .attr('transform', 'translate(-10,-10)')
73851             .attr('width', '20')
73852             .attr('height', '20')
73853             .attr('xlink:href', function(d) { return '#operation-' + d.id; });
73854
73855         tooltip = select(document.body)
73856             .append('div')
73857             .attr('class', 'tooltip-inner radial-menu-tooltip');
73858
73859         function mousedown() {
73860             event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
73861         }
73862
73863         function mouseover(d, i) {
73864             var rect = context.surfaceRect(),
73865                 angle = a0 + i * a,
73866                 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
73867                 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
73868                 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
73869                 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
73870
73871             tooltip
73872                 .style('top', null)
73873                 .style('left', null)
73874                 .style('bottom', null)
73875                 .style('right', null)
73876                 .style('display', 'block')
73877                 .html(uiTooltipHtml(d.tooltip(), d.keys[0]));
73878
73879             if (i === 0) {
73880                 tooltip
73881                     .style('right', right)
73882                     .style('top', top);
73883             } else if (i >= 4) {
73884                 tooltip
73885                     .style('left', left)
73886                     .style('bottom', bottom);
73887             } else {
73888                 tooltip
73889                     .style('left', left)
73890                     .style('top', top);
73891             }
73892         }
73893
73894         function mouseout() {
73895             tooltip.style('display', 'none');
73896         }
73897     };
73898
73899
73900     radialMenu.close = function() {
73901         if (menu) {
73902             menu
73903                 .style('pointer-events', 'none')
73904                 .transition()
73905                 .attr('opacity', 0)
73906                 .remove();
73907         }
73908
73909         if (tooltip) {
73910             tooltip.remove();
73911         }
73912     };
73913
73914
73915     radialMenu.center = function(_) {
73916         if (!arguments.length) return center;
73917         center = _;
73918         return radialMenu;
73919     };
73920
73921
73922     return radialMenu;
73923 }
73924
73925 function uiSelectionList(context, selectedIDs) {
73926
73927     function selectEntity(entity) {
73928         context.enter(modeSelect(context, [entity.id]));
73929     }
73930
73931
73932     function deselectEntity(entity) {
73933         event.stopPropagation();
73934         var index = selectedIDs.indexOf(entity.id);
73935         if (index > -1) {
73936             selectedIDs.splice(index, 1);
73937         }
73938         context.enter(modeSelect(context, selectedIDs));
73939     }
73940
73941
73942     function selectionList(selection$$1) {
73943         selection$$1.classed('selection-list-pane', true);
73944
73945         var header = selection$$1
73946             .append('div')
73947             .attr('class', 'header fillL cf');
73948
73949         header
73950             .append('h3')
73951             .text(t('inspector.multiselect'));
73952
73953         var listWrap = selection$$1
73954             .append('div')
73955             .attr('class', 'inspector-body');
73956
73957         var list = listWrap
73958             .append('div')
73959             .attr('class', 'feature-list cf');
73960
73961         context.history().on('change.selection-list', drawList);
73962         drawList();
73963
73964
73965         function drawList() {
73966             var entities = selectedIDs
73967                 .map(function(id) { return context.hasEntity(id); })
73968                 .filter(function(entity) { return entity; });
73969
73970             var items = list.selectAll('.feature-list-item')
73971                 .data(entities, osmEntity$$1.key);
73972
73973             items.exit()
73974                 .remove();
73975
73976             // Enter
73977             var enter = items.enter()
73978                 .append('div')
73979                 .attr('class', 'feature-list-item')
73980                 .on('click', selectEntity);
73981
73982             var label = enter
73983                 .append('button')
73984                 .attr('class', 'label');
73985
73986             enter
73987                 .append('button')
73988                 .attr('class', 'close')
73989                 .on('click', deselectEntity)
73990                 .call(svgIcon('#icon-close'));
73991
73992             label
73993                 .append('span')
73994                 .attr('class', 'entity-geom-icon')
73995                 .call(svgIcon('', 'pre-text'));
73996
73997             label
73998                 .append('span')
73999                 .attr('class', 'entity-type');
74000
74001             label
74002                 .append('span')
74003                 .attr('class', 'entity-name');
74004
74005             // Update
74006             items = items.merge(enter);
74007
74008             items.selectAll('.entity-geom-icon use')
74009                 .attr('href', function() {
74010                     var entity = this.parentNode.parentNode.__data__;
74011                     return '#icon-' + context.geometry(entity.id);
74012                 });
74013
74014             items.selectAll('.entity-type')
74015                 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
74016
74017             items.selectAll('.entity-name')
74018                 .text(function(entity) { return utilDisplayName(entity); });
74019         }
74020     }
74021
74022     return selectionList;
74023 }
74024
74025 function uiSourceSwitch(context) {
74026     var keys$$1;
74027
74028
74029     function click() {
74030         event.preventDefault();
74031
74032         if (context.history().hasChanges() &&
74033             !window.confirm(t('source_switch.lose_changes'))) return;
74034
74035         var live = select(this)
74036             .classed('live');
74037
74038         context.connection()
74039             .switch(live ? keys$$1[1] : keys$$1[0]);
74040
74041         context.enter(modeBrowse(context));
74042         context.flush();
74043
74044         select(this)
74045             .text(live ? t('source_switch.dev') : t('source_switch.live'))
74046             .classed('live', !live);
74047     }
74048
74049     var sourceSwitch = function(selection$$1) {
74050         selection$$1
74051             .append('a')
74052             .attr('href', '#')
74053             .text(t('source_switch.live'))
74054             .classed('live', true)
74055             .attr('tabindex', -1)
74056             .on('click', click);
74057     };
74058
74059
74060     sourceSwitch.keys = function(_) {
74061         if (!arguments.length) return keys$$1;
74062         keys$$1 = _;
74063         return sourceSwitch;
74064     };
74065
74066
74067     return sourceSwitch;
74068 }
74069
74070 function uiSuccess(context) {
74071     var dispatch$$1 = dispatch('cancel'),
74072         changeset;
74073
74074
74075     function success(selection$$1) {
74076         var header = selection$$1
74077             .append('div')
74078             .attr('class', 'header fillL');
74079
74080         header
74081             .append('button')
74082             .attr('class', 'fr')
74083             .on('click', function() { dispatch$$1.call('cancel'); })
74084             .call(svgIcon('#icon-close'));
74085
74086         header
74087             .append('h3')
74088             .text(t('success.just_edited'));
74089
74090         var body = selection$$1
74091             .append('div')
74092             .attr('class', 'body save-success fillL');
74093
74094         body
74095             .append('p')
74096             .html(t('success.help_html'));
74097
74098         body
74099             .append('a')
74100             .attr('class', 'details')
74101             .attr('target', '_blank')
74102             .attr('tabindex', -1)
74103             .call(svgIcon('#icon-out-link', 'inline'))
74104             .attr('href', t('success.help_link_url'))
74105             .append('span')
74106             .text(t('success.help_link_text'));
74107
74108         var changesetURL = context.connection().changesetURL(changeset.id);
74109
74110
74111         var viewOnOsm = body
74112             .append('a')
74113             .attr('class', 'button col12 osm')
74114             .attr('target', '_blank')
74115             .attr('href', changesetURL);
74116
74117         viewOnOsm
74118             .append('svg')
74119             .attr('class', 'logo logo-osm')
74120             .append('use')
74121             .attr('xlink:href', '#logo-osm');
74122
74123         viewOnOsm
74124             .append('div')
74125             .text(t('success.view_on_osm'));
74126
74127
74128         var message = (changeset.tags.comment || t('success.edited_osm')).substring(0, 130) +
74129             ' ' + context.connection().changesetURL(changeset.id);
74130
74131         var sharing = {
74132             facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
74133             twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
74134             google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
74135         };
74136
74137         body.selectAll('.button.social')
74138             .data(entries(sharing))
74139             .enter()
74140             .append('a')
74141             .attr('class', 'button social col4')
74142             .attr('target', '_blank')
74143             .attr('href', function(d) { return d.value; })
74144             .call(tooltip()
74145                 .title(function(d) { return t('success.' + d.key); })
74146                 .placement('bottom'))
74147             .each(function(d) { select(this).call(svgIcon('#logo-' + d.key, 'social')); });
74148     }
74149
74150
74151     success.changeset = function(_) {
74152         if (!arguments.length) return changeset;
74153         changeset = _;
74154         return success;
74155     };
74156
74157
74158     return utilRebind(success, dispatch$$1, 'on');
74159 }
74160
74161 function coreHistory(context) {
74162     var imageryUsed = ['Bing'],
74163         dispatch$$1 = dispatch('change', 'undone', 'redone'),
74164         lock = utilSessionMutex('lock'),
74165         duration = 150,
74166         checkpoints = {},
74167         stack$$1, index, tree$$1;
74168
74169
74170     // internal _act, accepts list of actions and eased time
74171     function _act(actions, t) {
74172         actions = Array.prototype.slice.call(actions);
74173
74174         var annotation;
74175
74176         if (!lodash.isFunction(lodash.last(actions))) {
74177             annotation = actions.pop();
74178         }
74179
74180         stack$$1[index].transform = context.projection.transform();
74181         stack$$1[index].selectedIDs = context.selectedIDs();
74182
74183         var graph = stack$$1[index].graph;
74184         for (var i = 0; i < actions.length; i++) {
74185             graph = actions[i](graph, t);
74186         }
74187
74188         return {
74189             graph: graph,
74190             annotation: annotation,
74191             imageryUsed: imageryUsed
74192         };
74193     }
74194
74195
74196     // internal _perform with eased time
74197     function _perform(args, t) {
74198         var previous = stack$$1[index].graph;
74199         stack$$1 = stack$$1.slice(0, index + 1);
74200         stack$$1.push(_act(args, t));
74201         index++;
74202         return change(previous);
74203     }
74204
74205
74206     // internal _replace with eased time
74207     function _replace(args, t) {
74208         var previous = stack$$1[index].graph;
74209         // assert(index == stack.length - 1)
74210         stack$$1[index] = _act(args, t);
74211         return change(previous);
74212     }
74213
74214
74215     // internal _overwrite with eased time
74216     function _overwrite(args, t) {
74217         var previous = stack$$1[index].graph;
74218         if (index > 0) {
74219             index--;
74220             stack$$1.pop();
74221         }
74222         stack$$1 = stack$$1.slice(0, index + 1);
74223         stack$$1.push(_act(args, t));
74224         index++;
74225         return change(previous);
74226     }
74227
74228
74229     // determine diffrence and dispatch a change event
74230     function change(previous) {
74231         var difference = coreDifference(previous, history.graph());
74232         dispatch$$1.call('change', this, difference);
74233         return difference;
74234     }
74235
74236
74237     // iD uses namespaced keys so multiple installations do not conflict
74238     function getKey(n) {
74239         return 'iD_' + window.location.origin + '_' + n;
74240     }
74241
74242
74243     var history = {
74244
74245         graph: function() {
74246             return stack$$1[index].graph;
74247         },
74248
74249
74250         base: function() {
74251             return stack$$1[0].graph;
74252         },
74253
74254
74255         merge: function(entities, extent$$1) {
74256             stack$$1[0].graph.rebase(entities, lodash.map(stack$$1, 'graph'), false);
74257             tree$$1.rebase(entities, false);
74258
74259             dispatch$$1.call('change', this, undefined, extent$$1);
74260         },
74261
74262
74263         perform: function() {
74264             // complete any transition already in progress
74265             select(document).interrupt('history.perform');
74266
74267             var transitionable = false,
74268                 action0 = arguments[0];
74269
74270             if (arguments.length === 1 ||
74271                 arguments.length === 2 && !lodash.isFunction(arguments[1])) {
74272                 transitionable = !!action0.transitionable;
74273             }
74274
74275             if (transitionable) {
74276                 var origArguments = arguments;
74277                 select(document)
74278                     .transition('history.perform')
74279                     .duration(duration)
74280                     .ease(linear$1)
74281                     .tween('history.tween', function() {
74282                         return function(t) {
74283                             if (t < 1) _overwrite([action0], t);
74284                         };
74285                     })
74286                     .on('start', function() {
74287                         _perform([action0], 0);
74288                     })
74289                     .on('end interrupt', function() {
74290                         _overwrite(origArguments, 1);
74291                     });
74292
74293             } else {
74294                 return _perform(arguments);
74295             }
74296         },
74297
74298
74299         replace: function() {
74300             select(document).interrupt('history.perform');
74301             return _replace(arguments, 1);
74302         },
74303
74304
74305         // Same as calling pop and then perform
74306         overwrite: function() {
74307             select(document).interrupt('history.perform');
74308             return _overwrite(arguments, 1);
74309         },
74310
74311
74312         pop: function(n) {
74313             select(document).interrupt('history.perform');
74314
74315             var previous = stack$$1[index].graph;
74316             if (isNaN(+n) || +n < 0) {
74317                 n = 1;
74318             }
74319             while (n-- > 0 && index > 0) {
74320                 index--;
74321                 stack$$1.pop();
74322             }
74323             return change(previous);
74324         },
74325
74326
74327         // Back to the previous annotated state or index = 0.
74328         undo: function() {
74329             select(document).interrupt('history.perform');
74330
74331             var previous = stack$$1[index].graph;
74332             while (index > 0) {
74333                 index--;
74334                 if (stack$$1[index].annotation) break;
74335             }
74336
74337             dispatch$$1.call('undone', this, stack$$1[index]);
74338             return change(previous);
74339         },
74340
74341
74342         // Forward to the next annotated state.
74343         redo: function() {
74344             select(document).interrupt('history.perform');
74345
74346             var previous = stack$$1[index].graph;
74347             var tryIndex = index;
74348             while (tryIndex < stack$$1.length - 1) {
74349                 tryIndex++;
74350                 if (stack$$1[tryIndex].annotation) {
74351                     index = tryIndex;
74352                     dispatch$$1.call('redone', this, stack$$1[index]);
74353                     break;
74354                 }
74355             }
74356
74357             return change(previous);
74358         },
74359
74360
74361         undoAnnotation: function() {
74362             var i = index;
74363             while (i >= 0) {
74364                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
74365                 i--;
74366             }
74367         },
74368
74369
74370         redoAnnotation: function() {
74371             var i = index + 1;
74372             while (i <= stack$$1.length - 1) {
74373                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
74374                 i++;
74375             }
74376         },
74377
74378
74379         intersects: function(extent$$1) {
74380             return tree$$1.intersects(extent$$1, stack$$1[index].graph);
74381         },
74382
74383
74384         difference: function() {
74385             var base = stack$$1[0].graph,
74386                 head = stack$$1[index].graph;
74387             return coreDifference(base, head);
74388         },
74389
74390
74391         changes: function(action) {
74392             var base = stack$$1[0].graph,
74393                 head = stack$$1[index].graph;
74394
74395             if (action) {
74396                 head = action(head);
74397             }
74398
74399             var difference = coreDifference(base, head);
74400
74401             return {
74402                 modified: difference.modified(),
74403                 created: difference.created(),
74404                 deleted: difference.deleted()
74405             };
74406         },
74407
74408
74409         validate: function(changes) {
74410             return lodash(Validations)
74411                 .map(function(fn) { return fn()(changes, stack$$1[index].graph); })
74412                 .flatten()
74413                 .value();
74414         },
74415
74416
74417         hasChanges: function() {
74418             return this.difference().length() > 0;
74419         },
74420
74421
74422         imageryUsed: function(sources) {
74423             if (sources) {
74424                 imageryUsed = sources;
74425                 return history;
74426             } else {
74427                 return lodash(stack$$1.slice(1, index + 1))
74428                     .map('imageryUsed')
74429                     .flatten()
74430                     .uniq()
74431                     .without(undefined, 'Custom')
74432                     .value();
74433             }
74434         },
74435
74436
74437         // save the current history state
74438         checkpoint: function(key) {
74439             checkpoints[key] = {
74440                 stack: lodash.cloneDeep(stack$$1),
74441                 index: index
74442             };
74443             return history;
74444         },
74445
74446
74447         // restore history state to a given checkpoint or reset completely
74448         reset: function(key) {
74449             if (key !== undefined && checkpoints.hasOwnProperty(key)) {
74450                 stack$$1 = lodash.cloneDeep(checkpoints[key].stack);
74451                 index = checkpoints[key].index;
74452             } else {
74453                 stack$$1 = [{graph: coreGraph$$1()}];
74454                 index = 0;
74455                 tree$$1 = coreTree(stack$$1[0].graph);
74456                 checkpoints = {};
74457             }
74458             dispatch$$1.call('change');
74459             return history;
74460         },
74461
74462
74463         toIntroGraph: function() {
74464             var nextId = { n: 0, r: 0, w: 0 },
74465                 permIds = {},
74466                 graph = this.graph(),
74467                 baseEntities = {};
74468
74469             // clone base entities..
74470             lodash.forEach(graph.base().entities, function(entity) {
74471                 var copy = lodash.cloneDeepWith(entity, customizer);
74472                 baseEntities[copy.id] = copy;
74473             });
74474
74475             // replace base entities with head entities..
74476             lodash.forEach(graph.entities, function(entity, id) {
74477                 if (entity) {
74478                     var copy = lodash.cloneDeepWith(entity, customizer);
74479                     baseEntities[copy.id] = copy;
74480                 } else {
74481                     delete baseEntities[id];
74482                 }
74483             });
74484
74485             // swap temporary for permanent ids..
74486             lodash.forEach(baseEntities, function(entity) {
74487                 if (Array.isArray(entity.nodes)) {
74488                     entity.nodes = entity.nodes.map(function(node) {
74489                         return permIds[node] || node;
74490                     });
74491                 }
74492                 if (Array.isArray(entity.members)) {
74493                     entity.members = entity.members.map(function(member) {
74494                         member.id = permIds[member.id] || member.id;
74495                         return member;
74496                     });
74497                 }
74498             });
74499
74500             return JSON.stringify({ dataIntroGraph: baseEntities });
74501
74502
74503             function customizer(src) {
74504                 var copy = lodash.omit(lodash.cloneDeep(src), ['type', 'user', 'v', 'version', 'visible']);
74505                 if (lodash.isEmpty(copy.tags)) {
74506                     delete copy.tags;
74507                 }
74508
74509                 if (Array.isArray(copy.loc)) {
74510                     copy.loc[0] = +copy.loc[0].toFixed(6);
74511                     copy.loc[1] = +copy.loc[1].toFixed(6);
74512                 }
74513
74514                 var match = src.id.match(/([nrw])-\d*/);  // temporary id
74515                 if (match !== null) {
74516                     var nrw = match[1], permId;
74517                     do { permId = nrw + (++nextId[nrw]); }
74518                     while (baseEntities.hasOwnProperty(permId));
74519
74520                     copy.id = permIds[src.id] = permId;
74521                 }
74522                 return copy;
74523             }
74524         },
74525
74526
74527         toJSON: function() {
74528             if (!this.hasChanges()) return;
74529
74530             var allEntities = {},
74531                 baseEntities = {},
74532                 base = stack$$1[0];
74533
74534             var s = stack$$1.map(function(i) {
74535                 var modified = [], deleted = [];
74536
74537                 lodash.forEach(i.graph.entities, function(entity, id) {
74538                     if (entity) {
74539                         var key = osmEntity$$1.key(entity);
74540                         allEntities[key] = entity;
74541                         modified.push(key);
74542                     } else {
74543                         deleted.push(id);
74544                     }
74545
74546                     // make sure that the originals of changed or deleted entities get merged
74547                     // into the base of the stack after restoring the data from JSON.
74548                     if (id in base.graph.entities) {
74549                         baseEntities[id] = base.graph.entities[id];
74550                     }
74551                     // get originals of parent entities too
74552                     lodash.forEach(base.graph._parentWays[id], function(parentId) {
74553                         if (parentId in base.graph.entities) {
74554                             baseEntities[parentId] = base.graph.entities[parentId];
74555                         }
74556                     });
74557                 });
74558
74559                 var x = {};
74560
74561                 if (modified.length) x.modified = modified;
74562                 if (deleted.length) x.deleted = deleted;
74563                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
74564                 if (i.annotation) x.annotation = i.annotation;
74565
74566                 return x;
74567             });
74568
74569             return JSON.stringify({
74570                 version: 3,
74571                 entities: lodash.values(allEntities),
74572                 baseEntities: lodash.values(baseEntities),
74573                 stack: s,
74574                 nextIDs: osmEntity$$1.id.next,
74575                 index: index
74576             });
74577         },
74578
74579
74580         fromJSON: function(json$$1, loadChildNodes) {
74581             var h = JSON.parse(json$$1),
74582                 loadComplete = true;
74583
74584             osmEntity$$1.id.next = h.nextIDs;
74585             index = h.index;
74586
74587             if (h.version === 2 || h.version === 3) {
74588                 var allEntities = {};
74589
74590                 h.entities.forEach(function(entity) {
74591                     allEntities[osmEntity$$1.key(entity)] = osmEntity$$1(entity);
74592                 });
74593
74594                 if (h.version === 3) {
74595                     // This merges originals for changed entities into the base of
74596                     // the stack even if the current stack doesn't have them (for
74597                     // example when iD has been restarted in a different region)
74598                     var baseEntities = h.baseEntities.map(function(d) { return osmEntity$$1(d); });
74599                     stack$$1[0].graph.rebase(baseEntities, lodash.map(stack$$1, 'graph'), true);
74600                     tree$$1.rebase(baseEntities, true);
74601
74602                     // When we restore a modified way, we also need to fetch any missing
74603                     // childnodes that would normally have been downloaded with it.. #2142
74604                     if (loadChildNodes) {
74605                         var missing =  lodash(baseEntities)
74606                                 .filter({ type: 'way' })
74607                                 .map('nodes')
74608                                 .flatten()
74609                                 .uniq()
74610                                 .reject(function(n) { return stack$$1[0].graph.hasEntity(n); })
74611                                 .value();
74612
74613                         if (!lodash.isEmpty(missing)) {
74614                             loadComplete = false;
74615                             context.redrawEnable(false);
74616
74617                             var loading = uiLoading(context).blocking(true);
74618                             context.container().call(loading);
74619
74620                             var childNodesLoaded = function(err, result) {
74621                                 if (!err) {
74622                                     var visible = lodash.groupBy(result.data, 'visible');
74623                                     if (!lodash.isEmpty(visible.true)) {
74624                                         missing = lodash.difference(missing, lodash.map(visible.true, 'id'));
74625                                         stack$$1[0].graph.rebase(visible.true, lodash.map(stack$$1, 'graph'), true);
74626                                         tree$$1.rebase(visible.true, true);
74627                                     }
74628
74629                                     // fetch older versions of nodes that were deleted..
74630                                     lodash.each(visible.false, function(entity) {
74631                                         context.connection()
74632                                             .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
74633                                     });
74634                                 }
74635
74636                                 if (err || lodash.isEmpty(missing)) {
74637                                     loading.close();
74638                                     context.redrawEnable(true);
74639                                     dispatch$$1.call('change');
74640                                 }
74641                             };
74642
74643                             context.connection().loadMultiple(missing, childNodesLoaded);
74644                         }
74645                     }
74646                 }
74647
74648                 stack$$1 = h.stack.map(function(d) {
74649                     var entities = {}, entity;
74650
74651                     if (d.modified) {
74652                         d.modified.forEach(function(key) {
74653                             entity = allEntities[key];
74654                             entities[entity.id] = entity;
74655                         });
74656                     }
74657
74658                     if (d.deleted) {
74659                         d.deleted.forEach(function(id) {
74660                             entities[id] = undefined;
74661                         });
74662                     }
74663
74664                     return {
74665                         graph: coreGraph$$1(stack$$1[0].graph).load(entities),
74666                         annotation: d.annotation,
74667                         imageryUsed: d.imageryUsed
74668                     };
74669                 });
74670
74671             } else { // original version
74672                 stack$$1 = h.stack.map(function(d) {
74673                     var entities = {};
74674
74675                     for (var i in d.entities) {
74676                         var entity = d.entities[i];
74677                         entities[i] = entity === 'undefined' ? undefined : osmEntity$$1(entity);
74678                     }
74679
74680                     d.graph = coreGraph$$1(stack$$1[0].graph).load(entities);
74681                     return d;
74682                 });
74683             }
74684
74685             if (loadComplete) {
74686                 dispatch$$1.call('change');
74687             }
74688
74689             return history;
74690         },
74691
74692
74693         save: function() {
74694             if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
74695             return history;
74696         },
74697
74698
74699         clearSaved: function() {
74700             context.debouncedSave.cancel();
74701             if (lock.locked()) context.storage(getKey('saved_history'), null);
74702             return history;
74703         },
74704
74705
74706         lock: function() {
74707             return lock.lock();
74708         },
74709
74710
74711         unlock: function() {
74712             lock.unlock();
74713         },
74714
74715
74716         // is iD not open in another window and it detects that
74717         // there's a history stored in localStorage that's recoverable?
74718         restorableChanges: function() {
74719             return lock.locked() && !!context.storage(getKey('saved_history'));
74720         },
74721
74722
74723         // load history from a version stored in localStorage
74724         restore: function() {
74725             if (!lock.locked()) return;
74726
74727             var json$$1 = context.storage(getKey('saved_history'));
74728             if (json$$1) history.fromJSON(json$$1, true);
74729         },
74730
74731
74732         _getKey: getKey
74733
74734     };
74735
74736
74737     history.reset();
74738
74739     return utilRebind(history, dispatch$$1, 'on');
74740 }
74741
74742 function presetCollection(collection) {
74743     var maxSearchResults = 50,
74744         maxSuggestionResults = 10;
74745
74746     var presets = {
74747
74748         collection: collection,
74749
74750
74751         item: function(id) {
74752             return lodash.find(this.collection, function(d) {
74753                 return d.id === id;
74754             });
74755         },
74756
74757
74758         matchGeometry: function(geometry) {
74759             return presetCollection(this.collection.filter(function(d) {
74760                 return d.matchGeometry(geometry);
74761             }));
74762         },
74763
74764
74765         search: function(value, geometry) {
74766             if (!value) return this;
74767
74768             function leading(a) {
74769                 var index = a.indexOf(value);
74770                 return index === 0 || a[index - 1] === ' ';
74771             }
74772
74773             function suggestionName(name) {
74774                 var nameArray = name.split(' - ');
74775                 if (nameArray.length > 1) {
74776                     name = nameArray.slice(0, nameArray.length - 1).join(' - ');
74777                 }
74778                 return name.toLowerCase();
74779             }
74780
74781
74782             value = value.toLowerCase();
74783
74784             var searchable = lodash.filter(this.collection, function(a) {
74785                     return a.searchable !== false && a.suggestion !== true;
74786                 }),
74787                 suggestions = lodash.filter(this.collection, function(a) {
74788                     return a.suggestion === true;
74789                 });
74790
74791
74792             // matches value to preset.name
74793             var leading_name = lodash.filter(searchable, function(a) {
74794                     return leading(a.name().toLowerCase());
74795                 }).sort(function(a, b) {
74796                     var i;
74797                     i = b.originalScore - a.originalScore;
74798                     if (i !== 0) return i;
74799
74800                     i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
74801                     if (i !== 0) return i;
74802
74803                     return a.name().length - b.name().length;
74804                 });
74805
74806             // matches value to preset.terms values
74807             var leading_terms = lodash.filter(searchable, function(a) {
74808                     return lodash.some(a.terms() || [], leading);
74809                 });
74810
74811             // matches value to preset.tags values
74812             var leading_tag_values = lodash.filter(searchable, function(a) {
74813                     return lodash.some(lodash.without(lodash.values(a.tags || {}), '*'), leading);
74814                 });
74815
74816
74817             // finds close matches to value in preset.name
74818             var similar_name = searchable.map(function(a) {
74819                     return {
74820                         preset: a,
74821                         dist: utilEditDistance(value, a.name())
74822                     };
74823                 }).filter(function(a) {
74824                     return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
74825                 }).sort(function(a, b) {
74826                     return a.dist - b.dist;
74827                 }).map(function(a) {
74828                     return a.preset;
74829                 });
74830
74831             // finds close matches to value in preset.terms
74832             var similar_terms = lodash.filter(searchable, function(a) {
74833                     return lodash.some(a.terms() || [], function(b) {
74834                         return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
74835                     });
74836                 });
74837
74838             var leading_suggestions = lodash.filter(suggestions, function(a) {
74839                     return leading(suggestionName(a.name()));
74840                 }).sort(function(a, b) {
74841                     a = suggestionName(a.name());
74842                     b = suggestionName(b.name());
74843                     var i = a.indexOf(value) - b.indexOf(value);
74844                     if (i === 0) return a.length - b.length;
74845                     else return i;
74846                 });
74847
74848             var similar_suggestions = suggestions.map(function(a) {
74849                     return {
74850                         preset: a,
74851                         dist: utilEditDistance(value, suggestionName(a.name()))
74852                     };
74853                 }).filter(function(a) {
74854                     return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
74855                 }).sort(function(a, b) {
74856                     return a.dist - b.dist;
74857                 }).map(function(a) {
74858                     return a.preset;
74859                 });
74860
74861             var other = presets.item(geometry);
74862
74863             var results = leading_name.concat(
74864                     leading_terms,
74865                     leading_tag_values,
74866                     leading_suggestions.slice(0, maxSuggestionResults + 5),
74867                     similar_name,
74868                     similar_terms,
74869                     similar_suggestions.slice(0, maxSuggestionResults)
74870                 ).slice(0, maxSearchResults - 1);
74871
74872             return presetCollection(lodash.uniq(results.concat(other)));
74873         }
74874     };
74875
74876
74877     return presets;
74878 }
74879
74880 function presetCategory(id, category, all) {
74881     category = lodash.clone(category);
74882
74883     category.id = id;
74884
74885
74886     category.members = presetCollection(category.members.map(function(id) {
74887         return all.item(id);
74888     }));
74889
74890
74891     category.matchGeometry = function(geometry) {
74892         return category.geometry.indexOf(geometry) >= 0;
74893     };
74894
74895
74896     category.matchScore = function() {
74897         return -1;
74898     };
74899
74900
74901     category.name = function() {
74902         return t('presets.categories.' + id + '.name', {'default': id});
74903     };
74904
74905
74906     category.terms = function() {
74907         return [];
74908     };
74909
74910
74911     return category;
74912 }
74913
74914 function presetField(id, field) {
74915     field = lodash.clone(field);
74916
74917     field.id = id;
74918
74919
74920     field.matchGeometry = function(geometry) {
74921         return !field.geometry || field.geometry === geometry;
74922     };
74923
74924
74925     field.t = function(scope, options) {
74926         return t('presets.fields.' + id + '.' + scope, options);
74927     };
74928
74929
74930     field.label = function() {
74931         return field.t('label', {'default': id});
74932     };
74933
74934
74935     var placeholder = field.placeholder;
74936     field.placeholder = function() {
74937         return field.t('placeholder', {'default': placeholder});
74938     };
74939
74940
74941     return field;
74942 }
74943
74944 function presetPreset(id, preset, fields) {
74945     preset = lodash.clone(preset);
74946
74947     preset.id = id;
74948     preset.fields = (preset.fields || []).map(getFields);
74949     preset.geometry = (preset.geometry || []);
74950
74951
74952     function getFields(f) {
74953         return fields[f];
74954     }
74955
74956
74957     preset.matchGeometry = function(geometry) {
74958         return preset.geometry.indexOf(geometry) >= 0;
74959     };
74960
74961
74962     preset.originalScore = preset.matchScore || 1;
74963
74964
74965     preset.matchScore = function(entity) {
74966         var tags = preset.tags,
74967             score = 0;
74968
74969         for (var t$$1 in tags) {
74970             if (entity.tags[t$$1] === tags[t$$1]) {
74971                 score += preset.originalScore;
74972             } else if (tags[t$$1] === '*' && t$$1 in entity.tags) {
74973                 score += preset.originalScore / 2;
74974             } else {
74975                 return -1;
74976             }
74977         }
74978
74979         return score;
74980     };
74981
74982
74983     preset.t = function(scope, options) {
74984         return t('presets.presets.' + id + '.' + scope, options);
74985     };
74986
74987
74988     var name = preset.name || '';
74989     preset.name = function() {
74990         if (preset.suggestion) {
74991             id = id.split('/');
74992             id = id[0] + '/' + id[1];
74993             return name + ' - ' + t('presets.presets.' + id + '.name');
74994         }
74995         return preset.t('name', {'default': name});
74996     };
74997
74998
74999     preset.terms = function() {
75000         return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
75001     };
75002
75003
75004     preset.isFallback = function() {
75005         var tagCount = Object.keys(preset.tags).length;
75006         return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
75007     };
75008
75009
75010     var reference = preset.reference || {};
75011     preset.reference = function(geometry) {
75012         var key = reference.key || Object.keys(lodash.omit(preset.tags, 'name'))[0],
75013             value = reference.value || preset.tags[key];
75014
75015         if (geometry === 'relation' && key === 'type') {
75016             if (value in preset.tags) {
75017                 key = value;
75018                 value = preset.tags[key];
75019             } else {
75020                 return { rtype: value };
75021             }
75022         }
75023
75024         if (value === '*') {
75025             return { key: key };
75026         } else {
75027             return { key: key, value: value };
75028         }
75029     };
75030
75031
75032     var removeTags = preset.removeTags || preset.tags;
75033     preset.removeTags = function(tags, geometry) {
75034         tags = lodash.omit(tags, lodash.keys(removeTags));
75035
75036         for (var f in preset.fields) {
75037             var field = preset.fields[f];
75038             if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
75039                 delete tags[field.key];
75040             }
75041         }
75042
75043         delete tags.area;
75044         return tags;
75045     };
75046
75047
75048     var applyTags = preset.addTags || preset.tags;
75049     preset.applyTags = function(tags, geometry) {
75050         var k;
75051
75052         tags = lodash.clone(tags);
75053
75054         for (k in applyTags) {
75055             if (applyTags[k] === '*') {
75056                 tags[k] = 'yes';
75057             } else {
75058                 tags[k] = applyTags[k];
75059             }
75060         }
75061
75062         // Add area=yes if necessary.
75063         // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
75064         // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
75065         // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
75066         delete tags.area;
75067         if (geometry === 'area') {
75068             var needsAreaTag = true;
75069             if (preset.geometry.indexOf('line') === -1) {
75070                 for (k in applyTags) {
75071                     if (k in areaKeys) {
75072                         needsAreaTag = false;
75073                         break;
75074                     }
75075                 }
75076             }
75077             if (needsAreaTag) {
75078                 tags.area = 'yes';
75079             }
75080         }
75081
75082         for (var f in preset.fields) {
75083             var field = preset.fields[f];
75084             if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
75085                 tags[field.key] = field.default;
75086             }
75087         }
75088
75089         return tags;
75090     };
75091
75092
75093     return preset;
75094 }
75095
75096 function presetIndex() {
75097     // a presetCollection with methods for
75098     // loading new data and returning defaults
75099
75100     var all = presetCollection([]),
75101         defaults = { area: all, line: all, point: all, vertex: all, relation: all },
75102         fields = {},
75103         universal = [],
75104         recent = presetCollection([]);
75105
75106     // Index of presets by (geometry, tag key).
75107     var index = {
75108         point: {},
75109         vertex: {},
75110         line: {},
75111         area: {},
75112         relation: {}
75113     };
75114
75115     all.match = function(entity, resolver) {
75116         var geometry = entity.geometry(resolver);
75117
75118         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
75119         if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
75120             geometry = 'point';
75121         }
75122
75123         var geometryMatches = index[geometry],
75124             best = -1,
75125             match;
75126
75127         for (var k in entity.tags) {
75128             var keyMatches = geometryMatches[k];
75129             if (!keyMatches) continue;
75130
75131             for (var i = 0; i < keyMatches.length; i++) {
75132                 var score = keyMatches[i].matchScore(entity);
75133                 if (score > best) {
75134                     best = score;
75135                     match = keyMatches[i];
75136                 }
75137             }
75138         }
75139
75140         return match || all.item(geometry);
75141     };
75142
75143
75144     // Because of the open nature of tagging, iD will never have a complete
75145     // list of tags used in OSM, so we want it to have logic like "assume
75146     // that a closed way with an amenity tag is an area, unless the amenity
75147     // is one of these specific types". This function computes a structure
75148     // that allows testing of such conditions, based on the presets designated
75149     // as as supporting (or not supporting) the area geometry.
75150     //
75151     // The returned object L is a whitelist/blacklist of tags. A closed way
75152     // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
75153     // (see `Way#isArea()`). In other words, the keys of L form the whitelist,
75154     // and the subkeys form the blacklist.
75155     all.areaKeys = function() {
75156         var areaKeys = {},
75157             ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],  // probably a line..
75158             presets = lodash.reject(all.collection, 'suggestion');
75159
75160         // whitelist
75161         presets.forEach(function(d) {
75162             for (var key in d.tags) break;
75163             if (!key) return;
75164             if (ignore.indexOf(key) !== -1) return;
75165
75166             if (d.geometry.indexOf('area') !== -1) {    // probably an area..
75167                 areaKeys[key] = areaKeys[key] || {};
75168             }
75169         });
75170
75171         // blacklist
75172         presets.forEach(function(d) {
75173             for (var key in d.tags) break;
75174             if (!key) return;
75175             if (ignore.indexOf(key) !== -1) return;
75176
75177             var value = d.tags[key];
75178             if (key in areaKeys &&                      // probably an area...
75179                 d.geometry.indexOf('line') !== -1 &&    // but sometimes a line
75180                 value !== '*') {
75181                 areaKeys[key][value] = true;
75182             }
75183         });
75184
75185         return areaKeys;
75186     };
75187
75188
75189     all.init = function() {
75190         var d = data.presets;
75191
75192         all.collection = [];
75193         recent.collection = [];
75194         fields = {};
75195         universal = [];
75196         index = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
75197
75198         if (d.fields) {
75199             lodash.forEach(d.fields, function(d, id) {
75200                 fields[id] = presetField(id, d);
75201                 if (d.universal) universal.push(fields[id]);
75202             });
75203         }
75204
75205         if (d.presets) {
75206             lodash.forEach(d.presets, function(d, id) {
75207                 all.collection.push(presetPreset(id, d, fields));
75208             });
75209         }
75210
75211         if (d.categories) {
75212             lodash.forEach(d.categories, function(d, id) {
75213                 all.collection.push(presetCategory(id, d, all));
75214             });
75215         }
75216
75217         if (d.defaults) {
75218             var getItem = lodash.bind(all.item, all);
75219             defaults = {
75220                 area: presetCollection(d.defaults.area.map(getItem)),
75221                 line: presetCollection(d.defaults.line.map(getItem)),
75222                 point: presetCollection(d.defaults.point.map(getItem)),
75223                 vertex: presetCollection(d.defaults.vertex.map(getItem)),
75224                 relation: presetCollection(d.defaults.relation.map(getItem))
75225             };
75226         }
75227
75228         for (var i = 0; i < all.collection.length; i++) {
75229             var preset = all.collection[i],
75230                 geometry = preset.geometry;
75231
75232             for (var j = 0; j < geometry.length; j++) {
75233                 var g = index[geometry[j]];
75234                 for (var k in preset.tags) {
75235                     (g[k] = g[k] || []).push(preset);
75236                 }
75237             }
75238         }
75239
75240         return all;
75241     };
75242
75243     all.field = function(id) {
75244         return fields[id];
75245     };
75246
75247     all.universal = function() {
75248         return universal;
75249     };
75250
75251     all.defaults = function(geometry, n) {
75252         var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
75253             def = lodash.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
75254         return presetCollection(lodash.uniq(rec.concat(def).concat(all.item(geometry))));
75255     };
75256
75257     all.choose = function(preset) {
75258         if (!preset.isFallback()) {
75259             recent = presetCollection(lodash.uniq([preset].concat(recent.collection)));
75260         }
75261         return all;
75262     };
75263
75264     return all;
75265 }
75266
75267 var areaKeys = {};
75268
75269 function setAreaKeys(value) {
75270     areaKeys = value;
75271 }
75272
75273
75274 function coreContext() {
75275     var context = {};
75276     context.version = '2.3.2';
75277
75278     // create a special translation that contains the keys in place of the strings
75279     var tkeys = lodash.cloneDeep(en);
75280     var parents = [];
75281
75282     function traverser(v, k, obj) {
75283         parents.push(k);
75284         if (lodash.isObject(v)) {
75285             lodash.forOwn(v, traverser);
75286         } else if (lodash.isString(v)) {
75287             obj[k] = parents.join('.');
75288         }
75289         parents.pop();
75290     }
75291
75292     lodash.forOwn(tkeys, traverser);
75293     addTranslation('_tkeys_', tkeys);
75294
75295     addTranslation('en', en);
75296     setLocale('en');
75297
75298     var dispatch$$1 = dispatch('enter', 'exit', 'change');
75299
75300     // https://github.com/openstreetmap/iD/issues/772
75301     // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
75302     var storage;
75303     try { storage = localStorage; } catch (e) {}  // eslint-disable-line no-empty
75304     storage = storage || (function() {
75305         var s = {};
75306         return {
75307             getItem: function(k) { return s[k]; },
75308             setItem: function(k, v) { s[k] = v; },
75309             removeItem: function(k) { delete s[k]; }
75310         };
75311     })();
75312
75313     context.storage = function(k, v) {
75314         try {
75315             if (arguments.length === 1) return storage.getItem(k);
75316             else if (v === null) storage.removeItem(k);
75317             else storage.setItem(k, v);
75318         } catch (e) {
75319             // localstorage quota exceeded
75320             /* eslint-disable no-console */
75321             if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
75322             /* eslint-enable no-console */
75323         }
75324     };
75325
75326
75327     /* Straight accessors. Avoid using these if you can. */
75328     var ui, connection, history;
75329     context.ui = function() { return ui; };
75330     context.connection = function() { return connection; };
75331     context.history = function() { return history; };
75332
75333
75334     /* Connection */
75335     function entitiesLoaded(err, result) {
75336         if (!err) history.merge(result.data, result.extent);
75337     }
75338
75339     context.preauth = function(options) {
75340         connection.switch(options);
75341         return context;
75342     };
75343
75344     context.loadTiles = function(projection$$1, dimensions, callback) {
75345         function done(err, result) {
75346             entitiesLoaded(err, result);
75347             if (callback) callback(err, result);
75348         }
75349         connection.loadTiles(projection$$1, dimensions, done);
75350     };
75351
75352     context.loadEntity = function(id, callback) {
75353         function done(err, result) {
75354             entitiesLoaded(err, result);
75355             if (callback) callback(err, result);
75356         }
75357         connection.loadEntity(id, done);
75358     };
75359
75360     context.zoomToEntity = function(id, zoomTo) {
75361         if (zoomTo !== false) {
75362             this.loadEntity(id, function(err, result) {
75363                 if (err) return;
75364                 var entity = lodash.find(result.data, function(e) { return e.id === id; });
75365                 if (entity) { map.zoomTo(entity); }
75366             });
75367         }
75368
75369         map.on('drawn.zoomToEntity', function() {
75370             if (!context.hasEntity(id)) return;
75371             map.on('drawn.zoomToEntity', null);
75372             context.on('enter.zoomToEntity', null);
75373             context.enter(modeSelect(context, [id]));
75374         });
75375
75376         context.on('enter.zoomToEntity', function() {
75377             if (mode.id !== 'browse') {
75378                 map.on('drawn.zoomToEntity', null);
75379                 context.on('enter.zoomToEntity', null);
75380             }
75381         });
75382     };
75383
75384     var minEditableZoom = 16;
75385     context.minEditableZoom = function(_) {
75386         if (!arguments.length) return minEditableZoom;
75387         minEditableZoom = _;
75388         connection.tileZoom(_);
75389         return context;
75390     };
75391
75392
75393     /* History */
75394     var inIntro = false;
75395     context.inIntro = function(_) {
75396         if (!arguments.length) return inIntro;
75397         inIntro = _;
75398         return context;
75399     };
75400
75401     context.save = function() {
75402         // no history save, no message onbeforeunload
75403         if (inIntro || select('.modal').size()) return;
75404
75405         var canSave;
75406         if (mode && mode.id === 'save') {
75407             canSave = false;
75408         } else {
75409             canSave = context.selectedIDs().every(function(id) {
75410                 var entity = context.hasEntity(id);
75411                 return entity && !entity.isDegenerate();
75412             });
75413         }
75414
75415         if (canSave) {
75416             history.save();
75417         }
75418         if (history.hasChanges()) {
75419             return t('save.unsaved_changes');
75420         }
75421     };
75422
75423
75424     /* Graph */
75425     context.hasEntity = function(id) {
75426         return history.graph().hasEntity(id);
75427     };
75428     context.entity = function(id) {
75429         return history.graph().entity(id);
75430     };
75431     context.childNodes = function(way) {
75432         return history.graph().childNodes(way);
75433     };
75434     context.geometry = function(id) {
75435         return context.entity(id).geometry(history.graph());
75436     };
75437
75438
75439     /* Modes */
75440     var mode;
75441     context.mode = function() {
75442         return mode;
75443     };
75444     context.enter = function(newMode) {
75445         if (mode) {
75446             mode.exit();
75447             dispatch$$1.call('exit', this, mode);
75448         }
75449
75450         mode = newMode;
75451         mode.enter();
75452         dispatch$$1.call('enter', this, mode);
75453     };
75454
75455     context.selectedIDs = function() {
75456         if (mode && mode.selectedIDs) {
75457             return mode.selectedIDs();
75458         } else {
75459             return [];
75460         }
75461     };
75462
75463
75464     /* Behaviors */
75465     context.install = function(behavior) {
75466         context.surface().call(behavior);
75467     };
75468     context.uninstall = function(behavior) {
75469         context.surface().call(behavior.off);
75470     };
75471
75472
75473     /* Copy/Paste */
75474     var copyIDs = [], copyGraph;
75475     context.copyGraph = function() { return copyGraph; };
75476     context.copyIDs = function(_) {
75477         if (!arguments.length) return copyIDs;
75478         copyIDs = _;
75479         copyGraph = history.graph();
75480         return context;
75481     };
75482
75483
75484     /* Background */
75485     var background;
75486     context.background = function() { return background; };
75487
75488
75489     /* Features */
75490     var features;
75491     context.features = function() { return features; };
75492     context.hasHiddenConnections = function(id) {
75493         var graph = history.graph(),
75494             entity = graph.entity(id);
75495         return features.hasHiddenConnections(entity, graph);
75496     };
75497
75498
75499     /* Presets */
75500     var presets;
75501     context.presets = function() { return presets; };
75502
75503
75504     /* Map */
75505     var map;
75506     context.map = function() { return map; };
75507     context.layers = function() { return map.layers; };
75508     context.surface = function() { return map.surface; };
75509     context.editable = function() { return map.editable(); };
75510     context.surfaceRect = function() {
75511         return map.surface.node().getBoundingClientRect();
75512     };
75513
75514
75515     /* Debug */
75516     var debugFlags = {
75517         tile: false,
75518         collision: false,
75519         imagery: false,
75520         imperial: false,
75521         driveLeft: false
75522     };
75523     context.debugFlags = function() {
75524         return debugFlags;
75525     };
75526     context.setDebug = function(flag, val) {
75527         if (arguments.length === 1) val = true;
75528         debugFlags[flag] = val;
75529         dispatch$$1.call('change');
75530         return context;
75531     };
75532     context.getDebug = function(flag) {
75533         return flag && debugFlags[flag];
75534     };
75535
75536
75537     /* Container */
75538     var container = select(document.body);
75539     context.container = function(_) {
75540         if (!arguments.length) return container;
75541         container = _;
75542         container.classed('id-container', true);
75543         return context;
75544     };
75545     var embed;
75546     context.embed = function(_) {
75547         if (!arguments.length) return embed;
75548         embed = _;
75549         return context;
75550     };
75551
75552
75553     /* Assets */
75554     var assetPath = '';
75555     context.assetPath = function(_) {
75556         if (!arguments.length) return assetPath;
75557         assetPath = _;
75558         return context;
75559     };
75560
75561     var assetMap = {};
75562     context.assetMap = function(_) {
75563         if (!arguments.length) return assetMap;
75564         assetMap = _;
75565         return context;
75566     };
75567
75568     context.asset = function(_) {
75569         var filename = assetPath + _;
75570         return assetMap[filename] || filename;
75571     };
75572
75573     context.imagePath = function(_) {
75574         return context.asset('img/' + _);
75575     };
75576
75577
75578     /* locales */
75579     // `locale` variable contains a "requested locale".
75580     // It won't become the `currentLocale` until after loadLocale() is called.
75581     var locale, localePath;
75582
75583     context.locale = function(loc, path$$1) {
75584         if (!arguments.length) return currentLocale;
75585         locale = loc;
75586         localePath = path$$1;
75587         return context;
75588     };
75589
75590     context.loadLocale = function(callback) {
75591         if (locale && locale !== 'en' && dataLocales.hasOwnProperty(locale)) {
75592             localePath = localePath || context.asset('locales/' + locale + '.json');
75593             json(localePath, function(err, result) {
75594                 if (!err) {
75595                     addTranslation(locale, result[locale]);
75596                     setLocale(locale);
75597                     utilDetect(true);
75598                 }
75599                 if (callback) {
75600                     callback(err);
75601                 }
75602             });
75603         } else {
75604             if (locale) {
75605                 setLocale(locale);
75606                 utilDetect(true);
75607             }
75608             if (callback) {
75609                 callback();
75610             }
75611         }
75612     };
75613
75614
75615     /* reset (aka flush) */
75616     context.reset = context.flush = function() {
75617         context.debouncedSave.cancel();
75618         lodash.each(services, function(service) {
75619             if (service && typeof service.reset === 'function') {
75620                 service.reset(context);
75621             }
75622         });
75623         features.reset();
75624         history.reset();
75625         return context;
75626     };
75627
75628
75629     /* Init */
75630
75631     context.projection = geoRawMercator();
75632     context.curtainProjection = geoRawMercator();
75633
75634     locale = utilDetect().locale;
75635     if (locale && !dataLocales.hasOwnProperty(locale)) {
75636         locale = locale.split('-')[0];
75637     }
75638
75639     history = coreHistory(context);
75640     context.graph = history.graph;
75641     context.changes = history.changes;
75642     context.intersects = history.intersects;
75643
75644     // Debounce save, since it's a synchronous localStorage write,
75645     // and history changes can happen frequently (e.g. when dragging).
75646     context.debouncedSave = lodash.debounce(context.save, 350);
75647     function withDebouncedSave(fn) {
75648         return function() {
75649             var result = fn.apply(history, arguments);
75650             context.debouncedSave();
75651             return result;
75652         };
75653     }
75654
75655     context.perform = withDebouncedSave(history.perform);
75656     context.replace = withDebouncedSave(history.replace);
75657     context.pop = withDebouncedSave(history.pop);
75658     context.overwrite = withDebouncedSave(history.overwrite);
75659     context.undo = withDebouncedSave(history.undo);
75660     context.redo = withDebouncedSave(history.redo);
75661
75662     ui = uiInit(context);
75663
75664     connection = services.osm;
75665     background = rendererBackground(context);
75666     features = rendererFeatures(context);
75667     presets = presetIndex();
75668
75669     map = rendererMap(context);
75670     context.mouse = map.mouse;
75671     context.extent = map.extent;
75672     context.pan = map.pan;
75673     context.zoomIn = map.zoomIn;
75674     context.zoomOut = map.zoomOut;
75675     context.zoomInFurther = map.zoomInFurther;
75676     context.zoomOutFurther = map.zoomOutFurther;
75677     context.redrawEnable = map.redrawEnable;
75678
75679     lodash.each(services, function(service) {
75680         if (service && typeof service.init === 'function') {
75681             service.init(context);
75682         }
75683     });
75684
75685     background.init();
75686     presets.init();
75687     areaKeys = presets.areaKeys();
75688
75689
75690     return utilRebind(context, dispatch$$1, 'on');
75691 }
75692
75693 function osmWay() {
75694     if (!(this instanceof osmWay)) {
75695         return (new osmWay()).initialize(arguments);
75696     } else if (arguments.length) {
75697         this.initialize(arguments);
75698     }
75699 }
75700
75701
75702 osmEntity$$1.way = osmWay;
75703
75704 osmWay.prototype = Object.create(osmEntity$$1.prototype);
75705
75706
75707 lodash.extend(osmWay.prototype, {
75708     type: 'way',
75709     nodes: [],
75710
75711
75712     copy: function(resolver, copies) {
75713         if (copies[this.id])
75714             return copies[this.id];
75715
75716         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
75717
75718         var nodes = this.nodes.map(function(id) {
75719             return resolver.entity(id).copy(resolver, copies).id;
75720         });
75721
75722         copy = copy.update({ nodes: nodes });
75723         copies[this.id] = copy;
75724
75725         return copy;
75726     },
75727
75728
75729     extent: function(resolver) {
75730         return resolver.transient(this, 'extent', function() {
75731             var extent$$1 = geoExtent$$1();
75732             for (var i = 0; i < this.nodes.length; i++) {
75733                 var node = resolver.hasEntity(this.nodes[i]);
75734                 if (node) {
75735                     extent$$1._extend(node.extent());
75736                 }
75737             }
75738             return extent$$1;
75739         });
75740     },
75741
75742
75743     first: function() {
75744         return this.nodes[0];
75745     },
75746
75747
75748     last: function() {
75749         return this.nodes[this.nodes.length - 1];
75750     },
75751
75752
75753     contains: function(node) {
75754         return this.nodes.indexOf(node) >= 0;
75755     },
75756
75757
75758     affix: function(node) {
75759         if (this.nodes[0] === node) return 'prefix';
75760         if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
75761     },
75762
75763
75764     layer: function() {
75765         // explicit layer tag, clamp between -10, 10..
75766         if (isFinite(this.tags.layer)) {
75767             return Math.max(-10, Math.min(+(this.tags.layer), 10));
75768         }
75769
75770         // implied layer tag..
75771         if (this.tags.location === 'overground') return 1;
75772         if (this.tags.location === 'underground') return -1;
75773         if (this.tags.location === 'underwater') return -10;
75774
75775         if (this.tags.power === 'line') return 10;
75776         if (this.tags.power === 'minor_line') return 10;
75777         if (this.tags.aerialway) return 10;
75778         if (this.tags.bridge) return 1;
75779         if (this.tags.cutting) return -1;
75780         if (this.tags.tunnel) return -1;
75781         if (this.tags.waterway) return -1;
75782         if (this.tags.man_made === 'pipeline') return -10;
75783         if (this.tags.boundary) return -10;
75784         return 0;
75785     },
75786
75787
75788     isOneWay: function() {
75789         // explicit oneway tag..
75790         if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
75791         if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
75792
75793         // implied oneway tag..
75794         for (var key in this.tags) {
75795             if (key in osmOneWayTags && (this.tags[key] in osmOneWayTags[key]))
75796                 return true;
75797         }
75798         return false;
75799     },
75800
75801
75802     lanes: function() {
75803         return osmLanes(this);
75804     },
75805
75806
75807     isClosed: function() {
75808         return this.nodes.length > 1 && this.first() === this.last();
75809     },
75810
75811
75812     isConvex: function(resolver) {
75813         if (!this.isClosed() || this.isDegenerate()) return null;
75814
75815         var nodes = lodash.uniq(resolver.childNodes(this)),
75816             coords = lodash.map(nodes, 'loc'),
75817             curr = 0, prev = 0;
75818
75819         for (var i = 0; i < coords.length; i++) {
75820             var o = coords[(i+1) % coords.length],
75821                 a = coords[i],
75822                 b = coords[(i+2) % coords.length],
75823                 res = geoCross(o, a, b);
75824
75825             curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
75826             if (curr === 0) {
75827                 continue;
75828             } else if (prev && curr !== prev) {
75829                 return false;
75830             }
75831             prev = curr;
75832         }
75833         return true;
75834     },
75835
75836
75837     isArea: function() {
75838         if (this.tags.area === 'yes')
75839             return true;
75840         if (!this.isClosed() || this.tags.area === 'no')
75841             return false;
75842         for (var key in this.tags) {
75843             if (key in areaKeys && !(this.tags[key] in areaKeys[key])) {
75844                 return true;
75845             }
75846         }
75847         return false;
75848     },
75849
75850
75851     isDegenerate: function() {
75852         return lodash.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
75853     },
75854
75855
75856     areAdjacent: function(n1, n2) {
75857         for (var i = 0; i < this.nodes.length; i++) {
75858             if (this.nodes[i] === n1) {
75859                 if (this.nodes[i - 1] === n2) return true;
75860                 if (this.nodes[i + 1] === n2) return true;
75861             }
75862         }
75863         return false;
75864     },
75865
75866
75867     geometry: function(graph) {
75868         return graph.transient(this, 'geometry', function() {
75869             return this.isArea() ? 'area' : 'line';
75870         });
75871     },
75872
75873
75874     // If this way is not closed, append the beginning node to the end of the nodelist to close it.
75875     close: function() {
75876         if (this.isClosed() || !this.nodes.length) return this;
75877
75878         var nodes = this.nodes.slice();
75879         nodes = nodes.filter(noRepeatNodes);
75880         nodes.push(nodes[0]);
75881         return this.update({ nodes: nodes });
75882     },
75883
75884
75885     // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
75886     unclose: function() {
75887         if (!this.isClosed()) return this;
75888
75889         var nodes = this.nodes.slice(),
75890             connector = this.first(),
75891             i = nodes.length - 1;
75892
75893         // remove trailing connectors..
75894         while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
75895             nodes.splice(i, 1);
75896             i = nodes.length - 1;
75897         }
75898
75899         nodes = nodes.filter(noRepeatNodes);
75900         return this.update({ nodes: nodes });
75901     },
75902
75903
75904     // Adds a node (id) in front of the node which is currently at position index.
75905     // If index is undefined, the node will be added to the end of the way for linear ways,
75906     //   or just before the final connecting node for circular ways.
75907     // Consecutive duplicates are eliminated including existing ones.
75908     // Circularity is always preserved when adding a node.
75909     addNode: function(id, index) {
75910         var nodes = this.nodes.slice(),
75911             isClosed = this.isClosed(),
75912             max$$1 = isClosed ? nodes.length - 1 : nodes.length;
75913
75914         if (index === undefined) {
75915             index = max$$1;
75916         }
75917
75918         if (index < 0 || index > max$$1) {
75919             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
75920         }
75921
75922         // If this is a closed way, remove all connector nodes except the first one
75923         // (there may be duplicates) and adjust index if necessary..
75924         if (isClosed) {
75925             var connector = this.first();
75926
75927             // leading connectors..
75928             var i = 1;
75929             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
75930                 nodes.splice(i, 1);
75931                 if (index > i) index--;
75932             }
75933
75934             // trailing connectors..
75935             i = nodes.length - 1;
75936             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
75937                 nodes.splice(i, 1);
75938                 if (index > i) index--;
75939                 i = nodes.length - 1;
75940             }
75941         }
75942
75943         nodes.splice(index, 0, id);
75944         nodes = nodes.filter(noRepeatNodes);
75945
75946         // If the way was closed before, append a connector node to keep it closed..
75947         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75948             nodes.push(nodes[0]);
75949         }
75950
75951         return this.update({ nodes: nodes });
75952     },
75953
75954
75955     // Replaces the node which is currently at position index with the given node (id).
75956     // Consecutive duplicates are eliminated including existing ones.
75957     // Circularity is preserved when updating a node.
75958     updateNode: function(id, index) {
75959         var nodes = this.nodes.slice(),
75960             isClosed = this.isClosed(),
75961             max$$1 = nodes.length - 1;
75962
75963         if (index === undefined || index < 0 || index > max$$1) {
75964             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
75965         }
75966
75967         // If this is a closed way, remove all connector nodes except the first one
75968         // (there may be duplicates) and adjust index if necessary..
75969         if (isClosed) {
75970             var connector = this.first();
75971
75972             // leading connectors..
75973             var i = 1;
75974             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
75975                 nodes.splice(i, 1);
75976                 if (index > i) index--;
75977             }
75978
75979             // trailing connectors..
75980             i = nodes.length - 1;
75981             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
75982                 nodes.splice(i, 1);
75983                 if (index === i) index = 0;  // update leading connector instead
75984                 i = nodes.length - 1;
75985             }
75986         }
75987
75988         nodes.splice(index, 1, id);
75989         nodes = nodes.filter(noRepeatNodes);
75990
75991         // If the way was closed before, append a connector node to keep it closed..
75992         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
75993             nodes.push(nodes[0]);
75994         }
75995
75996         return this.update({nodes: nodes});
75997     },
75998
75999
76000     // Replaces each occurrence of node id needle with replacement.
76001     // Consecutive duplicates are eliminated including existing ones.
76002     // Circularity is preserved.
76003     replaceNode: function(needle, replacement) {
76004         var nodes = this.nodes.slice(),
76005             isClosed = this.isClosed();
76006
76007         for (var i = 0; i < nodes.length; i++) {
76008             if (nodes[i] === needle) {
76009                 nodes[i] = replacement;
76010             }
76011         }
76012
76013         nodes = nodes.filter(noRepeatNodes);
76014
76015         // If the way was closed before, append a connector node to keep it closed..
76016         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
76017             nodes.push(nodes[0]);
76018         }
76019
76020         return this.update({nodes: nodes});
76021     },
76022
76023
76024     // Removes each occurrence of node id needle with replacement.
76025     // Consecutive duplicates are eliminated including existing ones.
76026     // Circularity is preserved.
76027     removeNode: function(id) {
76028         var nodes = this.nodes.slice(),
76029             isClosed = this.isClosed();
76030
76031         nodes = nodes
76032             .filter(function(node) { return node !== id; })
76033             .filter(noRepeatNodes);
76034
76035         // If the way was closed before, append a connector node to keep it closed..
76036         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
76037             nodes.push(nodes[0]);
76038         }
76039
76040         return this.update({nodes: nodes});
76041     },
76042
76043
76044     asJXON: function(changeset_id) {
76045         var r = {
76046             way: {
76047                 '@id': this.osmId(),
76048                 '@version': this.version || 0,
76049                 nd: lodash.map(this.nodes, function(id) {
76050                     return { keyAttributes: { ref: osmEntity$$1.id.toOSM(id) } };
76051                 }),
76052                 tag: lodash.map(this.tags, function(v, k) {
76053                     return { keyAttributes: { k: k, v: v } };
76054                 })
76055             }
76056         };
76057         if (changeset_id) {
76058             r.way['@changeset'] = changeset_id;
76059         }
76060         return r;
76061     },
76062
76063
76064     asGeoJSON: function(resolver) {
76065         return resolver.transient(this, 'GeoJSON', function() {
76066             var coordinates = lodash.map(resolver.childNodes(this), 'loc');
76067             if (this.isArea() && this.isClosed()) {
76068                 return {
76069                     type: 'Polygon',
76070                     coordinates: [coordinates]
76071                 };
76072             } else {
76073                 return {
76074                     type: 'LineString',
76075                     coordinates: coordinates
76076                 };
76077             }
76078         });
76079     },
76080
76081
76082     area: function(resolver) {
76083         return resolver.transient(this, 'area', function() {
76084             var nodes = resolver.childNodes(this);
76085
76086             var json$$1 = {
76087                 type: 'Polygon',
76088                 coordinates: [lodash.map(nodes, 'loc')]
76089             };
76090
76091             if (!this.isClosed() && nodes.length) {
76092                 json$$1.coordinates[0].push(nodes[0].loc);
76093             }
76094
76095             var area$$1 = area(json$$1);
76096
76097             // Heuristic for detecting counterclockwise winding order. Assumes
76098             // that OpenStreetMap polygons are not hemisphere-spanning.
76099             if (area$$1 > 2 * Math.PI) {
76100                 json$$1.coordinates[0] = json$$1.coordinates[0].reverse();
76101                 area$$1 = area(json$$1);
76102             }
76103
76104             return isNaN(area$$1) ? 0 : area$$1;
76105         });
76106     }
76107 });
76108
76109
76110 // Filter function to eliminate consecutive duplicates.
76111 function noRepeatNodes(node, i, arr) {
76112     return i === 0 || node !== arr[i - 1];
76113 }
76114
76115 function osmTurn(turn) {
76116     if (!(this instanceof osmTurn))
76117         return new osmTurn(turn);
76118     lodash.extend(this, turn);
76119 }
76120
76121
76122 function osmIntersection(graph, vertexId) {
76123     var vertex = graph.entity(vertexId),
76124         parentWays = graph.parentWays(vertex),
76125         coincident = [],
76126         highways = {};
76127
76128     function addHighway(way, adjacentNodeId) {
76129         if (highways[adjacentNodeId]) {
76130             coincident.push(adjacentNodeId);
76131         } else {
76132             highways[adjacentNodeId] = way;
76133         }
76134     }
76135
76136     // Pre-split ways that would need to be split in
76137     // order to add a restriction. The real split will
76138     // happen when the restriction is added.
76139     parentWays.forEach(function(way) {
76140         if (!way.tags.highway || way.isArea() || way.isDegenerate())
76141             return;
76142
76143         var isFirst = (vertexId === way.first()),
76144             isLast = (vertexId === way.last()),
76145             isAffix = (isFirst || isLast),
76146             isClosingNode = (isFirst && isLast);
76147
76148         if (isAffix && !isClosingNode) {
76149             var index = (isFirst ? 1 : way.nodes.length - 2);
76150             addHighway(way, way.nodes[index]);
76151
76152         } else {
76153             var splitIndex, wayA, wayB, indexA, indexB;
76154             if (isClosingNode) {
76155                 splitIndex = Math.ceil(way.nodes.length / 2);  // split at midpoint
76156                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
76157                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
76158                 indexA = 1;
76159                 indexB = way.nodes.length - 2;
76160             } else {
76161                 splitIndex = lodash.indexOf(way.nodes, vertex.id, 1);  // split at vertexid
76162                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
76163                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
76164                 indexA = splitIndex - 1;
76165                 indexB = splitIndex + 1;
76166             }
76167             graph = graph.replace(wayA).replace(wayB);
76168             addHighway(wayA, way.nodes[indexA]);
76169             addHighway(wayB, way.nodes[indexB]);
76170         }
76171     });
76172
76173     // remove any ways from this intersection that are coincident
76174     // (i.e. any adjacent node used by more than one intersecting way)
76175     coincident.forEach(function (n) {
76176         delete highways[n];
76177     });
76178
76179
76180     var intersection = {
76181         highways: highways,
76182         ways: lodash.values(highways),
76183         graph: graph
76184     };
76185
76186
76187     intersection.adjacentNodeId = function(fromWayId) {
76188         return lodash.find(lodash.keys(highways), function(k) {
76189             return highways[k].id === fromWayId;
76190         });
76191     };
76192
76193
76194     intersection.turns = function(fromNodeId) {
76195         var start = highways[fromNodeId];
76196         if (!start)
76197             return [];
76198
76199         if (start.first() === vertex.id && start.tags.oneway === 'yes')
76200             return [];
76201         if (start.last() === vertex.id && start.tags.oneway === '-1')
76202             return [];
76203
76204         function withRestriction(turn) {
76205             graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
76206                 if (relation.tags.type !== 'restriction')
76207                     return;
76208
76209                 var f = relation.memberByRole('from'),
76210                     t = relation.memberByRole('to'),
76211                     v = relation.memberByRole('via');
76212
76213                 if (f && f.id === turn.from.way &&
76214                     v && v.id === turn.via.node &&
76215                     t && t.id === turn.to.way) {
76216                     turn.restriction = relation.id;
76217                 } else if (/^only_/.test(relation.tags.restriction) &&
76218                     f && f.id === turn.from.way &&
76219                     v && v.id === turn.via.node &&
76220                     t && t.id !== turn.to.way) {
76221                     turn.restriction = relation.id;
76222                     turn.indirect_restriction = true;
76223                 }
76224             });
76225
76226             return osmTurn(turn);
76227         }
76228
76229
76230         var from = {
76231                 node: fromNodeId,
76232                 way: start.id.split(/-(a|b)/)[0]
76233             },
76234             via = { node: vertex.id },
76235             turns = [];
76236
76237         lodash.each(highways, function(end, adjacentNodeId) {
76238             if (end === start)
76239                 return;
76240
76241             // backward
76242             if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
76243                 turns.push(withRestriction({
76244                     from: from,
76245                     via: via,
76246                     to: {
76247                         node: adjacentNodeId,
76248                         way: end.id.split(/-(a|b)/)[0]
76249                     }
76250                 }));
76251             }
76252
76253             // forward
76254             if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
76255                 turns.push(withRestriction({
76256                     from: from,
76257                     via: via,
76258                     to: {
76259                         node: adjacentNodeId,
76260                         way: end.id.split(/-(a|b)/)[0]
76261                     }
76262                 }));
76263             }
76264
76265         });
76266
76267         // U-turn
76268         if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
76269             turns.push(withRestriction({
76270                 from: from,
76271                 via: via,
76272                 to: from,
76273                 u: true
76274             }));
76275         }
76276
76277         return turns;
76278     };
76279
76280     return intersection;
76281 }
76282
76283
76284 function osmInferRestriction(graph, from, via, to, projection) {
76285     var fromWay = graph.entity(from.way),
76286         fromNode = graph.entity(from.node),
76287         toWay = graph.entity(to.way),
76288         toNode = graph.entity(to.node),
76289         viaNode = graph.entity(via.node),
76290         fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
76291             (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
76292         toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
76293             (toWay.tags.oneway === '-1' && toWay.last() === via.node),
76294         angle = geoAngle(viaNode, fromNode, projection) -
76295                 geoAngle(viaNode, toNode, projection);
76296
76297     angle = angle * 180 / Math.PI;
76298
76299     while (angle < 0)
76300         angle += 360;
76301
76302     if (fromNode === toNode)
76303         return 'no_u_turn';
76304     if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
76305         return 'no_u_turn';
76306     if (angle < 158)
76307         return 'no_right_turn';
76308     if (angle > 202)
76309         return 'no_left_turn';
76310
76311     return 'no_straight_on';
76312 }
76313
76314 function actionAddMember(relationId, member, memberIndex) {
76315     return function(graph) {
76316         var relation = graph.entity(relationId);
76317
76318         if (isNaN(memberIndex) && member.type === 'way') {
76319             var members = relation.indexedMembers();
76320             members.push(member);
76321
76322             var joined = osmJoinWays(members, graph);
76323             for (var i = 0; i < joined.length; i++) {
76324                 var segment = joined[i];
76325                 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
76326                     if (segment[j] !== member)
76327                         continue;
76328
76329                     if (j === 0) {
76330                         memberIndex = segment[j + 1].index;
76331                     } else if (j === segment.length - 1) {
76332                         memberIndex = segment[j - 1].index + 1;
76333                     } else {
76334                         memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
76335                     }
76336                 }
76337             }
76338         }
76339
76340         return graph.replace(relation.addMember(member, memberIndex));
76341     };
76342 }
76343
76344 function actionAddMidpoint(midpoint, node) {
76345     return function(graph) {
76346         graph = graph.replace(node.move(midpoint.loc));
76347
76348         var parents = lodash.intersection(
76349             graph.parentWays(graph.entity(midpoint.edge[0])),
76350             graph.parentWays(graph.entity(midpoint.edge[1])));
76351
76352         parents.forEach(function(way) {
76353             for (var i = 0; i < way.nodes.length - 1; i++) {
76354                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
76355                     graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
76356
76357                     // Add only one midpoint on doubled-back segments,
76358                     // turning them into self-intersections.
76359                     return;
76360                 }
76361             }
76362         });
76363
76364         return graph;
76365     };
76366 }
76367
76368 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
76369 function actionAddVertex(wayId, nodeId, index) {
76370     return function(graph) {
76371         return graph.replace(graph.entity(wayId).addNode(nodeId, index));
76372     };
76373 }
76374
76375 function actionChangeMember(relationId, member, memberIndex) {
76376     return function(graph) {
76377         return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
76378     };
76379 }
76380
76381 function actionChangePreset(entityId, oldPreset, newPreset) {
76382     return function(graph) {
76383         var entity = graph.entity(entityId),
76384             geometry = entity.geometry(graph),
76385             tags = entity.tags;
76386
76387         if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
76388         if (newPreset) tags = newPreset.applyTags(tags, geometry);
76389
76390         return graph.replace(entity.update({tags: tags}));
76391     };
76392 }
76393
76394 function actionChangeTags(entityId, tags) {
76395     return function(graph) {
76396         var entity = graph.entity(entityId);
76397         return graph.replace(entity.update({tags: tags}));
76398     };
76399 }
76400
76401 function actionCircularize(wayId, projection$$1, maxAngle) {
76402     maxAngle = (maxAngle || 20) * Math.PI / 180;
76403
76404
76405     var action = function(graph, t) {
76406         if (t === null || !isFinite(t)) t = 1;
76407         t = Math.min(Math.max(+t, 0), 1);
76408
76409         var way = graph.entity(wayId),
76410             origNodes = {};
76411
76412         graph.childNodes(way).forEach(function(node) {
76413             if (!origNodes[node.id]) origNodes[node.id] = node;
76414         });
76415
76416         if (!way.isConvex(graph)) {
76417             graph = action.makeConvex(graph);
76418         }
76419
76420         var nodes = lodash.uniq(graph.childNodes(way)),
76421             keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
76422             points = nodes.map(function(n) { return projection$$1(n.loc); }),
76423             keyPoints = keyNodes.map(function(n) { return projection$$1(n.loc); }),
76424             centroid = (points.length === 2) ? geoInterp(points[0], points[1], 0.5) : d3polygonCentroid(points),
76425             radius = median(points, function(p) { return geoEuclideanDistance(centroid, p); }),
76426             sign = d3polygonArea(points) > 0 ? 1 : -1,
76427             ids;
76428
76429         // we need atleast two key nodes for the algorithm to work
76430         if (!keyNodes.length) {
76431             keyNodes = [nodes[0]];
76432             keyPoints = [points[0]];
76433         }
76434
76435         if (keyNodes.length === 1) {
76436             var index = nodes.indexOf(keyNodes[0]),
76437                 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
76438
76439             keyNodes.push(nodes[oppositeIndex]);
76440             keyPoints.push(points[oppositeIndex]);
76441         }
76442
76443         // key points and nodes are those connected to the ways,
76444         // they are projected onto the circle, inbetween nodes are moved
76445         // to constant intervals between key nodes, extra inbetween nodes are
76446         // added if necessary.
76447         for (var i = 0; i < keyPoints.length; i++) {
76448             var nextKeyNodeIndex = (i + 1) % keyNodes.length,
76449                 startNode = keyNodes[i],
76450                 endNode = keyNodes[nextKeyNodeIndex],
76451                 startNodeIndex = nodes.indexOf(startNode),
76452                 endNodeIndex = nodes.indexOf(endNode),
76453                 numberNewPoints = -1,
76454                 indexRange = endNodeIndex - startNodeIndex,
76455                 nearNodes = {},
76456                 inBetweenNodes = [],
76457                 startAngle, endAngle, totalAngle, eachAngle,
76458                 angle, loc, node, origNode, j;
76459
76460             if (indexRange < 0) {
76461                 indexRange += nodes.length;
76462             }
76463
76464             // position this key node
76465             var distance$$1 = geoEuclideanDistance(centroid, keyPoints[i]);
76466             if (distance$$1 === 0) { distance$$1 = 1e-4; }
76467             keyPoints[i] = [
76468                 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance$$1 * radius,
76469                 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance$$1 * radius
76470             ];
76471             loc = projection$$1.invert(keyPoints[i]);
76472             node = keyNodes[i];
76473             origNode = origNodes[node.id];
76474             node = node.move(geoInterp(origNode.loc, loc, t));
76475             graph = graph.replace(node);
76476
76477             // figure out the between delta angle we want to match to
76478             startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
76479             endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
76480             totalAngle = endAngle - startAngle;
76481
76482             // detects looping around -pi/pi
76483             if (totalAngle * sign > 0) {
76484                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
76485             }
76486
76487             do {
76488                 numberNewPoints++;
76489                 eachAngle = totalAngle / (indexRange + numberNewPoints);
76490             } while (Math.abs(eachAngle) > maxAngle);
76491
76492
76493             // move existing nodes
76494             for (j = 1; j < indexRange; j++) {
76495                 angle = startAngle + j * eachAngle;
76496                 loc = projection$$1.invert([
76497                     centroid[0] + Math.cos(angle) * radius,
76498                     centroid[1] + Math.sin(angle) * radius
76499                 ]);
76500
76501                 node = nodes[(j + startNodeIndex) % nodes.length];
76502                 origNode = origNodes[node.id];
76503                 nearNodes[node.id] = angle;
76504
76505                 node = node.move(geoInterp(origNode.loc, loc, t));
76506                 graph = graph.replace(node);
76507             }
76508
76509             // add new inbetween nodes if necessary
76510             for (j = 0; j < numberNewPoints; j++) {
76511                 angle = startAngle + (indexRange + j) * eachAngle;
76512                 loc = projection$$1.invert([
76513                     centroid[0] + Math.cos(angle) * radius,
76514                     centroid[1] + Math.sin(angle) * radius
76515                 ]);
76516
76517                 // choose a nearnode to use as the original
76518                 var min$$1 = Infinity;
76519                 for (var nodeId in nearNodes) {
76520                     var nearAngle = nearNodes[nodeId],
76521                         dist = Math.abs(nearAngle - angle);
76522                     if (dist < min$$1) {
76523                         dist = min$$1;
76524                         origNode = origNodes[nodeId];
76525                     }
76526                 }
76527
76528                 node = osmNode({ loc: geoInterp(origNode.loc, loc, t) });
76529                 graph = graph.replace(node);
76530
76531                 nodes.splice(endNodeIndex + j, 0, node);
76532                 inBetweenNodes.push(node.id);
76533             }
76534
76535             // Check for other ways that share these keyNodes..
76536             // If keyNodes are adjacent in both ways,
76537             // we can add inBetween nodes to that shared way too..
76538             if (indexRange === 1 && inBetweenNodes.length) {
76539                 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
76540                     endIndex1 = way.nodes.lastIndexOf(endNode.id),
76541                     wayDirection1 = (endIndex1 - startIndex1);
76542                 if (wayDirection1 < -1) { wayDirection1 = 1; }
76543
76544                 /* eslint-disable no-loop-func */
76545                 lodash.each(lodash.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
76546                     if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
76547                         var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
76548                             endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
76549                             wayDirection2 = (endIndex2 - startIndex2),
76550                             insertAt = endIndex2;
76551                         if (wayDirection2 < -1) { wayDirection2 = 1; }
76552
76553                         if (wayDirection1 !== wayDirection2) {
76554                             inBetweenNodes.reverse();
76555                             insertAt = startIndex2;
76556                         }
76557                         for (j = 0; j < inBetweenNodes.length; j++) {
76558                             sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
76559                         }
76560                         graph = graph.replace(sharedWay);
76561                     }
76562                 });
76563                 /* eslint-enable no-loop-func */
76564             }
76565
76566         }
76567
76568         // update the way to have all the new nodes
76569         ids = nodes.map(function(n) { return n.id; });
76570         ids.push(ids[0]);
76571
76572         way = way.update({nodes: ids});
76573         graph = graph.replace(way);
76574
76575         return graph;
76576     };
76577
76578
76579     action.makeConvex = function(graph) {
76580         var way = graph.entity(wayId),
76581             nodes = lodash.uniq(graph.childNodes(way)),
76582             points = nodes.map(function(n) { return projection$$1(n.loc); }),
76583             sign = d3polygonArea(points) > 0 ? 1 : -1,
76584             hull = d3polygonHull(points);
76585
76586         // D3 convex hulls go counterclockwise..
76587         if (sign === -1) {
76588             nodes.reverse();
76589             points.reverse();
76590         }
76591
76592         for (var i = 0; i < hull.length - 1; i++) {
76593             var startIndex = points.indexOf(hull[i]),
76594                 endIndex = points.indexOf(hull[i+1]),
76595                 indexRange = (endIndex - startIndex);
76596
76597             if (indexRange < 0) {
76598                 indexRange += nodes.length;
76599             }
76600
76601             // move interior nodes to the surface of the convex hull..
76602             for (var j = 1; j < indexRange; j++) {
76603                 var point = geoInterp(hull[i], hull[i+1], j / indexRange),
76604                     node = nodes[(j + startIndex) % nodes.length].move(projection$$1.invert(point));
76605                 graph = graph.replace(node);
76606             }
76607         }
76608         return graph;
76609     };
76610
76611
76612     action.disabled = function(graph) {
76613         if (!graph.entity(wayId).isClosed())
76614             return 'not_closed';
76615     };
76616
76617
76618     action.transitionable = true;
76619
76620
76621     return action;
76622 }
76623
76624 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
76625 function actionDeleteWay(wayId) {
76626
76627
76628     function canDeleteNode(node, graph) {
76629         return !graph.parentWays(node).length &&
76630             !graph.parentRelations(node).length &&
76631             !node.hasInterestingTags();
76632     }
76633
76634
76635     var action = function(graph) {
76636         var way = graph.entity(wayId);
76637
76638         graph.parentRelations(way)
76639             .forEach(function(parent) {
76640                 parent = parent.removeMembersWithID(wayId);
76641                 graph = graph.replace(parent);
76642
76643                 if (parent.isDegenerate()) {
76644                     graph = actionDeleteRelation(parent.id)(graph);
76645                 }
76646             });
76647
76648         lodash.uniq(way.nodes).forEach(function(nodeId) {
76649             graph = graph.replace(way.removeNode(nodeId));
76650
76651             var node = graph.entity(nodeId);
76652             if (canDeleteNode(node, graph)) {
76653                 graph = graph.remove(node);
76654             }
76655         });
76656
76657         return graph.remove(way);
76658     };
76659
76660
76661     return action;
76662 }
76663
76664 function actionDeleteMultiple(ids) {
76665     var actions = {
76666         way: actionDeleteWay,
76667         node: actionDeleteNode,
76668         relation: actionDeleteRelation
76669     };
76670
76671
76672     var action = function(graph) {
76673         ids.forEach(function(id) {
76674             if (graph.hasEntity(id)) { // It may have been deleted aready.
76675                 graph = actions[graph.entity(id).type](id)(graph);
76676             }
76677         });
76678
76679         return graph;
76680     };
76681
76682
76683     return action;
76684 }
76685
76686 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
76687 function actionDeleteRelation(relationId) {
76688
76689
76690     function canDeleteEntity(entity, graph) {
76691         return !graph.parentWays(entity).length &&
76692             !graph.parentRelations(entity).length &&
76693             !entity.hasInterestingTags();
76694     }
76695
76696
76697     var action = function(graph) {
76698         var relation = graph.entity(relationId);
76699
76700         graph.parentRelations(relation)
76701             .forEach(function(parent) {
76702                 parent = parent.removeMembersWithID(relationId);
76703                 graph = graph.replace(parent);
76704
76705                 if (parent.isDegenerate()) {
76706                     graph = actionDeleteRelation(parent.id)(graph);
76707                 }
76708             });
76709
76710         lodash.uniq(lodash.map(relation.members, 'id')).forEach(function(memberId) {
76711             graph = graph.replace(relation.removeMembersWithID(memberId));
76712
76713             var entity = graph.entity(memberId);
76714             if (canDeleteEntity(entity, graph)) {
76715                 graph = actionDeleteMultiple([memberId])(graph);
76716             }
76717         });
76718
76719         return graph.remove(relation);
76720     };
76721
76722
76723     return action;
76724 }
76725
76726 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
76727 function actionDeleteNode(nodeId) {
76728     var action = function(graph) {
76729         var node = graph.entity(nodeId);
76730
76731         graph.parentWays(node)
76732             .forEach(function(parent) {
76733                 parent = parent.removeNode(nodeId);
76734                 graph = graph.replace(parent);
76735
76736                 if (parent.isDegenerate()) {
76737                     graph = actionDeleteWay(parent.id)(graph);
76738                 }
76739             });
76740
76741         graph.parentRelations(node)
76742             .forEach(function(parent) {
76743                 parent = parent.removeMembersWithID(nodeId);
76744                 graph = graph.replace(parent);
76745
76746                 if (parent.isDegenerate()) {
76747                     graph = actionDeleteRelation(parent.id)(graph);
76748                 }
76749             });
76750
76751         return graph.remove(node);
76752     };
76753
76754
76755     return action;
76756 }
76757
76758 // Connect the ways at the given nodes.
76759 //
76760 // The last node will survive. All other nodes will be replaced with
76761 // the surviving node in parent ways, and then removed.
76762 //
76763 // Tags and relation memberships of of non-surviving nodes are merged
76764 // to the survivor.
76765 //
76766 // This is the inverse of `iD.actionDisconnect`.
76767 //
76768 // Reference:
76769 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
76770 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
76771 //
76772 function actionConnect(nodeIds) {
76773     return function(graph) {
76774         var survivor = graph.entity(lodash.last(nodeIds));
76775
76776         for (var i = 0; i < nodeIds.length - 1; i++) {
76777             var node = graph.entity(nodeIds[i]);
76778
76779             /* eslint-disable no-loop-func */
76780             graph.parentWays(node).forEach(function(parent) {
76781                 if (!parent.areAdjacent(node.id, survivor.id)) {
76782                     graph = graph.replace(parent.replaceNode(node.id, survivor.id));
76783                 }
76784             });
76785
76786             graph.parentRelations(node).forEach(function(parent) {
76787                 graph = graph.replace(parent.replaceMember(node, survivor));
76788             });
76789             /* eslint-enable no-loop-func */
76790
76791             survivor = survivor.mergeTags(node.tags);
76792             graph = actionDeleteNode(node.id)(graph);
76793         }
76794
76795         graph = graph.replace(survivor);
76796
76797         return graph;
76798     };
76799 }
76800
76801 function actionCopyEntities(ids, fromGraph) {
76802     var copies = {};
76803
76804
76805     var action = function(graph) {
76806         ids.forEach(function(id) {
76807             fromGraph.entity(id).copy(fromGraph, copies);
76808         });
76809
76810         for (var id in copies) {
76811             graph = graph.replace(copies[id]);
76812         }
76813
76814         return graph;
76815     };
76816
76817
76818     action.copies = function() {
76819         return copies;
76820     };
76821
76822
76823     return action;
76824 }
76825
76826 function actionDeleteMember(relationId, memberIndex) {
76827     return function(graph) {
76828         var relation = graph.entity(relationId)
76829             .removeMember(memberIndex);
76830
76831         graph = graph.replace(relation);
76832
76833         if (relation.isDegenerate())
76834             graph = actionDeleteRelation(relation.id)(graph);
76835
76836         return graph;
76837     };
76838 }
76839
76840 function actionDeprecateTags(entityId) {
76841
76842     return function(graph) {
76843         var entity = graph.entity(entityId),
76844             newtags = lodash.clone(entity.tags),
76845             change = false,
76846             rule;
76847
76848         // This handles dataDeprecated tags with a single condition
76849         for (var i = 0; i < dataDeprecated.length; i++) {
76850
76851             rule = dataDeprecated[i];
76852             var match = lodash.toPairs(rule.old)[0],
76853                 replacements = rule.replace ? lodash.toPairs(rule.replace) : null;
76854
76855             if (entity.tags[match[0]] && match[1] === '*') {
76856
76857                 var value = entity.tags[match[0]];
76858                 if (replacements && !newtags[replacements[0][0]]) {
76859                     newtags[replacements[0][0]] = value;
76860                 }
76861                 delete newtags[match[0]];
76862                 change = true;
76863
76864             } else if (entity.tags[match[0]] === match[1]) {
76865                 newtags = lodash.assign({}, rule.replace || {}, lodash.omit(newtags, match[0]));
76866                 change = true;
76867             }
76868         }
76869
76870         if (change) {
76871             return graph.replace(entity.update({tags: newtags}));
76872         } else {
76873             return graph;
76874         }
76875     };
76876 }
76877
76878 function actionDiscardTags(difference) {
76879
76880     return function(graph) {
76881         function discardTags(entity) {
76882             if (!lodash.isEmpty(entity.tags)) {
76883                 var tags = {};
76884                 lodash.each(entity.tags, function(v, k) {
76885                     if (v) tags[k] = v;
76886                 });
76887
76888                 graph = graph.replace(entity.update({
76889                     tags: lodash.omit(tags, dataDiscarded)
76890                 }));
76891             }
76892         }
76893
76894         difference.modified().forEach(discardTags);
76895         difference.created().forEach(discardTags);
76896
76897         return graph;
76898     };
76899 }
76900
76901 // Disconect the ways at the given node.
76902 //
76903 // Optionally, disconnect only the given ways.
76904 //
76905 // For testing convenience, accepts an ID to assign to the (first) new node.
76906 // Normally, this will be undefined and the way will automatically
76907 // be assigned a new ID.
76908 //
76909 // This is the inverse of `iD.actionConnect`.
76910 //
76911 // Reference:
76912 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
76913 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
76914 //
76915 function actionDisconnect(nodeId, newNodeId) {
76916     var wayIds;
76917
76918
76919     var action = function(graph) {
76920         var node = graph.entity(nodeId),
76921             connections = action.connections(graph);
76922
76923         connections.forEach(function(connection) {
76924             var way = graph.entity(connection.wayID),
76925                 newNode = osmNode({id: newNodeId, loc: node.loc, tags: node.tags});
76926
76927             graph = graph.replace(newNode);
76928             if (connection.index === 0 && way.isArea()) {
76929                 // replace shared node with shared node..
76930                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
76931             } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
76932                 // replace closing node with new new node..
76933                 graph = graph.replace(way.unclose().addNode(newNode.id));
76934             } else {
76935                 // replace shared node with multiple new nodes..
76936                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
76937             }
76938         });
76939
76940         return graph;
76941     };
76942
76943
76944     action.connections = function(graph) {
76945         var candidates = [],
76946             keeping = false,
76947             parentWays = graph.parentWays(graph.entity(nodeId));
76948
76949         parentWays.forEach(function(way) {
76950             if (wayIds && wayIds.indexOf(way.id) === -1) {
76951                 keeping = true;
76952                 return;
76953             }
76954             if (way.isArea() && (way.nodes[0] === nodeId)) {
76955                 candidates.push({ wayID: way.id, index: 0 });
76956             } else {
76957                 way.nodes.forEach(function(waynode, index) {
76958                     if (waynode === nodeId) {
76959                         candidates.push({ wayID: way.id, index: index });
76960                     }
76961                 });
76962             }
76963         });
76964
76965         return keeping ? candidates : candidates.slice(1);
76966     };
76967
76968
76969     action.disabled = function(graph) {
76970         var connections = action.connections(graph);
76971         if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
76972             return 'not_connected';
76973
76974         var parentWays = graph.parentWays(graph.entity(nodeId)),
76975             seenRelationIds = {},
76976             sharedRelation;
76977
76978         parentWays.forEach(function(way) {
76979             if (wayIds && wayIds.indexOf(way.id) === -1)
76980                 return;
76981
76982             var relations = graph.parentRelations(way);
76983             relations.forEach(function(relation) {
76984                 if (relation.id in seenRelationIds) {
76985                     sharedRelation = relation;
76986                 } else {
76987                     seenRelationIds[relation.id] = true;
76988                 }
76989             });
76990         });
76991
76992         if (sharedRelation)
76993             return 'relation';
76994     };
76995
76996
76997     action.limitWays = function(_) {
76998         if (!arguments.length) return wayIds;
76999         wayIds = _;
77000         return action;
77001     };
77002
77003
77004     return action;
77005 }
77006
77007 // Join ways at the end node they share.
77008 //
77009 // This is the inverse of `iD.actionSplit`.
77010 //
77011 // Reference:
77012 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
77013 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
77014 //
77015 function actionJoin(ids) {
77016
77017     function groupEntitiesByGeometry(graph) {
77018         var entities = ids.map(function(id) { return graph.entity(id); });
77019         return lodash.extend({line: []}, lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
77020     }
77021
77022
77023     var action = function(graph) {
77024         var ways = ids.map(graph.entity, graph),
77025             survivor = ways[0];
77026
77027         // Prefer to keep an existing way.
77028         for (var i = 0; i < ways.length; i++) {
77029             if (!ways[i].isNew()) {
77030                 survivor = ways[i];
77031                 break;
77032             }
77033         }
77034
77035         var joined = osmJoinWays(ways, graph)[0];
77036
77037         survivor = survivor.update({nodes: lodash.map(joined.nodes, 'id')});
77038         graph = graph.replace(survivor);
77039
77040         joined.forEach(function(way) {
77041             if (way.id === survivor.id)
77042                 return;
77043
77044             graph.parentRelations(way).forEach(function(parent) {
77045                 graph = graph.replace(parent.replaceMember(way, survivor));
77046             });
77047
77048             survivor = survivor.mergeTags(way.tags);
77049
77050             graph = graph.replace(survivor);
77051             graph = actionDeleteWay(way.id)(graph);
77052         });
77053
77054         return graph;
77055     };
77056
77057
77058     action.disabled = function(graph) {
77059         var geometries = groupEntitiesByGeometry(graph);
77060         if (ids.length < 2 || ids.length !== geometries.line.length)
77061             return 'not_eligible';
77062
77063         var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
77064         if (joined.length > 1)
77065             return 'not_adjacent';
77066
77067         var nodeIds = lodash.map(joined[0].nodes, 'id').slice(1, -1),
77068             relation,
77069             tags = {},
77070             conflicting = false;
77071
77072         joined[0].forEach(function(way) {
77073             var parents = graph.parentRelations(way);
77074             parents.forEach(function(parent) {
77075                 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
77076                     relation = parent;
77077             });
77078
77079             for (var k in way.tags) {
77080                 if (!(k in tags)) {
77081                     tags[k] = way.tags[k];
77082                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
77083                     conflicting = true;
77084                 }
77085             }
77086         });
77087
77088         if (relation)
77089             return 'restriction';
77090
77091         if (conflicting)
77092             return 'conflicting_tags';
77093     };
77094
77095
77096     return action;
77097 }
77098
77099 function actionMerge(ids) {
77100
77101     function groupEntitiesByGeometry(graph) {
77102         var entities = ids.map(function(id) { return graph.entity(id); });
77103         return lodash.extend({point: [], area: [], line: [], relation: []},
77104             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
77105     }
77106
77107
77108     var action = function(graph) {
77109         var geometries = groupEntitiesByGeometry(graph),
77110             target = geometries.area[0] || geometries.line[0],
77111             points = geometries.point;
77112
77113         points.forEach(function(point) {
77114             target = target.mergeTags(point.tags);
77115             graph = graph.replace(target);
77116
77117             graph.parentRelations(point).forEach(function(parent) {
77118                 graph = graph.replace(parent.replaceMember(point, target));
77119             });
77120
77121             var nodes = lodash.uniq(graph.childNodes(target)),
77122                 removeNode = point;
77123
77124             for (var i = 0; i < nodes.length; i++) {
77125                 var node = nodes[i];
77126                 if (graph.parentWays(node).length > 1 ||
77127                     graph.parentRelations(node).length ||
77128                     node.hasInterestingTags()) {
77129                     continue;
77130                 }
77131
77132                 // Found an uninteresting child node on the target way.
77133                 // Move orig point into its place to preserve point's history. #3683
77134                 graph = graph.replace(point.update({ tags: {}, loc: node.loc }));
77135                 target = target.replaceNode(node.id, point.id);
77136                 graph = graph.replace(target);
77137                 removeNode = node;
77138                 break;
77139             }
77140
77141             graph = graph.remove(removeNode);
77142         });
77143
77144         return graph;
77145     };
77146
77147
77148     action.disabled = function(graph) {
77149         var geometries = groupEntitiesByGeometry(graph);
77150         if (geometries.point.length === 0 ||
77151             (geometries.area.length + geometries.line.length) !== 1 ||
77152             geometries.relation.length !== 0)
77153             return 'not_eligible';
77154     };
77155
77156
77157     return action;
77158 }
77159
77160 function actionMergePolygon(ids, newRelationId) {
77161
77162     function groupEntities(graph) {
77163         var entities = ids.map(function (id) { return graph.entity(id); });
77164         return lodash.extend({
77165                 closedWay: [],
77166                 multipolygon: [],
77167                 other: []
77168             }, lodash.groupBy(entities, function(entity) {
77169                 if (entity.type === 'way' && entity.isClosed()) {
77170                     return 'closedWay';
77171                 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
77172                     return 'multipolygon';
77173                 } else {
77174                     return 'other';
77175                 }
77176             }));
77177     }
77178
77179
77180     var action = function(graph) {
77181         var entities = groupEntities(graph);
77182
77183         // An array representing all the polygons that are part of the multipolygon.
77184         //
77185         // Each element is itself an array of objects with an id property, and has a
77186         // locs property which is an array of the locations forming the polygon.
77187         var polygons = entities.multipolygon.reduce(function(polygons, m) {
77188             return polygons.concat(osmJoinWays(m.members, graph));
77189         }, []).concat(entities.closedWay.map(function(d) {
77190             var member = [{id: d.id}];
77191             member.nodes = graph.childNodes(d);
77192             return member;
77193         }));
77194
77195         // contained is an array of arrays of boolean values,
77196         // where contained[j][k] is true iff the jth way is
77197         // contained by the kth way.
77198         var contained = polygons.map(function(w, i) {
77199             return polygons.map(function(d, n) {
77200                 if (i === n) return null;
77201                 return geoPolygonContainsPolygon(
77202                     lodash.map(d.nodes, 'loc'),
77203                     lodash.map(w.nodes, 'loc'));
77204             });
77205         });
77206
77207         // Sort all polygons as either outer or inner ways
77208         var members = [],
77209             outer = true;
77210
77211         while (polygons.length) {
77212             extractUncontained(polygons);
77213             polygons = polygons.filter(isContained);
77214             contained = contained.filter(isContained).map(filterContained);
77215         }
77216
77217         function isContained(d, i) {
77218             return lodash.some(contained[i]);
77219         }
77220
77221         function filterContained(d) {
77222             return d.filter(isContained);
77223         }
77224
77225         function extractUncontained(polygons) {
77226             polygons.forEach(function(d, i) {
77227                 if (!isContained(d, i)) {
77228                     d.forEach(function(member) {
77229                         members.push({
77230                             type: 'way',
77231                             id: member.id,
77232                             role: outer ? 'outer' : 'inner'
77233                         });
77234                     });
77235                 }
77236             });
77237             outer = !outer;
77238         }
77239
77240         // Move all tags to one relation
77241         var relation = entities.multipolygon[0] ||
77242             osmRelation({ id: newRelationId, tags: { type: 'multipolygon' }});
77243
77244         entities.multipolygon.slice(1).forEach(function(m) {
77245             relation = relation.mergeTags(m.tags);
77246             graph = graph.remove(m);
77247         });
77248
77249         entities.closedWay.forEach(function(way) {
77250             function isThisOuter(m) {
77251                 return m.id === way.id && m.role !== 'inner';
77252             }
77253             if (members.some(isThisOuter)) {
77254                 relation = relation.mergeTags(way.tags);
77255                 graph = graph.replace(way.update({ tags: {} }));
77256             }
77257         });
77258
77259         return graph.replace(relation.update({
77260             members: members,
77261             tags: lodash.omit(relation.tags, 'area')
77262         }));
77263     };
77264
77265
77266     action.disabled = function(graph) {
77267         var entities = groupEntities(graph);
77268         if (entities.other.length > 0 ||
77269             entities.closedWay.length + entities.multipolygon.length < 2)
77270             return 'not_eligible';
77271         if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
77272             return 'incomplete_relation';
77273     };
77274
77275
77276     return action;
77277 }
77278
77279 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
77280 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
77281 //
77282 // Permission is hereby granted, free of charge, to any person
77283 // obtaining a copy of this software and associated documentation files
77284 // (the "Software"), to deal in the Software without restriction,
77285 // including without limitation the rights to use, copy, modify, merge,
77286 // publish, distribute, sublicense, and/or sell copies of the Software,
77287 // and to permit persons to whom the Software is furnished to do so,
77288 // subject to the following conditions:
77289 //
77290 // The above copyright notice and this permission notice shall be
77291 // included in all copies or substantial portions of the Software.
77292 //
77293 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
77294 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
77295 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
77296 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
77297 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
77298 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
77299 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
77300 // SOFTWARE.
77301
77302 // source:  https://bitbucket.org/lshift/synchrotron/src
77303 function longest_common_subsequence(file1, file2) {
77304     /* Text diff algorithm following Hunt and McIlroy 1976.
77305      * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
77306      * comparison, Bell Telephone Laboratories CSTR #41 (1976)
77307      * http://www.cs.dartmouth.edu/~doug/
77308      *
77309      * Expects two arrays of strings.
77310      */
77311     var equivalenceClasses;
77312     var file2indices;
77313     var newCandidate;
77314     var candidates;
77315     var line;
77316     var c, i, j, jX, r, s;
77317
77318     equivalenceClasses = {};
77319     for (j = 0; j < file2.length; j++) {
77320         line = file2[j];
77321         if (equivalenceClasses[line]) {
77322             equivalenceClasses[line].push(j);
77323         } else {
77324             equivalenceClasses[line] = [j];
77325         }
77326     }
77327
77328     candidates = [{file1index: -1,
77329                    file2index: -1,
77330                    chain: null}];
77331
77332     for (i = 0; i < file1.length; i++) {
77333         line = file1[i];
77334         file2indices = equivalenceClasses[line] || [];
77335
77336         r = 0;
77337         c = candidates[0];
77338
77339         for (jX = 0; jX < file2indices.length; jX++) {
77340             j = file2indices[jX];
77341
77342             for (s = 0; s < candidates.length; s++) {
77343                 if ((candidates[s].file2index < j) &&
77344                     ((s === candidates.length - 1) ||
77345                      (candidates[s + 1].file2index > j)))
77346                     break;
77347             }
77348
77349             if (s < candidates.length) {
77350                 newCandidate = {file1index: i,
77351                                 file2index: j,
77352                                 chain: candidates[s]};
77353                 if (r === candidates.length) {
77354                     candidates.push(c);
77355                 } else {
77356                     candidates[r] = c;
77357                 }
77358                 r = s + 1;
77359                 c = newCandidate;
77360                 if (r === candidates.length) {
77361                     break; // no point in examining further (j)s
77362                 }
77363             }
77364         }
77365
77366         candidates[r] = c;
77367     }
77368
77369     // At this point, we know the LCS: it's in the reverse of the
77370     // linked-list through .chain of
77371     // candidates[candidates.length - 1].
77372
77373     return candidates[candidates.length - 1];
77374 }
77375
77376
77377
77378
77379
77380
77381
77382
77383
77384
77385
77386 function diff_indices(file1, file2) {
77387     // We apply the LCS to give a simple representation of the
77388     // offsets and lengths of mismatched chunks in the input
77389     // files. This is used by diff3_merge_indices below.
77390
77391     var result = [];
77392     var tail1 = file1.length;
77393     var tail2 = file2.length;
77394
77395     for (var candidate = longest_common_subsequence(file1, file2);
77396          candidate !== null;
77397          candidate = candidate.chain)
77398     {
77399         var mismatchLength1 = tail1 - candidate.file1index - 1;
77400         var mismatchLength2 = tail2 - candidate.file2index - 1;
77401         tail1 = candidate.file1index;
77402         tail2 = candidate.file2index;
77403
77404         if (mismatchLength1 || mismatchLength2) {
77405             result.push({file1: [tail1 + 1, mismatchLength1],
77406                          file2: [tail2 + 1, mismatchLength2]});
77407         }
77408     }
77409
77410     result.reverse();
77411     return result;
77412 }
77413
77414 function diff3_merge_indices (a, o, b) {
77415     // Given three files, A, O, and B, where both A and B are
77416     // independently derived from O, returns a fairly complicated
77417     // internal representation of merge decisions it's taken. The
77418     // interested reader may wish to consult
77419     //
77420     // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
77421     // Formal Investigation of Diff3." In Arvind and Prasad,
77422     // editors, Foundations of Software Technology and Theoretical
77423     // Computer Science (FSTTCS), December 2007.
77424     //
77425     // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
77426     var i;
77427
77428     var m1 = diff_indices(o, a);
77429     var m2 = diff_indices(o, b);
77430
77431     var hunks = [];
77432     function addHunk(h, side) {
77433         hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
77434     }
77435     for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
77436     for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
77437     hunks.sort();
77438
77439     var result = [];
77440     var commonOffset = 0;
77441     function copyCommon(targetOffset) {
77442         if (targetOffset > commonOffset) {
77443             result.push([1, commonOffset, targetOffset - commonOffset]);
77444             commonOffset = targetOffset;
77445         }
77446     }
77447
77448     for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
77449         var firstHunkIndex = hunkIndex;
77450         var hunk = hunks[hunkIndex];
77451         var regionLhs = hunk[0];
77452         var regionRhs = regionLhs + hunk[2];
77453         while (hunkIndex < hunks.length - 1) {
77454             var maybeOverlapping = hunks[hunkIndex + 1];
77455             var maybeLhs = maybeOverlapping[0];
77456             if (maybeLhs > regionRhs) break;
77457             regionRhs = maybeLhs + maybeOverlapping[2];
77458             hunkIndex++;
77459         }
77460
77461         copyCommon(regionLhs);
77462         if (firstHunkIndex === hunkIndex) {
77463     // The "overlap" was only one hunk long, meaning that
77464     // there's no conflict here. Either a and o were the
77465     // same, or b and o were the same.
77466             if (hunk[4] > 0) {
77467                 result.push([hunk[1], hunk[3], hunk[4]]);
77468             }
77469         } else {
77470     // A proper conflict. Determine the extents of the
77471     // regions involved from a, o and b. Effectively merge
77472     // all the hunks on the left into one giant hunk, and
77473     // do the same for the right; then, correct for skew
77474     // in the regions of o that each side changed, and
77475     // report appropriate spans for the three sides.
77476     var regions = {
77477         0: [a.length, -1, o.length, -1],
77478         2: [b.length, -1, o.length, -1]
77479     };
77480             for (i = firstHunkIndex; i <= hunkIndex; i++) {
77481         hunk = hunks[i];
77482                 var side = hunk[1];
77483         var r = regions[side];
77484         var oLhs = hunk[0];
77485         var oRhs = oLhs + hunk[2];
77486                 var abLhs = hunk[3];
77487                 var abRhs = abLhs + hunk[4];
77488         r[0] = Math.min(abLhs, r[0]);
77489         r[1] = Math.max(abRhs, r[1]);
77490         r[2] = Math.min(oLhs, r[2]);
77491         r[3] = Math.max(oRhs, r[3]);
77492             }
77493     var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
77494     var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
77495     var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
77496     var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
77497             result.push([-1,
77498              aLhs,      aRhs      - aLhs,
77499              regionLhs, regionRhs - regionLhs,
77500              bLhs,      bRhs      - bLhs]);
77501         }
77502         commonOffset = regionRhs;
77503     }
77504
77505     copyCommon(o.length);
77506     return result;
77507 }
77508
77509 function diff3_merge (a, o, b, excludeFalseConflicts) {
77510     // Applies the output of Diff3.diff3_merge_indices to actually
77511     // construct the merged file; the returned result alternates
77512     // between "ok" and "conflict" blocks.
77513
77514     var result = [];
77515     var files = [a, o, b];
77516     var indices = diff3_merge_indices(a, o, b);
77517
77518     var okLines = [];
77519     function flushOk() {
77520         if (okLines.length) {
77521             result.push({ok: okLines});
77522         }
77523         okLines = [];
77524     }
77525     function pushOk(xs) {
77526         for (var j = 0; j < xs.length; j++) {
77527             okLines.push(xs[j]);
77528         }
77529     }
77530
77531     function isTrueConflict(rec) {
77532         if (rec[2] !== rec[6]) return true;
77533         var aoff = rec[1];
77534         var boff = rec[5];
77535         for (var j = 0; j < rec[2]; j++) {
77536             if (a[j + aoff] !== b[j + boff]) return true;
77537         }
77538         return false;
77539     }
77540
77541     for (var i = 0; i < indices.length; i++) {
77542         var x = indices[i];
77543         var side = x[0];
77544         if (side === -1) {
77545             if (excludeFalseConflicts && !isTrueConflict(x)) {
77546                 pushOk(files[0].slice(x[1], x[1] + x[2]));
77547             } else {
77548                 flushOk();
77549                 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
77550                                         aIndex: x[1],
77551                                         o: o.slice(x[3], x[3] + x[4]),
77552                                         oIndex: x[3],
77553                                         b: b.slice(x[5], x[5] + x[6]),
77554                                         bIndex: x[5]}});
77555             }
77556         } else {
77557             pushOk(files[side].slice(x[1], x[1] + x[2]));
77558         }
77559     }
77560
77561     flushOk();
77562     return result;
77563 }
77564
77565 function actionMergeRemoteChanges(id, localGraph, remoteGraph, formatUser) {
77566     var option = 'safe',  // 'safe', 'force_local', 'force_remote'
77567         conflicts = [];
77568
77569
77570     function user(d) {
77571         return lodash.isFunction(formatUser) ? formatUser(d) : d;
77572     }
77573
77574
77575     function mergeLocation(remote, target) {
77576         function pointEqual(a, b) {
77577             var epsilon = 1e-6;
77578             return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
77579         }
77580
77581         if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
77582             return target;
77583         }
77584         if (option === 'force_remote') {
77585             return target.update({loc: remote.loc});
77586         }
77587
77588         conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
77589         return target;
77590     }
77591
77592
77593     function mergeNodes(base, remote, target) {
77594         if (option === 'force_local' || lodash.isEqual(target.nodes, remote.nodes)) {
77595             return target;
77596         }
77597         if (option === 'force_remote') {
77598             return target.update({nodes: remote.nodes});
77599         }
77600
77601         var ccount = conflicts.length,
77602             o = base.nodes || [],
77603             a = target.nodes || [],
77604             b = remote.nodes || [],
77605             nodes = [],
77606             hunks = diff3_merge(a, o, b, true);
77607
77608         for (var i = 0; i < hunks.length; i++) {
77609             var hunk = hunks[i];
77610             if (hunk.ok) {
77611                 nodes.push.apply(nodes, hunk.ok);
77612             } else {
77613                 // for all conflicts, we can assume c.a !== c.b
77614                 // because `diff3_merge` called with `true` option to exclude false conflicts..
77615                 var c = hunk.conflict;
77616                 if (lodash.isEqual(c.o, c.a)) {  // only changed remotely
77617                     nodes.push.apply(nodes, c.b);
77618                 } else if (lodash.isEqual(c.o, c.b)) {  // only changed locally
77619                     nodes.push.apply(nodes, c.a);
77620                 } else {       // changed both locally and remotely
77621                     conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
77622                     break;
77623                 }
77624             }
77625         }
77626
77627         return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
77628     }
77629
77630
77631     function mergeChildren(targetWay, children, updates, graph) {
77632         function isUsed(node, targetWay) {
77633             var parentWays = lodash.map(graph.parentWays(node), 'id');
77634             return node.hasInterestingTags() ||
77635                 lodash.without(parentWays, targetWay.id).length > 0 ||
77636                 graph.parentRelations(node).length > 0;
77637         }
77638
77639         var ccount = conflicts.length;
77640
77641         for (var i = 0; i < children.length; i++) {
77642             var id = children[i],
77643                 node = graph.hasEntity(id);
77644
77645             // remove unused childNodes..
77646             if (targetWay.nodes.indexOf(id) === -1) {
77647                 if (node && !isUsed(node, targetWay)) {
77648                     updates.removeIds.push(id);
77649                 }
77650                 continue;
77651             }
77652
77653             // restore used childNodes..
77654             var local = localGraph.hasEntity(id),
77655                 remote = remoteGraph.hasEntity(id),
77656                 target;
77657
77658             if (option === 'force_remote' && remote && remote.visible) {
77659                 updates.replacements.push(remote);
77660
77661             } else if (option === 'force_local' && local) {
77662                 target = osmEntity$$1(local);
77663                 if (remote) {
77664                     target = target.update({ version: remote.version });
77665                 }
77666                 updates.replacements.push(target);
77667
77668             } else if (option === 'safe' && local && remote && local.version !== remote.version) {
77669                 target = osmEntity$$1(local, { version: remote.version });
77670                 if (remote.visible) {
77671                     target = mergeLocation(remote, target);
77672                 } else {
77673                     conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
77674                 }
77675
77676                 if (conflicts.length !== ccount) break;
77677                 updates.replacements.push(target);
77678             }
77679         }
77680
77681         return targetWay;
77682     }
77683
77684
77685     function updateChildren(updates, graph) {
77686         for (var i = 0; i < updates.replacements.length; i++) {
77687             graph = graph.replace(updates.replacements[i]);
77688         }
77689         if (updates.removeIds.length) {
77690             graph = actionDeleteMultiple(updates.removeIds)(graph);
77691         }
77692         return graph;
77693     }
77694
77695
77696     function mergeMembers(remote, target) {
77697         if (option === 'force_local' || lodash.isEqual(target.members, remote.members)) {
77698             return target;
77699         }
77700         if (option === 'force_remote') {
77701             return target.update({members: remote.members});
77702         }
77703
77704         conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
77705         return target;
77706     }
77707
77708
77709     function mergeTags(base, remote, target) {
77710         function ignoreKey(k) {
77711             return lodash.includes(dataDiscarded, k);
77712         }
77713
77714         if (option === 'force_local' || lodash.isEqual(target.tags, remote.tags)) {
77715             return target;
77716         }
77717         if (option === 'force_remote') {
77718             return target.update({tags: remote.tags});
77719         }
77720
77721         var ccount = conflicts.length,
77722             o = base.tags || {},
77723             a = target.tags || {},
77724             b = remote.tags || {},
77725             keys = lodash.reject(lodash.union(lodash.keys(o), lodash.keys(a), lodash.keys(b)), ignoreKey),
77726             tags = lodash.clone(a),
77727             changed = false;
77728
77729         for (var i = 0; i < keys.length; i++) {
77730             var k = keys[i];
77731
77732             if (o[k] !== b[k] && a[k] !== b[k]) {    // changed remotely..
77733                 if (o[k] !== a[k]) {      // changed locally..
77734                     conflicts.push(t('merge_remote_changes.conflict.tags',
77735                         { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
77736
77737                 } else {                  // unchanged locally, accept remote change..
77738                     if (b.hasOwnProperty(k)) {
77739                         tags[k] = b[k];
77740                     } else {
77741                         delete tags[k];
77742                     }
77743                     changed = true;
77744                 }
77745             }
77746         }
77747
77748         return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
77749     }
77750
77751
77752     //  `graph.base()` is the common ancestor of the two graphs.
77753     //  `localGraph` contains user's edits up to saving
77754     //  `remoteGraph` contains remote edits to modified nodes
77755     //  `graph` must be a descendent of `localGraph` and may include
77756     //      some conflict resolution actions performed on it.
77757     //
77758     //                  --- ... --- `localGraph` -- ... -- `graph`
77759     //                 /
77760     //  `graph.base()` --- ... --- `remoteGraph`
77761     //
77762     var action = function(graph) {
77763         var updates = { replacements: [], removeIds: [] },
77764             base = graph.base().entities[id],
77765             local = localGraph.entity(id),
77766             remote = remoteGraph.entity(id),
77767             target = osmEntity$$1(local, { version: remote.version });
77768
77769         // delete/undelete
77770         if (!remote.visible) {
77771             if (option === 'force_remote') {
77772                 return actionDeleteMultiple([id])(graph);
77773
77774             } else if (option === 'force_local') {
77775                 if (target.type === 'way') {
77776                     target = mergeChildren(target, lodash.uniq(local.nodes), updates, graph);
77777                     graph = updateChildren(updates, graph);
77778                 }
77779                 return graph.replace(target);
77780
77781             } else {
77782                 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
77783                 return graph;  // do nothing
77784             }
77785         }
77786
77787         // merge
77788         if (target.type === 'node') {
77789             target = mergeLocation(remote, target);
77790
77791         } else if (target.type === 'way') {
77792             // pull in any child nodes that may not be present locally..
77793             graph.rebase(remoteGraph.childNodes(remote), [graph], false);
77794             target = mergeNodes(base, remote, target);
77795             target = mergeChildren(target, lodash.union(local.nodes, remote.nodes), updates, graph);
77796
77797         } else if (target.type === 'relation') {
77798             target = mergeMembers(remote, target);
77799         }
77800
77801         target = mergeTags(base, remote, target);
77802
77803         if (!conflicts.length) {
77804             graph = updateChildren(updates, graph).replace(target);
77805         }
77806
77807         return graph;
77808     };
77809
77810
77811     action.withOption = function(opt) {
77812         option = opt;
77813         return action;
77814     };
77815
77816
77817     action.conflicts = function() {
77818         return conflicts;
77819     };
77820
77821
77822     return action;
77823 }
77824
77825 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
77826 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
77827 function actionMove(moveIds, tryDelta, projection, cache) {
77828     var delta = tryDelta;
77829
77830     function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
77831     function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
77832
77833     function setupCache(graph) {
77834         function canMove(nodeId) {
77835             // Allow movement of any node that is in the selectedIDs list..
77836             if (moveIds.indexOf(nodeId) !== -1) return true;
77837
77838             // Allow movement of a vertex where 2 ways meet..
77839             var parents = lodash.map(graph.parentWays(graph.entity(nodeId)), 'id');
77840             if (parents.length < 3) return true;
77841
77842             // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
77843             var parentsMoving = lodash.every(parents, function(id) { return cache.moving[id]; });
77844             if (!parentsMoving) delete cache.moving[nodeId];
77845
77846             return parentsMoving;
77847         }
77848
77849         function cacheEntities(ids) {
77850             ids.forEach(function(id) {
77851                 if (cache.moving[id]) return;
77852                 cache.moving[id] = true;
77853
77854                 var entity = graph.hasEntity(id);
77855                 if (!entity) return;
77856
77857                 if (entity.type === 'node') {
77858                     cache.nodes.push(id);
77859                     cache.startLoc[id] = entity.loc;
77860                 } else if (entity.type === 'way') {
77861                     cache.ways.push(id);
77862                     cacheEntities(entity.nodes);
77863                 } else {
77864                     cacheEntities(entity.members.map(function(member) {
77865                         return member.id;
77866                     }));
77867                 }
77868             });
77869         }
77870
77871         function cacheIntersections(ids) {
77872             function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
77873
77874             ids.forEach(function(id) {
77875                 // consider only intersections with 1 moved and 1 unmoved way.
77876                 var childNodes = graph.childNodes(graph.entity(id));
77877                 childNodes.forEach(function(node) {
77878                     var parents = graph.parentWays(node);
77879                     if (parents.length !== 2) return;
77880
77881                     var moved = graph.entity(id),
77882                         unmoved = lodash.find(parents, function(way) { return !cache.moving[way.id]; });
77883                     if (!unmoved) return;
77884
77885                     // exclude ways that are overly connected..
77886                     if (lodash.intersection(moved.nodes, unmoved.nodes).length > 2) return;
77887
77888                     if (moved.isArea() || unmoved.isArea()) return;
77889
77890                     cache.intersection[node.id] = {
77891                         nodeId: node.id,
77892                         movedId: moved.id,
77893                         unmovedId: unmoved.id,
77894                         movedIsEP: isEndpoint(moved, node.id),
77895                         unmovedIsEP: isEndpoint(unmoved, node.id)
77896                     };
77897                 });
77898             });
77899         }
77900
77901
77902         if (!cache) {
77903             cache = {};
77904         }
77905         if (!cache.ok) {
77906             cache.moving = {};
77907             cache.intersection = {};
77908             cache.replacedVertex = {};
77909             cache.startLoc = {};
77910             cache.nodes = [];
77911             cache.ways = [];
77912
77913             cacheEntities(moveIds);
77914             cacheIntersections(cache.ways);
77915             cache.nodes = lodash.filter(cache.nodes, canMove);
77916
77917             cache.ok = true;
77918         }
77919     }
77920
77921
77922     // Place a vertex where the moved vertex used to be, to preserve way shape..
77923     function replaceMovedVertex(nodeId, wayId, graph, delta) {
77924         var way = graph.entity(wayId),
77925             moved = graph.entity(nodeId),
77926             movedIndex = way.nodes.indexOf(nodeId),
77927             len, prevIndex, nextIndex;
77928
77929         if (way.isClosed()) {
77930             len = way.nodes.length - 1;
77931             prevIndex = (movedIndex + len - 1) % len;
77932             nextIndex = (movedIndex + len + 1) % len;
77933         } else {
77934             len = way.nodes.length;
77935             prevIndex = movedIndex - 1;
77936             nextIndex = movedIndex + 1;
77937         }
77938
77939         var prev = graph.hasEntity(way.nodes[prevIndex]),
77940             next = graph.hasEntity(way.nodes[nextIndex]);
77941
77942         // Don't add orig vertex at endpoint..
77943         if (!prev || !next) return graph;
77944
77945         var key = wayId + '_' + nodeId,
77946             orig = cache.replacedVertex[key];
77947         if (!orig) {
77948             orig = osmNode();
77949             cache.replacedVertex[key] = orig;
77950             cache.startLoc[orig.id] = cache.startLoc[nodeId];
77951         }
77952
77953         var start, end;
77954         if (delta) {
77955             start = projection(cache.startLoc[nodeId]);
77956             end = projection.invert(vecAdd(start, delta));
77957         } else {
77958             end = cache.startLoc[nodeId];
77959         }
77960         orig = orig.move(end);
77961
77962         var angle = Math.abs(geoAngle(orig, prev, projection) -
77963                 geoAngle(orig, next, projection)) * 180 / Math.PI;
77964
77965         // Don't add orig vertex if it would just make a straight line..
77966         if (angle > 175 && angle < 185) return graph;
77967
77968         // Don't add orig vertex if another point is already nearby (within 10m)
77969         if (geoSphericalDistance(prev.loc, orig.loc) < 10 ||
77970             geoSphericalDistance(orig.loc, next.loc) < 10) return graph;
77971
77972         // moving forward or backward along way?
77973         var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
77974             p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
77975             d1 = geoPathLength(p1),
77976             d2 = geoPathLength(p2),
77977             insertAt = (d1 < d2) ? movedIndex : nextIndex;
77978
77979         // moving around closed loop?
77980         if (way.isClosed() && insertAt === 0) insertAt = len;
77981
77982         way = way.addNode(orig.id, insertAt);
77983         return graph.replace(orig).replace(way);
77984     }
77985
77986
77987     // Reorder nodes around intersections that have moved..
77988     function unZorroIntersection(intersection, graph) {
77989         var vertex = graph.entity(intersection.nodeId),
77990             way1 = graph.entity(intersection.movedId),
77991             way2 = graph.entity(intersection.unmovedId),
77992             isEP1 = intersection.movedIsEP,
77993             isEP2 = intersection.unmovedIsEP;
77994
77995         // don't move the vertex if it is the endpoint of both ways.
77996         if (isEP1 && isEP2) return graph;
77997
77998         var nodes1 = lodash.without(graph.childNodes(way1), vertex),
77999             nodes2 = lodash.without(graph.childNodes(way2), vertex);
78000
78001         if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
78002         if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
78003
78004         var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection),
78005             edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection),
78006             loc;
78007
78008         // snap vertex to nearest edge (or some point between them)..
78009         if (!isEP1 && !isEP2) {
78010             var epsilon = 1e-4, maxIter = 10;
78011             for (var i = 0; i < maxIter; i++) {
78012                 loc = geoInterp(edge1.loc, edge2.loc, 0.5);
78013                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
78014                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
78015                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
78016             }
78017         } else if (!isEP1) {
78018             loc = edge1.loc;
78019         } else {
78020             loc = edge2.loc;
78021         }
78022
78023         graph = graph.replace(vertex.move(loc));
78024
78025         // if zorro happened, reorder nodes..
78026         if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
78027             way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
78028             graph = graph.replace(way1);
78029         }
78030         if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
78031             way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
78032             graph = graph.replace(way2);
78033         }
78034
78035         return graph;
78036     }
78037
78038
78039     function cleanupIntersections(graph) {
78040         lodash.each(cache.intersection, function(obj) {
78041             graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
78042             graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
78043             graph = unZorroIntersection(obj, graph);
78044         });
78045
78046         return graph;
78047     }
78048
78049
78050     // check if moving way endpoint can cross an unmoved way, if so limit delta..
78051     function limitDelta(graph) {
78052         lodash.each(cache.intersection, function(obj) {
78053             // Don't limit movement if this is vertex joins 2 endpoints..
78054             if (obj.movedIsEP && obj.unmovedIsEP) return;
78055             // Don't limit movement if this vertex is not an endpoint anyway..
78056             if (!obj.movedIsEP) return;
78057
78058             var node = graph.entity(obj.nodeId),
78059                 start = projection(node.loc),
78060                 end = vecAdd(start, delta),
78061                 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
78062                 movedPath = lodash.map(lodash.map(movedNodes, 'loc'),
78063                     function(loc) { return vecAdd(projection(loc), delta); }),
78064                 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
78065                 unmovedPath = lodash.map(lodash.map(unmovedNodes, 'loc'), projection),
78066                 hits = geoPathIntersections(movedPath, unmovedPath);
78067
78068             for (var i = 0; i < hits.length; i++) {
78069                 if (lodash.isEqual(hits[i], end)) continue;
78070                 var edge = geoChooseEdge(unmovedNodes, end, projection);
78071                 delta = vecSub(projection(edge.loc), start);
78072             }
78073         });
78074     }
78075
78076
78077     var action = function(graph) {
78078         if (delta[0] === 0 && delta[1] === 0) return graph;
78079
78080         setupCache(graph);
78081
78082         if (!lodash.isEmpty(cache.intersection)) {
78083             limitDelta(graph);
78084         }
78085
78086         lodash.each(cache.nodes, function(id) {
78087             var node = graph.entity(id),
78088                 start = projection(node.loc),
78089                 end = vecAdd(start, delta);
78090             graph = graph.replace(node.move(projection.invert(end)));
78091         });
78092
78093         if (!lodash.isEmpty(cache.intersection)) {
78094             graph = cleanupIntersections(graph);
78095         }
78096
78097         return graph;
78098     };
78099
78100
78101     action.delta = function() {
78102         return delta;
78103     };
78104
78105
78106     return action;
78107 }
78108
78109 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
78110 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
78111 function actionMoveNode(nodeId, loc) {
78112     return function(graph) {
78113         return graph.replace(graph.entity(nodeId).move(loc));
78114     };
78115 }
78116
78117 function actionNoop() {
78118     return function(graph) {
78119         return graph;
78120     };
78121 }
78122
78123 /*
78124  * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
78125  */
78126 function actionOrthogonalize(wayId, projection) {
78127     var threshold = 12, // degrees within right or straight to alter
78128         lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
78129         upperThreshold = Math.cos(threshold * Math.PI / 180);
78130
78131
78132     var action = function(graph, t) {
78133         if (t === null || !isFinite(t)) t = 1;
78134         t = Math.min(Math.max(+t, 0), 1);
78135
78136         var way = graph.entity(wayId),
78137             nodes = graph.childNodes(way),
78138             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); }),
78139             corner = {i: 0, dotp: 1},
78140             epsilon = 1e-4,
78141             node, loc, score, motions, i, j;
78142
78143         if (points.length === 3) {   // move only one vertex for right triangle
78144             for (i = 0; i < 1000; i++) {
78145                 motions = points.map(calcMotion);
78146                 points[corner.i] = addPoints(points[corner.i], motions[corner.i]);
78147                 score = corner.dotp;
78148                 if (score < epsilon) {
78149                     break;
78150                 }
78151             }
78152
78153             node = graph.entity(nodes[corner.i].id);
78154             loc = projection.invert(points[corner.i]);
78155             graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
78156
78157         } else {
78158             var best,
78159                 originalPoints = lodash.clone(points);
78160             score = Infinity;
78161
78162             for (i = 0; i < 1000; i++) {
78163                 motions = points.map(calcMotion);
78164                 for (j = 0; j < motions.length; j++) {
78165                     points[j] = addPoints(points[j],motions[j]);
78166                 }
78167                 var newScore = squareness(points);
78168                 if (newScore < score) {
78169                     best = lodash.clone(points);
78170                     score = newScore;
78171                 }
78172                 if (score < epsilon) {
78173                     break;
78174                 }
78175             }
78176
78177             points = best;
78178
78179             for (i = 0; i < points.length; i++) {
78180                 // only move the points that actually moved
78181                 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
78182                     loc = projection.invert(points[i]);
78183                     node = graph.entity(nodes[i].id);
78184                     graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
78185                 }
78186             }
78187
78188             // remove empty nodes on straight sections
78189             for (i = 0; t === 1 && i < points.length; i++) {
78190                 node = graph.entity(nodes[i].id);
78191
78192                 if (graph.parentWays(node).length > 1 ||
78193                     graph.parentRelations(node).length ||
78194                     node.hasInterestingTags()) {
78195                     continue;
78196                 }
78197
78198                 var dotp = normalizedDotProduct(i, points);
78199                 if (dotp < -1 + epsilon) {
78200                     graph = actionDeleteNode(node.id)(graph);
78201                 }
78202             }
78203         }
78204
78205         return graph;
78206
78207
78208         function calcMotion(b, i, array) {
78209             var a = array[(i - 1 + array.length) % array.length],
78210                 c = array[(i + 1) % array.length],
78211                 p = subtractPoints(a, b),
78212                 q = subtractPoints(c, b),
78213                 scale, dotp;
78214
78215             scale = 2 * Math.min(geoEuclideanDistance(p, [0, 0]), geoEuclideanDistance(q, [0, 0]));
78216             p = normalizePoint(p, 1.0);
78217             q = normalizePoint(q, 1.0);
78218
78219             dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
78220
78221             // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
78222             if (array.length > 3) {
78223                 if (dotp < -0.707106781186547) {
78224                     dotp += 1.0;
78225                 }
78226             } else if (dotp && Math.abs(dotp) < corner.dotp) {
78227                 corner.i = i;
78228                 corner.dotp = Math.abs(dotp);
78229             }
78230
78231             return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
78232         }
78233     };
78234
78235
78236     function squareness(points) {
78237         return points.reduce(function(sum, val, i, array) {
78238             var dotp = normalizedDotProduct(i, array);
78239
78240             dotp = filterDotProduct(dotp);
78241             return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
78242         }, 0);
78243     }
78244
78245
78246     function normalizedDotProduct(i, points) {
78247         var a = points[(i - 1 + points.length) % points.length],
78248             b = points[i],
78249             c = points[(i + 1) % points.length],
78250             p = subtractPoints(a, b),
78251             q = subtractPoints(c, b);
78252
78253         p = normalizePoint(p, 1.0);
78254         q = normalizePoint(q, 1.0);
78255
78256         return p[0] * q[0] + p[1] * q[1];
78257     }
78258
78259
78260     function subtractPoints(a, b) {
78261         return [a[0] - b[0], a[1] - b[1]];
78262     }
78263
78264
78265     function addPoints(a, b) {
78266         return [a[0] + b[0], a[1] + b[1]];
78267     }
78268
78269
78270     function normalizePoint(point, scale) {
78271         var vector = [0, 0];
78272         var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
78273         if (length !== 0) {
78274             vector[0] = point[0] / length;
78275             vector[1] = point[1] / length;
78276         }
78277
78278         vector[0] *= scale;
78279         vector[1] *= scale;
78280
78281         return vector;
78282     }
78283
78284
78285     function filterDotProduct(dotp) {
78286         if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
78287             return dotp;
78288         }
78289
78290         return 0;
78291     }
78292
78293
78294     action.disabled = function(graph) {
78295         var way = graph.entity(wayId),
78296             nodes = graph.childNodes(way),
78297             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); });
78298
78299         if (squareness(points)) {
78300             return false;
78301         }
78302
78303         return 'not_squarish';
78304     };
78305
78306
78307     action.transitionable = true;
78308
78309
78310     return action;
78311 }
78312
78313 // Split a way at the given node.
78314 //
78315 // Optionally, split only the given ways, if multiple ways share
78316 // the given node.
78317 //
78318 // This is the inverse of `iD.actionJoin`.
78319 //
78320 // For testing convenience, accepts an ID to assign to the new way.
78321 // Normally, this will be undefined and the way will automatically
78322 // be assigned a new ID.
78323 //
78324 // Reference:
78325 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
78326 //
78327 function actionSplit(nodeId, newWayIds) {
78328     var wayIds;
78329
78330     // if the way is closed, we need to search for a partner node
78331     // to split the way at.
78332     //
78333     // The following looks for a node that is both far away from
78334     // the initial node in terms of way segment length and nearby
78335     // in terms of beeline-distance. This assures that areas get
78336     // split on the most "natural" points (independent of the number
78337     // of nodes).
78338     // For example: bone-shaped areas get split across their waist
78339     // line, circles across the diameter.
78340     function splitArea(nodes, idxA, graph) {
78341         var lengths = new Array(nodes.length),
78342             length,
78343             i,
78344             best = 0,
78345             idxB;
78346
78347         function wrap(index) {
78348             return utilWrap(index, nodes.length);
78349         }
78350
78351         function dist(nA, nB) {
78352             return geoSphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
78353         }
78354
78355         // calculate lengths
78356         length = 0;
78357         for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
78358             length += dist(nodes[i], nodes[wrap(i-1)]);
78359             lengths[i] = length;
78360         }
78361
78362         length = 0;
78363         for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
78364             length += dist(nodes[i], nodes[wrap(i+1)]);
78365             if (length < lengths[i])
78366                 lengths[i] = length;
78367         }
78368
78369         // determine best opposite node to split
78370         for (i = 0; i < nodes.length; i++) {
78371             var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
78372             if (cost > best) {
78373                 idxB = i;
78374                 best = cost;
78375             }
78376         }
78377
78378         return idxB;
78379     }
78380
78381
78382     function split(graph, wayA, newWayId) {
78383         var wayB = osmWay({id: newWayId, tags: wayA.tags}),
78384             nodesA,
78385             nodesB,
78386             isArea = wayA.isArea(),
78387             isOuter = osmIsSimpleMultipolygonOuterMember(wayA, graph);
78388
78389         if (wayA.isClosed()) {
78390             var nodes = wayA.nodes.slice(0, -1),
78391                 idxA = lodash.indexOf(nodes, nodeId),
78392                 idxB = splitArea(nodes, idxA, graph);
78393
78394             if (idxB < idxA) {
78395                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
78396                 nodesB = nodes.slice(idxB, idxA + 1);
78397             } else {
78398                 nodesA = nodes.slice(idxA, idxB + 1);
78399                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
78400             }
78401         } else {
78402             var idx = lodash.indexOf(wayA.nodes, nodeId, 1);
78403             nodesA = wayA.nodes.slice(0, idx + 1);
78404             nodesB = wayA.nodes.slice(idx);
78405         }
78406
78407         wayA = wayA.update({nodes: nodesA});
78408         wayB = wayB.update({nodes: nodesB});
78409
78410         graph = graph.replace(wayA);
78411         graph = graph.replace(wayB);
78412
78413         graph.parentRelations(wayA).forEach(function(relation) {
78414             if (relation.isRestriction()) {
78415                 var via = relation.memberByRole('via');
78416                 if (via && wayB.contains(via.id)) {
78417                     relation = relation.replaceMember(wayA, wayB);
78418                     graph = graph.replace(relation);
78419                 }
78420             } else {
78421                 if (relation === isOuter) {
78422                     graph = graph.replace(relation.mergeTags(wayA.tags));
78423                     graph = graph.replace(wayA.update({tags: {}}));
78424                     graph = graph.replace(wayB.update({tags: {}}));
78425                 }
78426
78427                 var member = {
78428                     id: wayB.id,
78429                     type: 'way',
78430                     role: relation.memberById(wayA.id).role
78431                 };
78432
78433                 graph = actionAddMember(relation.id, member)(graph);
78434             }
78435         });
78436
78437         if (!isOuter && isArea) {
78438             var multipolygon = osmRelation({
78439                 tags: lodash.extend({}, wayA.tags, {type: 'multipolygon'}),
78440                 members: [
78441                     {id: wayA.id, role: 'outer', type: 'way'},
78442                     {id: wayB.id, role: 'outer', type: 'way'}
78443                 ]});
78444
78445             graph = graph.replace(multipolygon);
78446             graph = graph.replace(wayA.update({tags: {}}));
78447             graph = graph.replace(wayB.update({tags: {}}));
78448         }
78449
78450         return graph;
78451     }
78452
78453
78454     var action = function(graph) {
78455         var candidates = action.ways(graph);
78456         for (var i = 0; i < candidates.length; i++) {
78457             graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
78458         }
78459         return graph;
78460     };
78461
78462
78463     action.ways = function(graph) {
78464         var node = graph.entity(nodeId),
78465             parents = graph.parentWays(node),
78466             hasLines = lodash.some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
78467
78468         return parents.filter(function(parent) {
78469             if (wayIds && wayIds.indexOf(parent.id) === -1)
78470                 return false;
78471
78472             if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
78473                 return false;
78474
78475             if (parent.isClosed()) {
78476                 return true;
78477             }
78478
78479             for (var i = 1; i < parent.nodes.length - 1; i++) {
78480                 if (parent.nodes[i] === nodeId) {
78481                     return true;
78482                 }
78483             }
78484
78485             return false;
78486         });
78487     };
78488
78489
78490     action.disabled = function(graph) {
78491         var candidates = action.ways(graph);
78492         if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
78493             return 'not_eligible';
78494     };
78495
78496
78497     action.limitWays = function(_) {
78498         if (!arguments.length) return wayIds;
78499         wayIds = _;
78500         return action;
78501     };
78502
78503
78504     return action;
78505 }
78506
78507 // Create a restriction relation for `turn`, which must have the following structure:
78508 //
78509 //     {
78510 //         from: { node: <node ID>, way: <way ID> },
78511 //         via:  { node: <node ID> },
78512 //         to:   { node: <node ID>, way: <way ID> },
78513 //         restriction: <'no_right_turn', 'no_left_turn', etc.>
78514 //     }
78515 //
78516 // This specifies a restriction of type `restriction` when traveling from
78517 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
78518 // (The action does not check that these entities form a valid intersection.)
78519 //
78520 // If `restriction` is not provided, it is automatically determined by
78521 // osmInferRestriction.
78522 //
78523 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
78524 // and `to.node` are used to determine which portion of the split ways become
78525 // members of the restriction.
78526 //
78527 // For testing convenience, accepts an ID to assign to the new relation.
78528 // Normally, this will be undefined and the relation will automatically
78529 // be assigned a new ID.
78530 //
78531 function actionRestrictTurn(turn, projection, restrictionId) {
78532
78533     return function(graph) {
78534         var from = graph.entity(turn.from.way),
78535             via  = graph.entity(turn.via.node),
78536             to   = graph.entity(turn.to.way);
78537
78538         function isClosingNode(way, nodeId) {
78539             return nodeId === way.first() && nodeId === way.last();
78540         }
78541
78542         function split(toOrFrom) {
78543             var newID = toOrFrom.newID || osmWay().id;
78544             graph = actionSplit(via.id, [newID])
78545                 .limitWays([toOrFrom.way])(graph);
78546
78547             var a = graph.entity(newID),
78548                 b = graph.entity(toOrFrom.way);
78549
78550             if (a.nodes.indexOf(toOrFrom.node) !== -1) {
78551                 return [a, b];
78552             } else {
78553                 return [b, a];
78554             }
78555         }
78556
78557         if (!from.affix(via.id) || isClosingNode(from, via.id)) {
78558             if (turn.from.node === turn.to.node) {
78559                 // U-turn
78560                 from = to = split(turn.from)[0];
78561             } else if (turn.from.way === turn.to.way) {
78562                 // Straight-on or circular
78563                 var s = split(turn.from);
78564                 from = s[0];
78565                 to   = s[1];
78566             } else {
78567                 // Other
78568                 from = split(turn.from)[0];
78569             }
78570         }
78571
78572         if (!to.affix(via.id) || isClosingNode(to, via.id)) {
78573             to = split(turn.to)[0];
78574         }
78575
78576         return graph.replace(osmRelation({
78577             id: restrictionId,
78578             tags: {
78579                 type: 'restriction',
78580                 restriction: turn.restriction ||
78581                     osmInferRestriction(
78582                         graph,
78583                         turn.from,
78584                         turn.via,
78585                         turn.to,
78586                         projection)
78587             },
78588             members: [
78589                 {id: from.id, type: 'way',  role: 'from'},
78590                 {id: via.id,  type: 'node', role: 'via'},
78591                 {id: to.id,   type: 'way',  role: 'to'}
78592             ]
78593         }));
78594     };
78595 }
78596
78597 function actionRevert(id) {
78598     var action = function(graph) {
78599         var entity = graph.hasEntity(id),
78600             base = graph.base().entities[id];
78601
78602         if (entity && !base) {    // entity will be removed..
78603             if (entity.type === 'node') {
78604                 graph.parentWays(entity)
78605                     .forEach(function(parent) {
78606                         parent = parent.removeNode(id);
78607                         graph = graph.replace(parent);
78608
78609                         if (parent.isDegenerate()) {
78610                             graph = actionDeleteWay(parent.id)(graph);
78611                         }
78612                     });
78613             }
78614
78615             graph.parentRelations(entity)
78616                 .forEach(function(parent) {
78617                     parent = parent.removeMembersWithID(id);
78618                     graph = graph.replace(parent);
78619
78620                     if (parent.isDegenerate()) {
78621                         graph = actionDeleteRelation(parent.id)(graph);
78622                     }
78623                 });
78624         }
78625
78626         return graph.revert(id);
78627     };
78628
78629     return action;
78630 }
78631
78632 function actionRotate(rotateIds, pivot, angle, projection) {
78633
78634     var action = function(graph) {
78635         return graph.update(function(graph) {
78636             utilGetAllNodes(rotateIds, graph).forEach(function(node) {
78637                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
78638                 graph = graph.replace(node.move(projection.invert(point)));
78639             });
78640         });
78641     };
78642
78643     return action;
78644 }
78645
78646 /*
78647  * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
78648  */
78649 function actionStraighten(wayId, projection) {
78650
78651     function positionAlongWay(n, s, e) {
78652         return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1])) /
78653                 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
78654     }
78655
78656
78657     var action = function(graph, t) {
78658         if (t === null || !isFinite(t)) t = 1;
78659         t = Math.min(Math.max(+t, 0), 1);
78660
78661         var way = graph.entity(wayId),
78662             nodes = graph.childNodes(way),
78663             points = nodes.map(function(n) { return projection(n.loc); }),
78664             startPoint = points[0],
78665             endPoint = points[points.length-1],
78666             toDelete = [],
78667             i;
78668
78669         for (i = 1; i < points.length-1; i++) {
78670             var node = nodes[i],
78671                 point = points[i];
78672
78673             if (t < 1 || graph.parentWays(node).length > 1 ||
78674                 graph.parentRelations(node).length ||
78675                 node.hasInterestingTags()) {
78676
78677                 var u = positionAlongWay(point, startPoint, endPoint),
78678                     p = [
78679                         startPoint[0] + u * (endPoint[0] - startPoint[0]),
78680                         startPoint[1] + u * (endPoint[1] - startPoint[1])
78681                     ],
78682                     loc2 = projection.invert(p);
78683
78684                 graph = graph.replace(node.move(geoInterp(node.loc, loc2, t)));
78685
78686             } else {
78687                 // safe to delete
78688                 if (toDelete.indexOf(node) === -1) {
78689                     toDelete.push(node);
78690                 }
78691             }
78692         }
78693
78694         for (i = 0; i < toDelete.length; i++) {
78695             graph = actionDeleteNode(toDelete[i].id)(graph);
78696         }
78697
78698         return graph;
78699     };
78700
78701
78702     action.disabled = function(graph) {
78703         // check way isn't too bendy
78704         var way = graph.entity(wayId),
78705             nodes = graph.childNodes(way),
78706             points = nodes.map(function(n) { return projection(n.loc); }),
78707             startPoint = points[0],
78708             endPoint = points[points.length-1],
78709             threshold = 0.2 * geoEuclideanDistance(startPoint, endPoint),
78710             i;
78711
78712         if (threshold === 0) {
78713             return 'too_bendy';
78714         }
78715
78716         for (i = 1; i < points.length-1; i++) {
78717             var point = points[i],
78718                 u = positionAlongWay(point, startPoint, endPoint),
78719                 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
78720                 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
78721                 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
78722
78723             // to bendy if point is off by 20% of total start/end distance in projected space
78724             if (isNaN(dist) || dist > threshold) {
78725                 return 'too_bendy';
78726             }
78727         }
78728     };
78729
78730
78731     action.transitionable = true;
78732
78733
78734     return action;
78735 }
78736
78737 // Remove the effects of `turn.restriction` on `turn`, which must have the
78738 // following structure:
78739 //
78740 //     {
78741 //         from: { node: <node ID>, way: <way ID> },
78742 //         via:  { node: <node ID> },
78743 //         to:   { node: <node ID>, way: <way ID> },
78744 //         restriction: <relation ID>
78745 //     }
78746 //
78747 // In the simple case, `restriction` is a reference to a `no_*` restriction
78748 // on the turn itself. In this case, it is simply deleted.
78749 //
78750 // The more complex case is where `restriction` references an `only_*`
78751 // restriction on a different turn in the same intersection. In that case,
78752 // that restriction is also deleted, but at the same time restrictions on
78753 // the turns other than the first two are created.
78754 //
78755 function actionUnrestrictTurn(turn) {
78756     return function(graph) {
78757         return actionDeleteRelation(turn.restriction)(graph);
78758     };
78759 }
78760
78761 /* Reflect the given area around its axis of symmetry */
78762 function actionReflect(reflectIds, projection$$1) {
78763     var useLongAxis = true;
78764
78765
78766     // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
78767     // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
78768     function getSmallestSurroundingRectangle(graph, nodes) {
78769         var points = nodes.map(function(n) { return projection$$1(n.loc); }),
78770             hull = d3polygonHull(points),
78771             centroid = d3polygonCentroid(hull),
78772             minArea = Infinity,
78773             ssrExtent = [],
78774             ssrAngle = 0,
78775             c1 = hull[0];
78776
78777         for (var i = 0; i < hull.length - 1; i++) {
78778             var c2 = hull[i + 1],
78779                 angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]),
78780                 poly = geoRotate(hull, -angle, centroid),
78781                 extent$$1 = poly.reduce(function(extent$$1, point) {
78782                         return extent$$1.extend(geoExtent$$1(point));
78783                     }, geoExtent$$1()),
78784                 area$$1 = extent$$1.area();
78785
78786             if (area$$1 < minArea) {
78787                 minArea = area$$1;
78788                 ssrExtent = extent$$1;
78789                 ssrAngle = angle;
78790             }
78791             c1 = c2;
78792         }
78793
78794         return {
78795             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
78796             angle: ssrAngle
78797         };
78798     }
78799
78800
78801     var action = function(graph, t) {
78802         if (t === null || !isFinite(t)) t = 1;
78803         t = Math.min(Math.max(+t, 0), 1);
78804
78805         var nodes = utilGetAllNodes(reflectIds, graph),
78806             ssr = getSmallestSurroundingRectangle(graph, nodes);
78807
78808         // Choose line pq = axis of symmetry.
78809         // The shape's surrounding rectangle has 2 axes of symmetry.
78810         // Reflect across the longer axis by default.
78811         var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2 ],
78812             q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2 ],
78813             p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2 ],
78814             q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2 ],
78815             p, q;
78816
78817         var isLong = (geoEuclideanDistance(p1, q1) > geoEuclideanDistance(p2, q2));
78818         if ((useLongAxis && isLong) || (!useLongAxis && !isLong)) {
78819             p = p1;
78820             q = q1;
78821         } else {
78822             p = p2;
78823             q = q2;
78824         }
78825
78826         // reflect c across pq
78827         // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
78828         var dx = q[0] - p[0];
78829         var dy = q[1] - p[1];
78830         var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
78831         var b = 2 * dx * dy / (dx * dx + dy * dy);
78832         for (var i = 0; i < nodes.length; i++) {
78833             var node = nodes[i];
78834             var c = projection$$1(node.loc);
78835             var c2 = [
78836                 a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0],
78837                 b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]
78838             ];
78839             var loc2 = projection$$1.invert(c2);
78840             node = node.move(geoInterp(node.loc, loc2, t));
78841             graph = graph.replace(node);
78842         }
78843
78844         return graph;
78845     };
78846
78847
78848     action.useLongAxis = function(_) {
78849         if (!arguments.length) return useLongAxis;
78850         useLongAxis = _;
78851         return action;
78852     };
78853
78854
78855     action.transitionable = true;
78856
78857
78858     return action;
78859 }
78860
78861
78862
78863 var index$17 = Object.freeze({
78864         d3combobox: d3combobox,
78865         d3geoTile: d3geoTile,
78866         d3keybinding: d3keybinding
78867 });
78868
78869 /* export some legacy symbols: */
78870 var Connection = services.osm;
78871 var debug = false;
78872
78873
78874
78875
78876 var iD = Object.freeze({
78877         Connection: Connection,
78878         debug: debug,
78879         d3: index$2,
78880         _: lodash$1,
78881         lib: index$17,
78882         Context: coreContext,
78883         setAreaKeys: setAreaKeys,
78884         Difference: coreDifference,
78885         Graph: coreGraph$$1,
78886         History: coreHistory,
78887         Tree: coreTree,
78888         Entity: osmEntity$$1,
78889         Node: osmNode,
78890         Relation: osmRelation,
78891         Way: osmWay,
78892         BackgroundSource: rendererBackgroundSource,
78893         Background: rendererBackground,
78894         Features: rendererFeatures,
78895         Map: rendererMap,
78896         TileLayer: rendererTileLayer,
78897         Detect: utilDetect,
78898         actionAddEntity: actionAddEntity,
78899         actionAddMember: actionAddMember,
78900         actionAddMidpoint: actionAddMidpoint,
78901         actionAddVertex: actionAddVertex,
78902         actionChangeMember: actionChangeMember,
78903         actionChangePreset: actionChangePreset,
78904         actionChangeTags: actionChangeTags,
78905         actionCircularize: actionCircularize,
78906         actionConnect: actionConnect,
78907         actionCopyEntities: actionCopyEntities,
78908         actionDeleteMember: actionDeleteMember,
78909         actionDeleteMultiple: actionDeleteMultiple,
78910         actionDeleteNode: actionDeleteNode,
78911         actionDeleteRelation: actionDeleteRelation,
78912         actionDeleteWay: actionDeleteWay,
78913         actionDeprecateTags: actionDeprecateTags,
78914         actionDiscardTags: actionDiscardTags,
78915         actionDisconnect: actionDisconnect,
78916         actionJoin: actionJoin,
78917         actionMerge: actionMerge,
78918         actionMergePolygon: actionMergePolygon,
78919         actionMergeRemoteChanges: actionMergeRemoteChanges,
78920         actionMove: actionMove,
78921         actionMoveNode: actionMoveNode,
78922         actionNoop: actionNoop,
78923         actionOrthogonalize: actionOrthogonalize,
78924         actionRestrictTurn: actionRestrictTurn,
78925         actionReverse: actionReverse,
78926         actionRevert: actionRevert,
78927         actionRotate: actionRotate,
78928         actionSplit: actionSplit,
78929         actionStraighten: actionStraighten,
78930         actionUnrestrictTurn: actionUnrestrictTurn,
78931         actionReflect: actionReflect,
78932         behaviorAddWay: behaviorAddWay,
78933         behaviorBreathe: behaviorBreathe,
78934         behaviorCopy: behaviorCopy,
78935         behaviorDrag: behaviorDrag,
78936         behaviorDrawWay: behaviorDrawWay,
78937         behaviorDraw: behaviorDraw,
78938         behaviorEdit: behaviorEdit,
78939         behaviorHash: behaviorHash,
78940         behaviorHover: behaviorHover,
78941         behaviorLasso: behaviorLasso,
78942         behaviorOperation: behaviorOperation,
78943         behaviorPaste: behaviorPaste,
78944         behaviorSelect: behaviorSelect,
78945         behaviorTail: behaviorTail,
78946         coreContext: coreContext,
78947         coreDifference: coreDifference,
78948         coreGraph: coreGraph$$1,
78949         coreHistory: coreHistory,
78950         coreTree: coreTree,
78951         dataFeatureIcons: dataFeatureIcons,
78952         data: data,
78953         dataWikipedia: dataWikipedia,
78954         dataSuggestions: dataSuggestions,
78955         dataAddressFormats: dataAddressFormats,
78956         dataDeprecated: dataDeprecated,
78957         dataDiscarded: dataDiscarded,
78958         dataLocales: dataLocales,
78959         dataPhoneFormats: dataPhoneFormats,
78960         dataShortcuts: dataShortcuts,
78961         dataImperial: dataImperial,
78962         dataDriveLeft: dataDriveLeft,
78963         dataEn: en,
78964         geoAngle: geoAngle,
78965         geoChooseEdge: geoChooseEdge,
78966         geoCross: geoCross,
78967         geoEdgeEqual: geoEdgeEqual,
78968         geoEuclideanDistance: geoEuclideanDistance,
78969         geoExtent: geoExtent$$1,
78970         geoInterp: geoInterp,
78971         geoRawMercator: geoRawMercator,
78972         geoRoundCoords: geoRoundCoords,
78973         geoRotate: geoRotate,
78974         geoLatToMeters: geoLatToMeters,
78975         geoLineIntersection: geoLineIntersection,
78976         geoLonToMeters: geoLonToMeters,
78977         geoMetersToLat: geoMetersToLat,
78978         geoMetersToLon: geoMetersToLon,
78979         geoMetersToOffset: geoMetersToOffset,
78980         geoOffsetToMeters: geoOffsetToMeters,
78981         geoPathIntersections: geoPathIntersections,
78982         geoPathLength: geoPathLength,
78983         geoPointInPolygon: geoPointInPolygon,
78984         geoPolygonContainsPolygon: geoPolygonContainsPolygon,
78985         geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
78986         geoSphericalDistance: geoSphericalDistance,
78987         modeAddArea: modeAddArea$$1,
78988         modeAddLine: modeAddLine$$1,
78989         modeAddPoint: modeAddPoint$$1,
78990         modeBrowse: modeBrowse,
78991         modeDragNode: modeDragNode$$1,
78992         modeDrawArea: modeDrawArea,
78993         modeDrawLine: modeDrawLine,
78994         modeMove: modeMove$$1,
78995         modeRotate: modeRotate$$1,
78996         modeSave: modeSave$$1,
78997         modeSelect: modeSelect,
78998         operationCircularize: operationCircularize,
78999         operationContinue: operationContinue,
79000         operationDelete: operationDelete,
79001         operationDisconnect: operationDisconnect,
79002         operationMerge: operationMerge,
79003         operationMove: operationMove,
79004         operationOrthogonalize: operationOrthogonalize,
79005         operationReflectShort: operationReflectShort,
79006         operationReflectLong: operationReflectLong,
79007         operationReverse: operationReverse,
79008         operationRotate: operationRotate,
79009         operationSplit: operationSplit,
79010         operationStraighten: operationStraighten,
79011         osmChangeset: osmChangeset,
79012         osmEntity: osmEntity$$1,
79013         osmNode: osmNode,
79014         osmRelation: osmRelation,
79015         osmWay: osmWay,
79016         osmIntersection: osmIntersection,
79017         osmTurn: osmTurn,
79018         osmInferRestriction: osmInferRestriction,
79019         osmLanes: osmLanes,
79020         osmIsSimpleMultipolygonOuterMember: osmIsSimpleMultipolygonOuterMember,
79021         osmSimpleMultipolygonOuterMember: osmSimpleMultipolygonOuterMember,
79022         osmJoinWays: osmJoinWays,
79023         osmOneWayTags: osmOneWayTags,
79024         osmPavedTags: osmPavedTags,
79025         osmIsInterestingTag: osmIsInterestingTag,
79026         presetCategory: presetCategory,
79027         presetCollection: presetCollection,
79028         presetField: presetField,
79029         presetPreset: presetPreset,
79030         presetIndex: presetIndex,
79031         rendererBackgroundSource: rendererBackgroundSource,
79032         rendererBackground: rendererBackground,
79033         rendererFeatures: rendererFeatures,
79034         rendererMap: rendererMap,
79035         rendererTileLayer: rendererTileLayer,
79036         services: services,
79037         svgAreas: svgAreas$$1,
79038         svgDebug: svgDebug,
79039         svgDefs: svgDefs,
79040         svgGpx: svgGpx,
79041         svgIcon: svgIcon,
79042         svgLabels: svgLabels,
79043         svgLayers: svgLayers,
79044         svgLines: svgLines$$1,
79045         svgMapillaryImages: svgMapillaryImages,
79046         svgMapillarySigns: svgMapillarySigns,
79047         svgMidpoints: svgMidpoints$$1,
79048         svgOneWaySegments: svgOneWaySegments,
79049         svgOsm: svgOsm,
79050         svgPath: svgPath,
79051         svgPointTransform: svgPointTransform,
79052         svgPoints: svgPoints$$1,
79053         svgRelationMemberTags: svgRelationMemberTags,
79054         svgTagClasses: svgTagClasses,
79055         svgTurns: svgTurns,
79056         svgVertices: svgVertices$$1,
79057         uiFields: uiFields,
79058         uiFieldDefaultCheck: uiFieldCheck,
79059         uiFieldOnewayCheck: uiFieldCheck,
79060         uiFieldCheck: uiFieldCheck,
79061         uiFieldMultiCombo: uiFieldCombo,
79062         uiFieldNetworkCombo: uiFieldCombo,
79063         uiFieldSemiCombo: uiFieldCombo,
79064         uiFieldTypeCombo: uiFieldCombo,
79065         uiFieldCombo: uiFieldCombo,
79066         uiFieldUrl: uiFieldText,
79067         uiFieldNumber: uiFieldText,
79068         uiFieldTel: uiFieldText,
79069         uiFieldEmail: uiFieldText,
79070         uiFieldText: uiFieldText,
79071         uiFieldAccess: uiFieldAccess,
79072         uiFieldAddress: uiFieldAddress,
79073         uiFieldCycleway: uiFieldCycleway,
79074         uiFieldLanes: uiFieldLanes,
79075         uiFieldLocalized: uiFieldLocalized,
79076         uiFieldMaxspeed: uiFieldMaxspeed,
79077         uiFieldStructureRadio: uiFieldRadio,
79078         uiFieldRadio: uiFieldRadio,
79079         uiFieldRestrictions: uiFieldRestrictions,
79080         uiFieldTextarea: uiFieldTextarea,
79081         uiFieldWikipedia: uiFieldWikipedia,
79082         uiIntro: uiIntro,
79083         uiInfoPanels: uiInfoPanels,
79084         uiPanelBackground: uiPanelBackground,
79085         uiPanelHistory: uiPanelHistory,
79086         uiPanelLocation: uiPanelLocation,
79087         uiPanelMeasurement: uiPanelMeasurement,
79088         uiInit: uiInit,
79089         uiAccount: uiAccount,
79090         uiAttribution: uiAttribution,
79091         uiBackground: uiBackground,
79092         uiCmd: uiCmd,
79093         uiCommit: uiCommit,
79094         uiConfirm: uiConfirm,
79095         uiConflicts: uiConflicts,
79096         uiContributors: uiContributors,
79097         uiCurtain: uiCurtain,
79098         uiDisclosure: uiDisclosure,
79099         uiEditMenu: uiEditMenu,
79100         uiEntityEditor: uiEntityEditor,
79101         uiFeatureInfo: uiFeatureInfo,
79102         uiFeatureList: uiFeatureList,
79103         uiFlash: uiFlash,
79104         uiFullScreen: uiFullScreen,
79105         uiGeolocate: uiGeolocate,
79106         uiHelp: uiHelp,
79107         uiInfo: uiInfo,
79108         uiInspector: uiInspector,
79109         uiLasso: uiLasso,
79110         uiLoading: uiLoading,
79111         uiMapData: uiMapData,
79112         uiMapInMap: uiMapInMap,
79113         uiModal: uiModal,
79114         uiModes: uiModes,
79115         uiNotice: uiNotice,
79116         uiPreset: uiPreset,
79117         uiPresetIcon: uiPresetIcon,
79118         uiPresetList: uiPresetList,
79119         uiRadialMenu: uiRadialMenu,
79120         uiRawMemberEditor: uiRawMemberEditor,
79121         uiRawMembershipEditor: uiRawMembershipEditor,
79122         uiRawTagEditor: uiRawTagEditor,
79123         uiRestore: uiRestore,
79124         uiSave: uiSave,
79125         uiScale: uiScale,
79126         uiSelectionList: uiSelectionList,
79127         uiSidebar: uiSidebar,
79128         uiSourceSwitch: uiSourceSwitch,
79129         uiSpinner: uiSpinner,
79130         uiSplash: uiSplash,
79131         uiStatus: uiStatus,
79132         uiSuccess: uiSuccess,
79133         uiTagReference: uiTagReference,
79134         uiToggle: uiToggle,
79135         uiTooltipHtml: uiTooltipHtml,
79136         uiUndoRedo: uiUndoRedo,
79137         uiVersion: uiVersion,
79138         uiViewOnOSM: uiViewOnOSM,
79139         uiZoom: uiZoom,
79140         utilAsyncMap: utilAsyncMap,
79141         utilDisplayName: utilDisplayName,
79142         utilDisplayNameForPath: utilDisplayNameForPath,
79143         utilDisplayType: utilDisplayType,
79144         utilEditDistance: utilEditDistance,
79145         utilEntitySelector: utilEntitySelector,
79146         utilEntityOrMemberSelector: utilEntityOrMemberSelector,
79147         utilFastMouse: utilFastMouse,
79148         utilFunctor: utilFunctor,
79149         utilGetAllNodes: utilGetAllNodes,
79150         utilGetPrototypeOf: utilGetPrototypeOf,
79151         utilGetSetValue: utilGetSetValue,
79152         utilNoAuto: utilNoAuto,
79153         utilPrefixCSSProperty: utilPrefixCSSProperty,
79154         utilPrefixDOMProperty: utilPrefixDOMProperty,
79155         utilQsString: utilQsString,
79156         utilRebind: utilRebind,
79157         utilSetTransform: utilSetTransform,
79158         utilSessionMutex: utilSessionMutex,
79159         utilStringQs: utilStringQs,
79160         utilSuggestNames: utilSuggestNames,
79161         utilTagText: utilTagText,
79162         utilTriggerEvent: utilTriggerEvent,
79163         utilWrap: utilWrap,
79164         d3combobox: d3combobox,
79165         d3geoTile: d3geoTile,
79166         d3keybinding: d3keybinding,
79167         validationDeprecatedTag: validationDeprecatedTag,
79168         validationDisconnectedHighway: validationDisconnectedHighway,
79169         validationManyDeletions: validationManyDeletions,
79170         validationMissingTag: validationMissingTag,
79171         validationOldMultipolygon: validationOldMultipolygon,
79172         validationTagSuggestsArea: validationTagSuggestsArea
79173 });
79174
79175 window.iD = iD;
79176
79177 }());
79178 //# sourceMappingURL=iD.js.map